色々なファイルの返送

CGIはHTMLテキストファイルだけを返送するプログラムではありません。 画像ファイルや動画、音声などの閲覧のためのファイルや、 閲覧者のディスクにダウンロードさせるための LZH圧縮ファイルなども CGIの出力として送り返すことができます。


● 画像送信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タグによるリンクが使えます。

<IMG SRC="randimag.cgi">
もちろん普通のHREFタグも使えます。


■ 他の形式の閲覧ファイルの転送

他の形式の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"); // その他のバイナリファイル

● 名前を指定した保存ファイルの送信CGI

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


目次

Copyright(C) by Naoki Watanabe. Oct 21st, 1995.
渡辺尚貴 naoki@cms.phys.s.u-tokyo.ac.jp