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の出力も低水準で行って下さい。なぜなら バッファリングが無いのでデータの追い越しが発生するからです。