綾小路龍之介の素人思考

ピンの設置

とにかくcgiが呼び出されたらバイナリモードで画像ファイルを読み込んでこれを標準出力するcgiプログラムを考える。よくあるアクセス解析用のPINは一つのプログラムで構成されていることが多い。これを、画像出力、環境変数記録、統計、それぞれ別のモジュールを書くことで同じようなアクセス解析用のcgiプログラムを作る。

ページ訪問者に悟られないようにPINを設置する手法の一つとしてimgタグによるPINが考えられる。これは下のようなHTMLタグをWebページに書き込むことでなされる。

<img src="/pin.cgi" alt="Pin">

このとき呼び出された/pin.cgiはこれが標準出力にバイナリデータを出力するcgiプログラムであるため、訪問者はimgタグの書き込まれた位置に一見普通の画像(hrefにjpgやgif画像が指定されているように)が表示されたように見る。cgiプログラムで標準出力にバイナリを読み込むするには以下のようにして行う。

open IMG,pin.gif;
binmode IMG;
read IMG,$ImgData,-s pin.gif;
close IMG;

pin.gifをファイルハンドルIMGでオープン、ファイルハンドルIMGの読み込み方法をバイナリモードに変更し、ファイルハンドルIMGからpin.gifのファイルサイズ分だけ$ImgDataにデータを複写、ファイルハンドルIMGをクローズ。画像データを読み込んだ後はこれを出力しなければならない。出力は以下のようにして行う。

binmode STDOUT;
print STDOUT "Content-Type: image/gif\n\n";
print STDOUT $ImgData;

標準出力をバイナリモードに変更、後に続くデータの形式を明示するためにMIMEヘッダを標準出力、続けて先ほど読み込んだ$ImgDataをを標準出力。こうすることでブラウザ上に画像が表示される。例えば下のように。このプログラムをWebページに仕込むために最初に示したimgタグを使う。でもその前にこいつをサブルーチンにしておこうと思う。

<img src="http://za.toypark.in/***************.cgi?globe32" alt="ピン" />
  1. PNG Icons & Icon Packs Download | IconsPedia - Free Icons
  2. Globe Icon | Download Vistoon PNG icon | IconsPedia

サブルーチン化は上で述べたモジュール化の第1歩である。ところでサブルーチンとは何か。サブルーチンとはある機能をボタン一つで呼び出せるようにしたものだと思う。別に難しくはない。上で書いた2つのセクションをsub pin{...}の...の部分に入れるだけだ。つまり下のような感じになる。サブルーチンにした場合に限らず、中括弧{}で括られた中身が何行にもわたる場合はインデントする(行頭に等しい量の空白を開ける)ことが望ましいとLarryが言っているのでここではそれに従う。最初に書かれた&pinは今定義した機能を呼びだすボタンである。こいつが書き込まれた場所で、サブルーチンpinが実行される。つまり、機能を定義して、これにボタンをつけても、ボタンを押さなければ機能は発揮されない。

&pin;
sub pin{
  open IMG,pin.gif;
  binmode IMG;
  read IMG,$ImgData,-s pin.gif;
  close IMG;
  binmode STDOUT;
  print STDOUT "Content-Type: image/gif\n\n";
  print STDOUT $ImgData;
}

ついでにもう少し汎用性を持たせてみる。例えば、別の画像に差し替えたい場合を考えてみる。上のサブルーチンで表示される画像はpin.gifという名前だが、別に違ってもいいはずだ。サブルーチンの中に出現する"pin.gif"の回数は2回なので、もし別の画像を表示したい場合は、2箇所書き換えなければならない。これは面倒なので、"pin.gif"を内容に持つ変数を作って画像ファイルの名前が必要なときは常にその変数にお伺いを立てて変数の中身を尋ねる事にする。例えば下のような感じだ。こうすることで画像の差し替えを行いたい場合はpinサブルーチンのはじめに書かれた変数$ImgFileの内容を書き換えればよいことになる。ところでmyとは何か。myを変数の前につけることで、my以降に続く変数は、myの含まれる中括弧の中だけで有効な変数になる。つまり、中括弧の外からは$ImgFileにお伺いを立てることができないのである。myを使うことは、サブルーチンを含めてプログラムが大きくなってきたときに意味を持ってくると思う。なぜなら、人間は自分の定義した変数の名前とそれの内容を覚えておけないからだ。簡単に言えば、全く同じ内容を持つ異なる名前の変数を作ることは、メモリの無駄使いだし、全く同じ名前を持つ異なる内容の変数を作ることは、混乱の元である。

