从MS Word复制的表单字段在数据库中输入时会导致无效字符

时间:2011-01-20 05:09:10

标签: php database forms ms-word

我遇到的问题是提交给PHP脚本然后插入MySQL数据库的Web表单。

问题在于Copy&从Microsoft Word或类似的文字处理软件粘贴,主要影响项目符号,但有时会影响引号和单引号。我无法嗅到该人提交的字符编码。

我的文件顶部有以下代码(函数)来处理数据:

function init_byte_map(){
  global $byte_map;
  for($x=128;$x<256;++$x){
    $byte_map[chr($x)]=utf8_encode(chr($x));
  }
  $cp1252_map=array(
    "\x80"=>"\xE2\x82\xAC",    // EURO SIGN
    "\x82" => "\xE2\x80\x9A",  // SINGLE LOW-9 QUOTATION MARK
    "\x83" => "\xC6\x92",      // LATIN SMALL LETTER F WITH HOOK
    "\x84" => "\xE2\x80\x9E",  // DOUBLE LOW-9 QUOTATION MARK
    "\x85" => "\xE2\x80\xA6",  // HORIZONTAL ELLIPSIS
    "\x86" => "\xE2\x80\xA0",  // DAGGER
    "\x87" => "\xE2\x80\xA1",  // DOUBLE DAGGER
    "\x88" => "\xCB\x86",      // MODIFIER LETTER CIRCUMFLEX ACCENT
    "\x89" => "\xE2\x80\xB0",  // PER MILLE SIGN
    "\x8A" => "\xC5\xA0",      // LATIN CAPITAL LETTER S WITH CARON
    "\x8B" => "\xE2\x80\xB9",  // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
    "\x8C" => "\xC5\x92",      // LATIN CAPITAL LIGATURE OE
    "\x8E" => "\xC5\xBD",      // LATIN CAPITAL LETTER Z WITH CARON
    "\x91" => "\xE2\x80\x98",  // LEFT SINGLE QUOTATION MARK
    "\x92" => "\xE2\x80\x99",  // RIGHT SINGLE QUOTATION MARK
    "\x93" => "\xE2\x80\x9C",  // LEFT DOUBLE QUOTATION MARK
    "\x94" => "\xE2\x80\x9D",  // RIGHT DOUBLE QUOTATION MARK
    "\x95" => "\xE2\x80\xA2",  // BULLET
    "\x96" => "\xE2\x80\x93",  // EN DASH
    "\x97" => "\xE2\x80\x94",  // EM DASH
    "\x98" => "\xCB\x9C",      // SMALL TILDE
    "\x99" => "\xE2\x84\xA2",  // TRADE MARK SIGN
    "\x9A" => "\xC5\xA1",      // LATIN SMALL LETTER S WITH CARON
    "\x9B" => "\xE2\x80\xBA",  // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
    "\x9C" => "\xC5\x93",      // LATIN SMALL LIGATURE OE
    "\x9E" => "\xC5\xBE",      // LATIN SMALL LETTER Z WITH CARON
    "\x9F" => "\xC5\xB8"       // LATIN CAPITAL LETTER Y WITH DIAERESIS
  );
  foreach($cp1252_map as $k=>$v){
    $byte_map[$k]=$v;
  }
}

function fix_latin($instr){
  if(mb_check_encoding($instr,'UTF-8'))return $instr; // no need for the rest if it's all valid UTF-8 already
  global $nibble_good_chars,$byte_map;
  $outstr='';
  $char='';
  $rest='';
  while((strlen($instr))>0){
    if(1==preg_match($nibble_good_chars,$input,$match)){
      $char=$match[1];
      $rest=$match[2];
      $outstr.=$char;
    }elseif(1==preg_match('@^(.)(.*)$@s',$input,$match)){
      $char=$match[1];
      $rest=$match[2];
      $outstr.=$byte_map[$char];
    }
    $instr=$rest;
  }
  return $outstr;
}

$byte_map=array();
init_byte_map();
$ascii_char='[\x00-\x7F]';
$cont_byte='[\x80-\xBF]';
$utf8_2='[\xC0-\xDF]'.$cont_byte;
$utf8_3='[\xE0-\xEF]'.$cont_byte.'{2}';
$utf8_4='[\xF0-\xF7]'.$cont_byte.'{3}';
$utf8_5='[\xF8-\xFB]'.$cont_byte.'{4}';
$nibble_good_chars = "@^($ascii_char+|$utf8_2|$utf8_3|$utf8_4|$utf8_5)(.*)$@s";

然后我收到每个表单字段并运行fix_latin函数。

        foreach ($jobdata AS $field => $string)
        {
            $string = fix_latin($string);
            $jobdata[$field] = addslashes(str_replace("\n", '<br />', htmlspecialchars($string)));
        }

数据输入数据库,并通过电子邮件发送给系统管理员进行审批。今天我收到了一封管理员电子邮件,内容如下:

    Job Description: Responsibilities: 
路 Assist multi-state companies

当我查看数据库或在脚本中编辑时,子弹替换为方框,而不是•实体。

1 个答案:

答案 0 :(得分:0)

表单应使用与其主机文档相同的字符编码进行提交。理论上,您可以在声明表单时使用<form accept-charset="UTF-8">覆盖字符编码,但这在Internet Explorer中不起作用(惊喜)。

如果您对包含表单的页面使用相同的字符编码,则需要使用正确的字符编码来获取数据。

此外,如果您的脚本同时发送电子邮件并将数据存储到表中,则需要确保电子邮件和表格都使用相同的字符编码。您需要在电子邮件中设置相应的标题,以确保读者知道您正在使用的字符编码。

我建议您始终使用UTF8,确保您的数据库和网页都使用UTF8编码,并且您的脚本发送的任何电子邮件也会设置一个标题,表明它们也使用UTF8进行编码。它应该有希望消除像您一直使用的那样繁琐的转换功能的需要。我自己在一个项目中遇到了类似的问题,起初我尝试了解决问题的方法,但最终它只是处理得太多了,因为你需要捕获和处理成千上万的潜在输入。

与此同时,一个简单的解决方法是不直接从Word粘贴,而是从Word粘贴到简单的文本编辑器(如记事本),然后从记事本复制并粘贴到浏览器。