• このエントリーをはてなブックマークに追加

はじめに

CGIで,multipart/form-data としてPOSTされたときのデータの処理を,CUIでシミュレートっぽくしてみるためのメモです.

CGIまわりの処理は,CGI::Simple を利用しています.

POSTデータ

リクエストボディを想定したものを準備します.boundary=BoundaryBoundary であると仮定します.ここでは,reqbody として保存しています.

--BoundaryBoundary
Content-Disposition: form-data; name="nickname"
 
issm
--BoundaryBoundary
Content-Disposition: form-data; name="hogehoge"
 
fugafuga
--BoundaryBoundary--

Mac OSX の場合,改行コードを,CR+LF にしておく必要がありました.Emacsであれば,Ctrl+x - Enter - f して「utf-8-dos」を入力すればおk.

Perlスクリプト

#!/usr/bin/env perl
use strict;
use warnings;
use utf8;
use lib "$ENV{HOME}/src/git/cgi-extlib-perl/extlib";  # git-cloned from https://github.com/tokuhirom/cgi-extlib-perl
use CGI::Simple;
use Data::Dumper;
 
my $file_reqbody = 'reqbody';
 
sub D { Dumper @_ }
 
$ENV{HTTP_USER_AGENT} = '';
$ENV{QUERY_STRING}    = 'hoge=1&fuga=2';
$ENV{REQUEST_URI}     = '/';
$ENV{REQUEST_METHOD} ||= '';
 
if ($ENV{REQUEST_METHOD} eq 'POST') {
    $ENV{CONTENT_LENGTH} = ( (stat $file_reqbody)[7] ) || 0;
}
 
my $q = CGI::Simple->new;
 
if ($q->cgi_error) {
    print $q->cgi_error, "\n";
    exit;
}
 
print D $q;
print D {$q->Vars};
__END__

CONTENT_LENGTHを手で設定するのはメンドイので,先で保存したファイルのサイズを stat 関数で取得しています.

実行結果

環境変数 REQUEST_METHODCONTENT_TYPE を次のようにセットした上で実行します:

REQUEST_METHOD
POST
CONTENT_TYPE
multipart/form-data; boundary=BoundaryBoundary

このとき,ファイル reqbody を標準入力するようにします.

% REQUEST_METHOD=POST CONTENT_TYPE='multipart/form-data; boundary=BoundaryBoundary' ./cgi-cui.pl < reqbody

出力結果はこんな感じ.

$VAR1 = bless( {
                 '.parameters' => [
                                    'nickname',
                                    'hogehoge'
                                  ],
                 '.globals' => {
                                 'DEBUG' => 0,
                                 'NO_UNDEF_PARAMS' => 0,
                                 'NO_NULL' => 1,
                                 'FATAL' => -1,
                                 'USE_PARAM_SEMICOLONS' => 0,
                                 'PARAM_UTF8' => 0,
                                 'DISABLE_UPLOADS' => 1,
                                 'USE_CGI_PM_DEFAULTS' => 0,
                                 'NPH' => 0,
                                 'POST_MAX' => 102400,
                                 'HEADERS_ONCE' => 0
                               },
                 'hogehoge' => [
                                 'fugafuga'
                               ],
                 'nickname' => [
                                 'issm'
                               ],
                 '.fieldnames' => {
                                    'hogehoge' => 1,
                                    'nickname' => 1
                                  },
                 '.crlf' => '
'
               }, 'CGI::Simple' );
$VAR1 = {
          'nickname' => 'issm',
          'hogehoge' => 'fugafuga'
        };

無事パラメータがセットされているようです.

おまけ: GETの場合は?

REQUEST_METHODGET に設定すると,ソースコード中の QUERY_STRING環境変数でセットした文字列が,パラメータにセットされます.

% REQUEST_METHOD=GET CONTENT_TYPE='multipart/form-data; boundary=BoundaryBoundary' ./cgi-cui.pl < reqbody
$VAR1 = bless( {
                 '.parameters' => [
                                    'hoge',
                                    'fuga'
                                  ],
                 '.globals' => {
                                 'DEBUG' => 0,
                                 'NO_UNDEF_PARAMS' => 0,
                                 'NO_NULL' => 1,
                                 'FATAL' => -1,
                                 'USE_PARAM_SEMICOLONS' => 0,
                                 'PARAM_UTF8' => 0,
                                 'DISABLE_UPLOADS' => 1,
                                 'USE_CGI_PM_DEFAULTS' => 0,
                                 'NPH' => 0,
                                 'POST_MAX' => 102400,
                                 'HEADERS_ONCE' => 0
                               },
                 'fuga' => [
                             '2'
                           ],
                 '.fieldnames' => {
                                    'fuga' => 1,
                                    'hoge' => 1
                                  },
                 'hoge' => [
                             '1'
                           ]
               }, 'CGI::Simple' );
$VAR1 = {
          'fuga' => '2',
          'hoge' => '1'
        };

まとめ

  • 環境変数 REQUEST_METHODCONTENT_TYPECONTENT_LENGTH を適切にセットする
  • POSTデータを標準入力する.ファイルで保存する場合には改行コードに注意

上記条件の下で CGI::Simple->new することで,POSTデータの処理をシミュレートできるっぽいことがわかりました.

おわりに

以上,CGI::Simpleモジュールを使って,multipart/form-dataなPOSTデータ処理を,CUIでシミュレートしてみるためのメモでした.

たぶん CGI モジュール でもいけると思います.

また,今回は「ファイルアップロード」については触れませんでしたが,同じ multipart/form-data なPOSTであれば,まぁなんとかなるんじゃないでしょうかねw