D言語でCGI / フォーム表示、取得(UTF-8)


フォーム表示、取得

フォーム項目の表示と、取得は以下のようにします。 ほとんどDikiからの引用になっているのが恥ずかしいところです。 上のほうはおまじないだと思って、main関数のみ見てください。 new CGIとしてCGIオブジェクトを作って、cgi.reqsでフォーム値を取得します。 78kbyte以上のフォーム項目を受けると死んでしまうため、staticコンストラクタで処理せずにnewするようにしています。また、htmlタグを書き込むことで発生するクロスサイトスクリプティングを防止するために、入力されたデータはhtmlエスケープしています。

ソース

import std.conv;
import std.stream;
class URI
{
    // I don't know why it's wrong on arm-linux...
    //private static int [char] h2i;
    //private static int [char] noEsc;
    private static int [256] h2i;
    private static int [256] noEsc;
    static this()
    {
        for(char c='0'; c<='9'; ++c)         h2i[c] = c - '0';
        for(char c='A'; c<='F'; ++c)         h2i[c] = c - 'A' + 10;
        for(char c='a'; c<='f'; ++c)         h2i[c] = c - 'a' + 10;
        for(char c=0x20; c<=0x7E; ++c)       noEsc[c] = true;
        foreach(char c ; ";/?:&=+,-_.!~'()") noEsc[c] = false;
    }

    static char[] encode( char[] s )
    {
        char[] r;
        foreach( char c ; s )
            if( noEsc[c] ) r ~= (c==' ' ? '+' : c);
            else           r ~= int_format("%%%02X", c);
        version (IgnoreCase) {
            r = tolower(r);
        }
        return r;
    }

    static char[] decode( char[] s )
    {
        char[] r;
        for( int i=0; i!=s.length; ++i )
            switch( s[i] )
            {
            default:  r ~= s[i]; break;
            case '+': r ~= ' ';  break;
            case '%':
                if( i+1>=s.length )         break;
                if( s[++i]=='%' ) { r~='%'; break; }
                if( i+1>=s.length )         break;
                r~= cast(char)( 16*h2i[s[i]] + h2i[s[i+1]] );
                ++i;
            }
        version (IgnoreCase) {
            r = tolower(r);
        }
        return r;
    }
    static char[] int_format( char[] fmt, int v )
    {
        MemoryStream m = new MemoryStream();
        m.printf( fmt, v );
        return cast(char[]) m.data();
    }
}

extern(C) char* getenv( char* envvarname );
class Env
{
    static char[] opIndex( char[] varname )
    {
        char* result = getenv( toStringz(varname) );
        return result is null ? `` : std.string.toString(result);
    }
    class asInt {
        static int opIndex( char[] v )
        {
            return toInt( Env[v] );
        }
    }
}

class CGI
{
    final static char[]         self_name;
    final static char[][char[]] reqs;

    this()
    {
        char[] query;
        switch( Env[`REQUEST_METHOD`] )
        {
        case `GET` : query = Env[`QUERY_STRING`];                      break;
        case `POST`: query = readStdIn( Env.asInt[`CONTENT_LENGTH`] ); break;
        }
        foreach( char[] pair ; split(query,`&`) )
        {
            char[][] kv = split( pair, `=` );
            switch( kv.length )
            {
            case 1: reqs[``]               = URI.decode(kv[0]); break;
            case 2: reqs[URI.decode(kv[0])] = URI.decode(kv[1]); break;
            }
        }

        self_name = Env[`REQUEST_URI`];
        self_name = self_name[ rfind(self_name,'/')+1 .. self_name.length ];
        int end = find(self_name,'?');
        if( end >= 0 ) self_name = self_name[0 .. end];
    }

    private char[] readStdIn( uint size )
    {
        ubyte[] buf; buf.length = size;
        ubyte* ptr = buf;

        int x=0, y=1;
        while( x<size && y!=0 )
        {
            y = stdin.readBlock( ptr+x, size-x );
            x += y;
        }

        buf.length = x;
        return cast(char[]) buf;
    }
}
char[] escapeHTML(char[] str)
{
    str = replace(str,"&","&amp;");
    str = replace(str,"<","&lt;");
    str = replace(str,">","&gt;");
    str = replace(str,"\"","&quot;");
    str = replace(str,"'","&#39;");
    return str;
}

void main()
{
    CGI cgi = new CGI();
    char[] name = escapeHTML(cgi.reqs["name"]);
    printf(`content-type:text/html;

<html>
<body>
%.*s
<form name="a" action="form.cgi">
<input type="text" value="%.*s" name="name"><br>
<input type="submit" value="送信">
</form>
</body>
</html>
`,name,name);

}

ファイル

&ref(): File not found: "form.zip" at page "D言語でCGI/フォーム表示、取得(UTF-8)";

実行例

http://p38.aaacafe.ne.jp/~sakurai/cgi-bin/form.cgi

*MenuBar

人気の10件

  • counter: 2693
  • today: 1
  • yesterday: 0
  • online: 1