プログラムテクニックメモ(2001/07/12)
画面フォーム間でのデータ送信は、POST か GET の形式にて通常行いますが、このデータ送信の際に困るのが、データ項目名とデータとの切り分けなのです。実際なにが困るのかと言うと、データの区切り文字とデータ中に区切り文字が発生した場合が困るのです。
「xyz=aaaa」という場合は、xyz項目名は aaaa というデータです。となるのですが、「xyz=x=a」と記述された場合は、xyz項目名は x=a と解釈できないからです。この問題を解決するためにURLエンコードという手法を使い、データ部を特殊文字に置き換える事によって解決します。「xyz=%82%A1%AB%62」とかという文字列を見たことありませんか? それがURLエンコードされた文字なのです。
半角の[0-9]、[a-z]、[A-Z]、[*-.@_]は、そのまま記述([]は、関係ないです)し、半角スペースは 「+」で置き換え、日本語等の8bit文字は、漢字コードの上位・下位に「%」を付け変換します。例えば漢字コード "あ" は 0xA4A2 ですので %A4%A2 となります。
変換例: ()'~!あ*-._ → abZ+%28%29%27%7E%21%A4%A2*-._
下記ソースは、gcc でコンパイルしましたが、特殊な命令は使用していないので、大抵の Cコンパイラでコンパイルできるでしょう。(ソース)
下記関数の仕様としては、エラー時には(-1)を返し、正常時には変換した文字列長を返します。また、第2引数に指定された領域には、URLエンコードした文字列ポインタが格納(使用終了後は、必ずfreeすること)されます。
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
/* *-._ はそのまま、スペースは +、あとはエンコード */
static char enctbl[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
'+', 0, 0, 0, 0, 0, 0, 0, 0, 0, '*', 0, 0, '-', '.', 0,
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0, 0, 0, 0, '_',
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static char codetbl[16] = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F' };URLencode(char *in, char **out)
{
int len; /* data length */
char *str = in; /* in data pointer */
unsigned char hi, lo;
unsigned char cstr;
char *outp;
int cnt = 0;
/* in param nodata */
if (!in || (len = strlen(in)) == 0)
return -1;
/* output area */
outp = (char *)malloc(sizeof(char) * ((len * 3) + 1));
memset( outp, 0, (len * 3) + 1);
/**/
while( *str ) {
cstr = *str;
if ( enctbl[cstr] > 0) {
outp[cnt++] = enctbl[cstr];
} else {
hi = cstr >> 4;
lo = cstr << 4; lo = lo >> 4;
outp[cnt++] = '%';
outp[cnt++] = codetbl[hi];
outp[cnt++] = codetbl[lo];
}
str++;
}
/* data output area malloc */
if ((*out = (char *)malloc(sizeof(char) * cnt + 1)) == NULL) {
free(outp);
return(-1);
}
/**/
strcpy(*out, outp);
free(outp);
return (cnt + 1);
}