第89章 CGIプログラミング その10


前章の方法でカウンターを表示するのではは、SSIが使えない 環境では困ってしまいます。画像ファイルをCGIで転送する方法について考えてみます。



呼び出し側のHTMLが

<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<TITLE>画像表示</TITLE>
</HEAD>
<BODY>
<CENTER>
<H1>画像表示</H1>
<IMG SRC="img.cgi">
</CENTER>
</BODY>
</HTML>
となっている場合、CGIプログラムで画像ファイルを標準出力に出力すれば 画像が表示されるはずです。何か簡単ですね。

fopen関数で画像ファイルをオープンして、fread関数で読み出して、fwrite関数で 標準出力に書き込む。

理屈的にはこれでよいのですが、失敗します。

ファイル入出力は特に指定しないと、テキストモードになってしまいます。 これは、改行文字などを変換するモードです。画像ファイルのデータビットが 偶然改行文字のそれと一致しないとも限りません。

そこで、ファイル入出力はバイナリーモードで行う必要があります。

fopen関数の第2引数の文字列に'b'文字を含ませる必要があります。

これで、fread関数を呼び出せばバイナリーモードで読み込みが行えます。

fopen関数については第18章などを参照してください。

fread関数については第62章を参照してください。

さて、ここで標準出力(stdout)にfwrite関数で書き込みます。

size_t fwrite(
   const void *buffer,
   size_t size,
   size_t count,
   FILE *stream 
);
ストリームにデータを書き込みます。

bufferは書き込むデータへのポインタです。

sizeは項目のサイズ(バイト)です。

countには、書き込む最大項目数を指定します。

streamには、FILE構造体へのポインタを指定します。

戻り値は、実際に書き込まれた項目数となります。この数がcountより少ないと エラーが発生したことになります。

さて、標準出力への書き込みがテキストモードになっていると、これが非常にわかりにくいバグとなります。この関数自体は書き込みモードを指定できません。そこで、_setmode関数を使います。

int _setmode (
   int handle,
   int mode 
);
ファイル変換モードを指定します。

handleには、ファイルハンドルを指定します。

modeには、設定するモードを指定します。テキストモードの時は、_O_TEXT 、バイナリーモードの 時は _O_BINARYを指定します。

関数が失敗したときは-1が返されます。成功したときは直前のモードが返されます。

では、標準出力のファイルハンドルはどのように取得すればよいのでしょうか。

これには、_fileno関数を使います。

int _fileno( 
   FILE *stream 
);
ファイルハンドルが返されます。

streamには、FILE構造体へのポインタを指定します。

さて、これで画像ファイルの出力方法はわかったと思いますが、これだけではいけません。

ファイル出力の前に、どのようなファイルかを指定する必要があります。 ファイルの種類に応じて

"Content-type:image/bmp\n\n"
"Content-type:image/jpeg\n\n"
"Content-type:image/gif\n\n"
などを出力する必要があります。

では、プログラムを見てみましょう。

// img.c

#define FNAME "img/test.jpg"
#include <stdio.h>
#include <fcntl.h>
#include <io.h>


int main(void)
{
    int j;
    unsigned char buf[4];
    FILE *fp;

    printf("Content-type:image/jpeg\n\n");
    fp = fopen(FNAME, "rb");
    if (fp == NULL)
        return -1;
    _setmode(_fileno(stdout), _O_BINARY);

    while (1) {
        j = (int)fread(buf, 1, 1, fp);
        fwrite(buf, 1, j, stdout);

        if (feof(fp))
            break;
    }
    fclose(fp);
    _setmode(_fileno(stdout), _O_TEXT);

    return 0;
}
これで、できたimg.exeをimg.cgiにリネームしてサーバーの指定の場所に置きます。

左の図は実際にjpeg画像を表示しているところです。



さて、ここでは、ファイル入出力について同時にこれが起こった場合の対策は 施されていません。実際のインターネットではさらに、他の危険なことも起こり得るので 注意が必要です。


[Index][総合Index] [Previous Chapter] [Next Chapter]

Update Apr/20/2003 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。