ストリームの読み込みとクローズ処理をするための関数の作成
今回は、読み込みのみのために必要な関数はreadとcloseの2つの関数のみです。これ以外にも、以下の関数をストリームを扱う関数として登録できます。
| 命令 | 説明 | 対応するPHPの関数 |
|---|---|---|
| write | ファイルの書き込み処理 | fwrite() |
| read | ファイルの読み込み処理 | fread() |
| close | ファイルを閉じる処理 | fclose() |
| flush | ファイル書込時のflush処理 | fflush() |
| seek | ストリーム内の場所の移動 | fseek() |
| stat | ストリームリソースについての情報の取得 | fstat() |
| cast | 元のリソースを取得 | stream_select() |
| set_option | ストリームのオプション設定 | 対応なし |
では、読み込み処理から実装します。
static size_t php_pzip_ops_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
{
struct php_pzip_stream_data_t *self = (struct php_pzip_stream_data_t *)stream->abstract; // ……(1)
ssize_t n = 0;
if(self->zf){
n = zip_fread(self->zf, buf, count); // ……(2)
if ( n < 0){
return 0;
}
if ( n == 0 || n < (ssize_t)count){ // ……(3)
stream->eof = 1; // ……(4)
}
else{
self->cursor += n; // ……(5)
}
}
return (n < 1 ? 0 : (size_t)n); // ……(6)
}
(1)のようにして、引数のstreamから先ほど作成したストリームの状態を管理している構造体にアクセスができます。次に、(2)のように実際にリソースからデータを読み込む処理を記述します。どの程度のデータを読むかは引数のcountになり、同様に読み込んだデータは引数のbuf変数に設定します。また、実際に読み込んだデータが0バイト、もしくは(2)で指示したサイズよりも小さいということは最後のデータまで読み込まれたということなので、(4)のようにstream->eofに1を立ててストリームの終端まで読み込んだフラグを立てます。また、(5)では、実際に読み込んだデータの総量をカウントし、(6)で今回に実際に読み込んだデータサイズを返します。
続いて、クローズ処理を実装します。
static int php_pzip_ops_close(php_stream *stream, int close_handle TSRMLS_DC)
{
struct php_pzip_stream_data_t *self =
(struct php_pzip_stream_data_t *)stream->abstract; //……(1)
if(self->zf){
zip_fclose(self->zf); // ……(2)
self->zf = NULL;
}
efree(self); // ……(3)
stream->abstract = NULL;
return EOF; // ……(4)
}
(1)は先ほどとまったく同様で、ストリームの状態を管理している構造体にアクセスします。このコードは各命令で同じになるので、実際にはマクロなどを作成して、それを利用するケースが多々あります。後は、(2)のようにそのリソースに沿ったclose処理を行い、(3)のように状態管理の構造体自身のメモリも解放します。(4)のように最後にEOFを返せば、クローズ処理の実装も終了です。
ハンドラ関数登録の構造体の作成
今まで作成してきた関数をPHP側で認識できるように構造体に設定する必要があります。
php_stream_ops php_stream_pzip_ops = { // ……(1)
NULL, // write
php_pzip_ops_read, // ……(2)
php_pzip_ops_close, // ……(3)
NULL, // flush
"pzip", // label
: (省略)
};
そのためには、(1)php_stream_opsの構造体を作成し、(2)、(3)のように先ほど作成した関数を登録します。この構造体は、php_stream.hで定義されており、ストリームに関する定義はそのヘッダファイルを見ることで、詳しい定義が分かります。
ストリームのオープン処理
最後に、ストリームのオープン処理です。オープン処理だけは構造体で管理されずに、プログラマ自身が作成する必要があります。
php_stream *php_stream_pzip_open(struct zip_file *zf, char *mode STREAMS_DC TSRMLS_DC) // ……(1)
{
php_stream *stream = NULL;
struct php_pzip_stream_data_t *self; // ……(2)
if(zf){
self = emalloc(sizeof(*self)); // ……(3)
self->zf = zf;
self->cursor = 0;
stream = php_stream_alloc(&php_stream_pzip_ops, self , NULL ,mode); // ……(4)
if(stream){
return stream;
}
else{
return NULL;
}
}
else{
return NULL;
}
}
(1)php_streamの戻り値を返す関数を定義します。この関数はPZipFile::getStream()の中で利用するためのものです。実際には、その関数内でopenされたストリームを引数を引数に呼び出されます。(2)で、ストリームの状態を管理する構造体の変数を用意し、(3)で実際にメモリを確保します。(4)でPHPのストリームを作成します。その際に、ストリームの操作を設定した構造体変数と、(2)で用意した変数を設定します。
以上で、メソッドを通じてストリームを取得方法が完了しました。