&pin;
sub pin{
  my $ImgFile = 'pin.gif';
  my $ImgData;
  open IMG,$ImgFile;
  binmode IMG;
  read IMG,$ImgData,-s $ImgFile;
  close IMG;
  binmode STDOUT;
  print STDOUT "Content-Type: image/gif\n\n";
  print STDOUT $ImgData;
}

さて、中括弧の外からは$ImgFileにお伺いを立てることができない、ということは、中括弧の外からは$ImgFileを書き換えることができない、という事である。myをはずせばできないこともないが、理由を上で述べたようにあまりお勧めできない。書き換えるためには、サブルーチンに引数を与えればよい。引数を与えるとは、サブルーチンを呼び出す&pin時に、括弧をつけて呼び出す&pin(...)ことである。括弧の中身を引数と呼ぶ。引数はサブルーチンの外と中で変数をやり取りするために設けられたものと考えてよいと思う。引数にpin.gifを与えてサブルーチンを呼び出せば$ImgFileを書き換えることができる。例えば下のような感じだ。重要なのは&pin($ImgFile)の引数$ImgFileと、サブルーチンの中にある$ImgFileとは別物、ということだ。別物という意味は、コンピュータはこれを区別するという意味だ。人間様にとって重要なのは$ImgFileという名前の引数には画像ファイルの名前pin.gifが含まれているということだ。だから、サブルーチンの中でも外でも画像ファイルの名前を内容に持つ変数には$ImgFileという名前を付ける。特に今までやってきたように、既存の機能をサブルーチンとしてまとめる場合には、サブルーチンの中でも外でも同じ名前の変数を使い、サブルーチンの外で定義された変数を中で使用するためにこれを引数で与えることが多いように思う。どちらにしても、サブルーチンは一度定義したら、中身を書き換えなくてもよいモノであったほうがよいと思う。このような汎用性を与えるためにはサブルーチンの中で""や''を使うような変数の定義(外から書き換えられない変数の定義)は避けたほうがよいと思う。

my $ImgFile = 'pin.gif';
&pin($ImgFile);
sub pin{
  my $ImgFile = $_[0];
  my $ImgData;
  open IMG,$ImgFile;
  binmode IMG;
  read IMG,$ImgData,-s $ImgFile;
  close IMG;
  binmode STDOUT;
  print STDOUT "Content-Type: image/gif\n\n";
  print STDOUT $ImgData;
}

前述のようにサブルーチンには汎用性がなければならない。上のサブルーチンの問題点をさらにあげるとするならばMIMEがgifに固定されている点だろう。つまり、このままではサブルーチンpinの引数にはgifファイルしか指定できない。例えば、pngやjpegファイルは指定できない。この言い方には多少問題がある。それは、ファイルがgifファイルであることを確かめるにはファイルの内容を解析しなければならないからだ。MIMEと以降に続く内容は整合性が取れていなければならないが、この整合性を判断するにはファイルの内容を解析しなければならない。もちろん正しい解析によりファイルの種類を判別しすることがもっとも望ましいが、解析によって得られた判定が間違っていないとも限らないし、ブラウザによっては送られてきたMIMEよりも自分の判断を優先するブラウザもある。そんなわけでMIMEを厳密に判定せずに、ファイルに付けられた拡張子を元にしてContent-Type宣言をしようと思う。まぁ、ファイルに付けられた拡張子だって詐称可能なんだから、あまり説得力ないけど。とりあえず今日はここまで。

ソーシャルブックマーク

  1. はてなブックマーク
  2. Google Bookmarks
  3. del.icio.us

ChangeLog

  1. Posted: 2008-10-26T04:54:00+09:00
  2. Modified: 2008-10-26T07:18:03+09:00
  3. Generated: 2017-03-29T23:09:53+09:00