php中使用gbk/BIG5编码时关于繁体字编码反斜杠的问题

問題說明

 如果您的 MySQL character set 採用「big5」的話,它本身能辨識雙位元文字,那麼以下的內容是您必須要注意的。

 BIG5 碼系統為兩位元組之內碼系統,共可定義 19782 個字碼。其高、低位元組的範圍如下:

 高位元組:0x81 ~ 0xFE(ASCII 129 ~ 254)
低位元組:0x40 ~ 0x7E 與 0xA1 ~ 0xFE(ASCII 64 ~ 126 與 161 ~ 254)

 在許多程式語言之中,ASCII 92()被當作是跳脫(escape)字元,在程式中需要輸出特定字元時,先加上 ,才能被系統所辨識出來。例如:在指定字串變數值時,$Str = "PHP 是一種程式語言",前後都會用到 " 這個字元,如果希望在字串中使用 " 的話,則可以這麼寫:$Str = ""PHP" 是一種程式語言"。如此一來,「PHP」前後的雙引號就可以被視為字串的一部份了。

 問題就出在這裡!假如使用者在文字框中輸入「成功」二字,我們來看看傳到伺服器端的資料是什麼(以下一併顯示中文與十六進位的 ASCII 碼):
使用者端傳送:成(A6 A8)功(A5 5C)
伺服器端接收:成(A6 A8)功(A5 5C 5C)

 有什麼不同?「功」字的後半部是 5C,轉成十進位是 92,剛好就是上述的跳脫字元。為了正確地傳送此一字串,PHP 會自動在該字元之前多加個 。

 顯示在畫面上的是「成功」,只是有點礙眼,沒啥影響。如果要存入資料庫的話,問題就來了:
$SQL = "Insert INTO mytable VALUES ('$Str');";

 對資料庫而言,它將收到一個這樣的命令:

 Insert INTO mytable VALUES ('成功');

 原本「成功」前後的單引號是用來標示字串的,但後面那個單引號加上 之後,就被視為字串的一部份,而該命令就少了一個單引號了。不正確的命令,當然不能期待它會產生正確的執行結果。

解决BIG5繁体编码反斜杠的问题

 只要可供使用者輸入文字的元件(如 Text、Textarea…),都需要經過下列函數的過濾,才能組成對資料庫執行存取動作的 SQL 敘述句。

