PHP の拡張機能の作成は特に面倒というわけではありませんが、SWIG を利用すると、そうした作業が非常に単純になります。その大きな理由は、PHP のコードと C や C++ のコードとを混在させる上で必要な作業を SWIG が自動的に行ってくれるためです。関数の記述 (その関数の名前と正式な引数) を指定すると、SWIG は PHP と下位レベルのコードを接続するラッパーを生成してくれます。
SWIG には、いくつかの前提条件があります。最新バージョンの SWIG には PHP V5 が必要です。また、GCC (GNU Compiler Collection) などの C/C++ コンパイラー、そして PHP MDK (Module Development Kit) のコピーも必要です。具体的には、PHP のインストールに関連付けられたヘッダー・ファイルが必要です。Ubuntu Linux® を使用する場合、または Debian のバリエーションを使用する場合で、パッケージ・リポジトリーから PHP V5 をインストールした場合には、通常は APT (Advanced Packaging Tool) を使って MDK を追加します。例えば Ubuntu のカーネル 9.10 の場合には、apt-get install sudo apt-get install --install-recommends --yes php5-dev と入力します。
2009年が終わる時点での SWIG の最新リリースは V1.3.40 です (「参考文献」を参照)。SWIG を利用するには tarball (gzip で圧縮された TAR ファイル) をダウンロードして解凍し、ご使用のシステムに合わせてコードを構成し、その構成したソフトウェアをビルドしてインストールします。(すべての構成オプションを表示するためには、./configure --help を実行します。) リスト 1 は、SWIG のダウンロード、解凍、インストールのためのコマンドを示しています。
リスト 1. SWIG のダウンロード、解凍、インストールのためのコマンド
$ wget http://prdownloads.sourceforge.net/swig/swig-1.3.40.tar.gz $ tar xzf swig-1.3.40.tar.gz $ cd swig-1.3.40 $ ./configure $ make $ sudo make install $ which swig /usr/local/bin/swig |
では、Linux の mcrypt ライブラリーを使ってメッセージの暗号化と暗号化解除を行う拡張機能を作成しましょう。PHP が提供している mcrypt ライブラリーは、Linux の mcrypt ライブラリーの C によるエントリー・ポイントに対する非常に薄いレイヤーにすぎません。ここでは、それよりもはるかに簡潔な 2 つのメソッドとして、文字列を暗号化するためのメソッドと、文字列の暗号化を解除するためのメソッドを作成しましょう。
Ubuntu や Ubuntu と類似のシステムでは、該当する mcrypt ライブラリーとヘッダー・ファイルを APT によってインストールすることができます ($ sudo apt-get install libmcrypt-dev libmcrypt4 mcrypt libmhash2)。
ソースからビルドしたい場合や、ディストリビューションに mcrypt が含まれていない場合には、mcrypt のホームページからソース・コードをダウンロードすることができます (「参考文献」を参照)。mcrypt ユーティリティーは crypt を置き換えるものですが、libmhash にも依存しており、mcrypt をコンパイルする前に libmhash をビルドする必要があります。リスト 2 は libmhash をビルドするためのコードを示しています。
リスト 2.
libmhash をビルドする$ # libmhash $ wget http://sourceforge.net/projects/mhash/files/mhash/0.9.9.9/\ mhash-0.9.9.9.tar.bz2/download $ tar xfj mhash-0.9.9.9.tar.bz2 $ cd mhash-0.9.9.9 $ ./configure $ make $ sudo make install # libmcrypt $ wget ftp://mcrypt.hellug.gr/pub/crypto/mcrypt/libmcrypt/\ libmcrypt-2.5.7.tar.gz $ tar xfz libmcrypt-2.5.7.tar.gz $ cd libmcrypt-2.5.7 $ ./configure $ make $ sudo make install $ # mcrypt $ wget wget http://sourceforge.net/projects/mcrypt/files/MCrypt/2.6.8/\ mcrypt-2.6.8.tar.gz/download $ tar xfz mcrypt-2.6.8.tar.gz $ cd mcrypt-2.6.8 $ ./configure $ make $ sudo make install |
次に、この拡張機能のための C コードを作成します。このコードの中で興味深い関数は、リスト 3 の最後にある encode() と decode() です。どちらの関数も 2 つの正式な引数 (文字列とカウント値) を取って文字列を返します。encode() は平文の文字列を暗号化し、エンコードされた文字列を返します。decode() はエンコードされた文字列の暗号化を解除し、平文の文字列を返します。文字列の長さは任意です。
このコードは DES-ECB (Data Encryption Standard-Electronic Codebook) アルゴリズムを使用しています。秘密鍵は 8 文字の任意の文字列ですが、ここでは説明用に 12345678 としてあります。暗号化されたメッセージを他の相手と交換する場合には、その相手の鍵を入手するか、あるいは新しい鍵を生成してその鍵を相手と共有します。暗号化アルゴリズムはアーキテクチャーや言語に依存しませんが、送信側と受信側の両方が秘密鍵を知っている必要があります。
リスト 3. PHP 拡張機能のための C コード
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mcrypt.h>
char *encode( char *string, int length );
char *decode( char *string, int length );
MCRYPT start() {
MCRYPT td = mcrypt_module_open( "des", NULL, "ecb", NULL );
if ( td == MCRYPT_FAILED ) {
return( MCRYPT_FAILED );
}
if ( mcrypt_enc_self_test( td ) != 0 ) {
return( MCRYPT_FAILED );
}
int i;
char *IV;
int iv_size = mcrypt_enc_get_iv_size( td );
if ( iv_size != 0 ) {
IV = calloc( 1, iv_size );
for ( i = 0; i < iv_size; i++ ) {
IV[ i ] = rand();
}
}
int keysize = mcrypt_enc_get_key_size( td );
char *key = calloc( 1, keysize );
memcpy(key, "12345678", keysize);
i = mcrypt_generic_init ( td, key, keysize, IV );
if ( i < 0 ) {
mcrypt_perror( i );
exit(1);
}
return( td );
}
void end( MCRYPT td ) {
mcrypt_generic_deinit( td );
mcrypt_module_close( td );
}
#define B64_DEF_LINE_SIZE 72
#define B64_MIN_LINE_SIZE 4
/*
** encode 3 8-bit binary bytes as 4 '6-bit' characters
*/
void encodeblock( unsigned char in[3], unsigned char out[4], int len ) {
static const char
cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
out[0] = cb64[ in[0] >> 2 ];
out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
out[2] = (unsigned char) (len > 1 ? cb64[
((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
}
char *base64encode( char *input, int size ) {
int i, x, len;
unsigned char in[3], out[4];
char *target = calloc( 1, ( ( size + 2 ) / 3 ) * 4 + 1 );
char *t = target;
for ( x = 0; x < size; ) {
len = 0;
for( i = 0; i < 3; i++ ) {
if ( x < size ) {
len++;
in[i] = input[x++];
}
else {
in[i] = 0;
}
}
if( len ) {
encodeblock( in, out, len );
for( i = 0; i < 4; i++ ) {
*t++ = out[i];
}
}
}
return( target );
}
char *encode( char *string, int length ) {
MCRYPT td = start();
int blocksize = mcrypt_enc_get_block_size( td );
int cryptsize = ( ( length + blocksize - 1 ) / blocksize ) * blocksize;
char *target = calloc( 1, cryptsize );
memcpy( target, string, length );
if ( mcrypt_generic( td, target, cryptsize ) != 0 ) {
fprintf( stderr, "Code failing" );
}
end( td );
char* result = base64encode( target, cryptsize );
free( target );
return result;
}
char *decode( char *string, int length ) {
MCRYPT td = start();
int blocksize = mcrypt_enc_get_block_size( td );
char *block_buffer = calloc( 1, blocksize );
int decryptlength = (length + blocksize - 1) / blocksize * blocksize;
char *target = calloc( 1, decryptlength );
memcpy(target, string, length);
mdecrypt_generic( td, target, decryptlength );
end( td );
free(block_buffer);
return( target );
}
|
リスト 3 のコードをコピーし、secret.c という新しいファイルに貼り付けます。secret.c を用意できたら、次はこのファイルを基にした拡張機能の API を SWIG 独自の構文を使って記述します。
この時点で、secret.c を基に拡張機能を手動で作成することもできますが、SWIG を使用すると、ほんのわずかな擬似コードを作成するだけで、あとの面倒な作業は SWIG がしてくれるのです。リスト 4 は、この新しい拡張機能のための SWIG テンプレートである secret.i を示しています。
リスト 4. secret.i
%module secret
%{
extern char *encode( char *string, int length );
extern char *decode( char *string, int length );
%}
extern char *encode( char *string, int length );
extern char *decode( char *string, int length );
|
SWIG の構文とオプションを完全に説明することは、この記事の目的ではありません。完全なドキュメントはオンラインで閲覧することができます (「参考文献」を参照)。この SWIG ファイルを簡単に説明すると、1 行目はこの拡張機能の名前を宣言しており、それ以外の部分はエントリー・ポイントを宣言しています。それがすべてです。コンパイルには、いくつかのステップが必要です。最初のステップとして、このコードのラッパーを生成します ($ swig -php secret.i)。
すると SWIG は secret.i を secret_wrap.c に変換します。次のいくつかのステップでは、ラッパー・コードと拡張機能、そして mcrypt ライブラリーをビルドしてリンクを実行します。各 C ソース・ファイルをビルドするときには必ず -fpic オプションを使うようにします。-fpic オプションを使うことで、共有ライブラリーに適した、場所に依存しないコードを生成することができます。
$ cc -fpic -c secret.c $ gcc `php-config --includes` -fpic -c secret_wrap.c $ gcc -shared *.o -o secret.so -lmcrypt $ sudo cp secret.so `php-config --extension-dir` |
最初の 2 つのコマンドは C ソースをビルドします。3 番目のコマンドは PHP 拡張機能をビルドします。-lmcrypt オプションは拡張機能の中の呼び出しを mcrypt ライブラリーのエントリー・ポイントによって解決します。4 番目のコマンドは PHP が新しい PHP 拡張機能をロードできるように、新しい PHP 拡張機能を適切なディレクトリーに配置します。
PHP コードを作成する前の最後のステップとして、この拡張機能をロードします。適切な php.ini ファイル (Apache 版またはコマンドライン版の PHP の php.ini ファイル) を開き、extension=secret.so という 1 行を追加します。
どの php.ini ファイルを編集するのかわからない場合には、PHP そのものに対して問い合わせを行います。下記の 3 行のプログラムを作成し、このプログラムをブラウザーまたは対話型のインタープリターを使って実行します。
<?php phpinfo(); ?> |
実行結果のなかで Loaded Configuration File で始まる行を探します。例えば、この記事の作成に使用したテスト・プラットフォームでは、このプログラムを実行することによって Loaded Configuration File => /etc/php5/cli/php.ini という出力が得られました。従って、編集対象のファイルは /etc/php5/cli/php.ini です。
新しい拡張機能が用意できると、PHP を作成することができます。リスト 5 は code.php を示しています。
リスト 5. code.php
<?php
include("secret.php");
$string = "Double secret probation";
$base64encode = secret::encode($string, strlen($string));
$base64decode = base64_decode($base64encode);
$decode = secret::decode( $base64decode, strlen($base64decode));
echo $decode . "\n";
?>
|
1 行目は、この拡張機能をロードしています。4 行目は “Double secret probation” という文字列をエンコードした後、その暗号化された文字列に対して Base64 を使用して、例えば E メールで簡単に送信できる印刷可能な文字列に変換しています。5 行目は Base64 エンコーディングをデコードして元の文字列を生成し、6 行目で秘密のメッセージの暗号化を解除して元のテキストにしています。
このコードを coder.php に保存したとし、また mcrypt ライブラリーをシステムの /usr/local/lib にインストールしたとすると、このサンプル・コードを下記のように PHP の CLI コマンドを使って実行することができます。
$ LD_LIBRARY_PATH=/usr/local/lib php ./code.php Double secret probation |
SWIG は既存のコードを再利用するための優れた手段です。C や C++ のライブラリーを SWIG でラップすることによって、その結果を皆さんの次期 Web アプリケーションやシステム・アプリケーションに統合することができます。さらに良いことに、SWIG を使うと、他のスクリプト言語用のラッパーも、まったく同じ .i ファイルから生成することができます。一度拡張機能を作成すれば、その機能を PHP、Perl、Python、Ruby で共有することができ、また他の開発者とも共有することができます。
学ぶために
- SWIG 拡張機能生成プログラムについて、SWIG のサイトから学んでください。
- SWIG のドキュメントを調べ、また SWIG に関する記事やチュートリアルを調べることで、より容易に SWIG を使えるようになります。このプロジェクトには、いくつかのウィキも用意されています。
- PHP.net は PHP 開発者のための中心的なリソースです。
- 「Recommended PHP reading list」を調べてみてください。
- developerWorks には他にも PHP に関する資料が豊富に用意されています。
- developerWorks を Twitter でフォローしてください。
- IBM developerWorks の PHP project resources を利用して PHP のスキルを磨いてください。
- developerWorks podcasts ではソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。
- PHP でデータベースを使うのであれば、Zend Core for IBM を調べてみてください。Zend Core for IBM は、IBM DB2 V9 をサポートする PHP の開発環境および本番環境として、シームレスでそのまま使用することができ、インストールも容易に行えます。
- My developerWorks コミュニティーは広範な話題を網羅した全般的なコミュニティーとして成功している一例です。
- developerWorks の Technical events and webcasts で最新情報を入手してください。
- IBM オープンソース開発者にとって関心のある、世界中で今後開催される会議や業界展示会、ウェブキャスト、その他のイベントについて調べてみてください。
- developerWorks の Open source ゾーンをご覧ください。オープンソース技術を使った開発や、IBM 製品でオープンソース技術を使用するためのハウ・ツー情報やツール、プロジェクトの更新情報など、豊富な情報が用意されています。また最も人気のあった記事やチュートリアルもご覧ください。
- IBM とオープンソース技術、そして製品機能を調べ、学ぶために、無料の developerWorks On demand demos をご覧ください。
製品や技術を入手するために
- SWIG プロジェクトのサイトから SWIG をダウンロードしてください。
mcryptライブラリーのソース・コードをダウンロードしてください。- 皆さんの次期オープンソース開発プロジェクトを IBM ソフトウェアの試用版を使って革新してください。ダウンロード、あるいは DVD で入手することができます。
- IBM 製品の評価版をダウンロードするか、あるいは IBM SOA Sandbox のオンライン試用版で、DB2®、Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。
議論するために
- developerWorks blogs から developerWorks のコミュニティーに加わってください。
- developerWorks の PHP Forum: Developing PHP applications with IBM Information Management products (DB2, IDS) に加わってください。

Martin Streicher はフリーランスの Ruby on Rails 開発者であり、以前は Linux Magazine の編集責任者でした。彼は Purdue University でコンピューター・サイエンスの修士号を取得しており、1986年以来 UNIX ライクなシステムのプログラミングをしてきました。彼は美術品やおもちゃを収集しています。