CGIはHTMLテキストファイルだけを返送するプログラムではありません。 画像ファイルや動画、音声などの閲覧のためのファイルや、 閲覧者のディスクにダウンロードさせるための LZH圧縮ファイルなども CGIの出力として送り返すことができます。
例えばこの
四角いアイコンのようにページを訪れるたびに異なる画像を表示することができます。
CGIの出力としてGIF形式の画像ファイルを出力するならば、
CGIの最初の出力で次のように唱えます。
printf("Content-type: image/gif\n\n");
この出力に続いて、送信したいGIF画像の内容をそのまま標準出力に 書き込みます。具体的には次のようなプログラムになります。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char* RandImage( void )
{
static char* ImageName[8] ={
"../ICON/red.gif",
"../ICON/orange.gif",
"../ICON/yellow.gif",
"../ICON/green.gif",
"../ICON/cyan.gif",
"../ICON/blue.gif",
"../ICON/magenta.gif",
"../ICON/deeppink.gif"
};
// time()%8 is not so random though...
return ImageName[time(NULL)%8];
}
int main( void )
{
FILE* fptr = fopen( RandImage(), "r" );
if( fptr == NULL ){
puts(
"Content-type: text/plain\n"
"\n"
"Can not open an image file."
);
exit(1);
}
puts("Content-type: image/gif\n");
int n;
char buf[1024];
while( ( n = fread( buf, 1, 1024, fptr )) > 0 ){
fwrite( buf , 1 , n , stdout );
}
fclose( fptr );
return 0;
}
おわかりと思いますが、RandImage()関数で転送する絵のファイル名を ランダムに決めています。当然これらのファイルが CGIの相対ディレクトリとして所定の位置に置かれていて、他者がアクセスできる ことが前提です。
そしてこのCGIへのリンクにはIMGタグによるリンクが使えます。
もちろん普通のHREFタグも使えます。<IMG SRC="randimag.cgi">
他の形式のbrowserで閲覧するためのファイルの転送も同様に行えます。 代表的な形式の Content-typeの記述法を紹介しておきます。
printf("Content-type: image/jpeg\n\n"); // JPEG画像
printf("Content-type: video/mpeg\n\n"); // MPEG動画
printf("Content-type: audio/x-wav\n\n"); // WAV音声
printf("Content-type: application/pdf\n\n"); // PDF文章
printf("Content-type: application/postscript\n\n"); // PostScript文章
printf("Content-type: application/octet-stream\n\n"); // その他のバイナリファイル
LZH形式等のファイルは、browserで閲覧するのではなく、 閲覧者のディスクに直接セーブさせるものです。CGIでその種のファイルを 送信する方法は画像ファイルでの方法と同じですが、 セーブするファイル名を指定しておくべきであることが異なります。 セーブするファイル名(例えばsavedfile.lzh)は次のようにして ヘッダー中で指定します。
printf("Content-Disposition: attachment; filename='savedfile.lzh'\n");
printf("Content-type: application/octet-stream\n\n");
Browserによっては、ファイル拡張子によって保存しないでその場で表示 してしまうことがあります。
もしなんらかの原因で画像ファイルが開かなくて、エラーメッセージを
出力する場合には気を付けて下さい。この例では Content-typeを出力してから
標準出力にエラーメッセージを書いています。ここで text/plain は
単純なテキストを意味します。
CGIでは Content-typeの指定無しに他の文字列を出力するとその行為自体が
server error を起こすので、閲覧者側では何が起こったのかさっぱりわかりません。
また、CGIが標準エラー出力 stderr にエラーメッセージを書くのはあまり
よろしくありません。なぜならそのメッセージは web server のエラーログファイル
(error_log)に書かれるので、web serverを共有するすべての人に
エラーが知られてしまうのでみっともないのです。
大量のデータを出力する場合には、バッファリングの無い 低水準出力が効率的ですが、低水準を使う場合には Content-typeの出力も低水準で行って下さい。なぜなら バッファリングが無いのでデータの追い越しが発生するからです。