XML/HTML代码
  1. function Fix_Backslash($org_str) {  
  2.   if ( mysql_client_encoding() != "big5" ) return $org_str;  
  3.   $tmp_length = strlen($org_str);  
  4.   for ( $tmp_i=0; $tmp_i<$tmp_length; $tmp_i++ ) {  
  5.     $ascii_str_a = substr($org_str, $tmp_i , 1);  
  6.     $ascii_str_b = substr($org_str, $tmp_i+1, 1);  
  7.     $ascii_value_a = ord($ascii_str_a);  
  8.     $ascii_value_b = ord($ascii_str_b);  
  9.     if ( $ascii_value_a > 128 ) {  
  10.       if ( $ascii_value_b == 92 ) {  
  11.         $org_str = substr($org_str, 0, $tmp_i+2) . substr($org_str,$tmp_i+3);  
  12.         $tmp_length = strlen($org_str);  
  13.       }  
  14.       $tmp_i++;  
  15.     }  
  16.   }  
  17.   $tmp_length = strlen($org_str);  
  18.   if ( substr($org_str, ($tmp_length-1), 1) == "\" ) $org_str .chr(32);  
  19.   $org_str = str_replace("\0", " 0", $org_str);  
  20.   return $org_str;  
  21. }  

解释说明:

 02 如果您的 MySQL character set 是 big5 之類的,它本身能辨識雙位元文字時,才需要本函數來加以處理。否則,就可以直接回傳原字串了。
請注意:這裡使用 mysql_client_encoding 函數來判斷您的 MySQL character set,而此函數需在 PHP 4.3.0 版以後才能支援。
03 先計算整個字串的總長度,以便後續的迴圈執行「逐字元檢查」的動作。
05 – 06 依序挑出每個字元,與它的下一個字元,意即連續擷取兩個字元。
07 – 08 將挑出的兩個字元分別轉成 ASCII 碼。
若所得的第一個字元大於 ASCII 128 的話(可能是中文字),執行 10 – 13 之間的程式;否則,將迴圈的指標多加 1,這個中文字(兩個字元)算是過關了。
所得的第二個字元恰好是 ASCII 92 的話(如:許、功、俞、餐等字),11 可以將被多加上去的 移除。假如被檢查的字串是「成功了」,請看做法:
檢查到「功」時 $tmp_i 是 2,substr($org_str, 0, $tmp_i+2) 可以擷取「成功」二字,再用 substr($org_str, $tmp_i+3) 擷取「了」字,並組合起來就行了。
12 重算整個字串的總長度,因為字串長度改變了。
17 重算整個字串的總長度,供第 18 行使用。
18 在上述的處理程序之後,如果在字串末尾還有 的話,在其後加個空白。
由於前後文字之間可能組合出 字元(Null),它也會干擾程式的正常運作,所在第 19 行利用 str_replace 函數,將所有的 改成 0(中間加個空白)。

20 大功告成了。

Big5衝碼文字
ASCII(5C) == “”

A45C么 AE5C娉 B85C稞 C25C擺 A55C功
AF5C珮 B95C鈾 C35C黠 A65C吒 B05C豹
BA5C暝 C45C孀 A75C吭 B15C崤 BB5C蓋
C55C髏 A85C沔 B25C淚 BC5C墦 C65C躡
A95C坼 B35C許 BD5C穀 AA5C歿 B45C廄
BE5C閱 AB5C俞 B55C琵 BF5C璞 AC5C枯
B65C跚 C05C餐 AD5C苒 B75C愧 C15C縷

ASCII(7C) == “|”

AA7C泜 B47C揉 A87C育 BE7C魯 B27C琍
BC7C慝 C67C鸛 A97C尚 B37C逖 BD7C罵
A77C坑 B17C悴 BB7C誡 C57C疊 A67C帆
B07C院 BA7C漏 C47C辮 AB7C咽 B57C稅
BF7C糕 AC7C洱 B67C閏 C07C嚐 AD7C迢
B77C會 C17C舉 A47C弋 AE7C徑 B87C腮
C27C甕 A57C四 AF7C砝 B97C頌 C37C牘

上面一段是猜测的,并没有做实际的测试,下面是我自己写的亲自测试过可以用

PHP代码
  1. //過濾繁體字特殊字體  
  2.   function strc($org_str) {  
  3.    $org_str=$org_str."|";//避免末尾最後一個字是特殊字體  
  4.    $tmp_length = strlen($org_str);  
  5.    $position="";  
  6.    for ($tmp_i=0; $tmp_i<$tmp_length$tmp_i++) {  
  7.     $ascii_str_a = substr($org_str$tmp_i , 1);  
  8.     $ascii_str_b = substr($org_str$tmp_i+1, 1);  
  9.     $ascii_value_a = ord($ascii_str_a);  
  10.     $ascii_value_b = ord($ascii_str_b);  
  11.     if ( $ascii_value_a > 128 ) {  
  12.       if ( $ascii_value_b == 92) {//這裡是5C所以用"\" ASCII(92) ,如果是7C是 "|" ASCII(124)  注:這裡只做了\的處理(92)  
  13.      $position.=(string)($tmp_i+2)."|"; 
  14.      //$org_str = substr($org_str, 0, $tmp_i+2).substr($org_str,$tmp_i+3); 
  15.      //$tmp_length = strlen($org_str); 
  16.       } 
  17.       $tmp_i++; 
  18.     } 
  19.     } 
  20.     /* 
  21.     結尾判斷 
  22.     if(ord(substr($org_str,strlen($org_str)-2,1))>128){ 
  23.      echo ord(substr($org_str,strlen($org_str)-1,1));die(); 
  24.     if(ord(substr($org_str,strlen($org_str)-1,1))==92){ 
  25.      $position.=(string)(strlen($org_str))."|"; 
  26.     } 
  27.     } 
  28.     */ 
  29.      $position=substr($position,0,strlen($position)-1); 
  30.      $arr=explode("|",$position); 
  31.      $count=sort($arr); 
  32.     foreach($arr as $key => $val){ 
  33.      if($val!=""){ 
  34.       $val=$val+($key*1); 
  35.       $star_org_str=substr($org_str,0,$val); 
  36.       $end_org_str=substr($org_str,$val,strlen($org_str)); 
  37.       $org_str=$star_org_str."\".$end_org_str;  
  38.      }  
  39.     }  
  40.      $org_str=substr($org_str,0,strlen($org_str)-1);//把最後一個傳進來的符號給去掉(|)  
  41.      return $org_str;  
  42.   }  

 

摘自:http://liangfen1224.blog.163.com/blog/static/7237764720101145184607/

点赞 (0)
  1. 一斑网说道:

    博客的话题太专业了,咱看不懂哪

  2. 抒情散文说道:

    感谢博主的分享,我的连接是 写景抒情散文http://www.jingdianwenji.com/sanwen/shuqing/xiejing/,欢迎来访,点击

  3. 台州租车网说道:

    来看看了呵呵呵

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

Captcha Code