掉坑里了,遭遇到了js与PHP对表单中中文编码、解码方法不统一的问题。
当年上学的时候,对ms很是不屑,总是想玩一些与众不同的东西,玩linux、freebsd,玩opera,玩C++builder。当我做了一个网络开发者,才发现自己曾经是多么的幼稚,才开始怀念IE一统天下的那段美好时光。做一个网络开发者最大的苦恼是什么?对我来说这个问题的答案是:不统一的标准。如果你也经历过下面这些事情,我想你会同意我的看法:
  一个在IE下看起来很正常很美观的页面,在其它的浏览器中却一踏糊涂,反之亦然;
  一段在IE下工作得很完美的js代码,在其它的浏览器中却一点反应都没有,反之亦然;
  ......
也许个性真的是学生才能玩的东西。
不说废话了,说说我遇到的这个问题吧。要做一个无刷新的评论,类似于discuz5.5中的无刷新回帖。在提交表单的时候遇到了问题,通过ajax提交到处理脚本的中文字符串被转成了utf-8的格式,于是在往数据库里执行插入的时候出现了乱码。搜了一把却没有发现解决方案,于是开始自己摸索,摸索的过程中写了下面的函数:

//将类似'%D5%E2%D5%E2%D5%E2%D5%E2%D5%E2%D5%E2'解码,返回一个正常的字符串
function chardecode($str,$sep='%')
{
 $string = str_replace($sep,'',$str);
 $len = strlen($string);
 $strdecode = '';
 for ($i=0;$i<$len;$i+=2){
  $num1 = substr($string,$i,2);
  $num1 = hexdec($num1);
  $i+=2;
  $num2 = substr($string,$i,2);
  $num2 = hexdec($num2);
  $strdecode .= chr($num1).chr($num2);
 }
 return $strdecode;
}
其实这个函数的作用类似于urlencode(),比它强的地方在于可以自己设置每个字符间的分隔符。代码已经足够简单了,用到了两个不太常用的函数,hexdex()和chr()。前者的作用是将一个16进制的数字转换成10进制,后者是将一个数字转换成对应的aiscII字符。
然而这个函数并没能帮我解决问题,乱码依旧。其实解决这个问题主要难点是发现问题到底出在哪里,我并不是一上来就发现中文字符被转成了utf-8格式,只能一点点的摸索,找到了原因这个问题也就不难解决了。
这里用的是pnews里的一个utf-8转gb2312的函数,放出来与大家共享:
function u2g( $instr ) {
 $fp = fopen( '../language/unicode-gb.tab', 'r' );
 $len = strlen($instr);
 $outstr = '';
 for( $i = $x = 0 ; $i < $len ; $i++ ) {
  $b1 = ord($instr[$i]);
  if( $b1 < 0x80 ) {
   $outstr[$x++] = chr($b1);
#   printf( "[%02X]", $b1);
  }
  elseif( $b1 >= 224 ) { # 3 bytes UTF-8
   $b1 -= 224;
   $b2 = ord($instr[$i+1]) - 128;
   $b3 = ord($instr[$i+2]) - 128;
   $i += 2;
   $uc = $b1 * 4096 + $b2 * 64 + $b3 ;
   fseek( $fp, $uc * 2 );
   $gb = fread( $fp, 2 );
   $outstr[$x++] = $gb[0];
   $outstr[$x++] = $gb[1];
#   printf( "[%02X%02X]", ord($gb[0]), ord($gb[1]));
  }
  elseif( $b1 >= 192 ) { # 2 bytes UTF-8
   printf( "[%02X%02X]", $b1, ord($instr[$i+1]) );
   $b1 -= 192;
   $b2 = ord($instr[$i]) - 128;
   $i++;
   $uc = $b1 * 64 + $b2 ;
   fseek( $fp, $uc * 2 );
   $gb = fread( $fp, 2 );
   $outstr[$x++] = $gb[0];
   $outstr[$x++] = $gb[1];
#   printf( "[%02X%02X]", ord($gb[0]), ord($gb[1]));
  }
 }
 fclose($fp);
 if( $instr != '' ) {
#  echo '##' . $instr . " becomes " . join( '', $outstr) . "<br>n";
  return join( '', $outstr);
 }
}
注意函数中用到了一个码表:unicode-gb.tab,附件中的就是了。使用的时候你得根据实际情况把函数中的第一句改成码表实际存放的位置。