<?php
/*
  程式 : big5 字串处理函数集
  档名 : big5_func.inc
  作者 : Pigo Chu<pigo@ms5.url.com.tw>
  说明 :
	这些函数是以 PHP4 来处理 big5 字元
	任何人都可以自由散布本程式
	写这些程式是看见 LinuxFab 上讨论区上很多人有中文问题才写的
	我不能保证会发生什么问题 , 若有 bug 请来信讨论不要谩骂
  时间 : 2002/4/21
  版本 : 0.10
  
  版本介绍 :
  0.01 版(2001/5/27) 提供的函数
  string big5_addslashes(string str) : 与 PHP addslashes 一样的功能 , 可以处理中文
  string big5_stripslashes(string str) : 与 stripslashes 一样
  int big5_strlen(string str) : 与 strlen 功能相同
  string big5_substr(string str,int start , int length) : 与 substr 一样
  string big5_strtolower(string str) : 与 strtolower 一样
  string big5_strtoupper(string str) : 与 strtoupper 一样
  
  0.02 版(2001/5/28) 提供的函数
  string big5_chunk_split(string $str, [int $chunklen=76] , [string $end="\r\n"]) : 与 chunk_split 相同
  
  0.03 版(2001/6/16) 提供的函数
  string big5_strpos(string haystack ,string needle , int [offset]) : 传回第一个找到 $str 的位置

  0.04 版(2001/11/12) 修改 bug
  把一些定义与判断式的写错修正 , 感谢网友小蓝 ...
  
  0.05 版(2002/2/13) 修正 big5_stripslashes()
  此函数会把所有 "\" 去掉的问题 , 谢谢网友Neil指正
  
  0.06 版(2002/2/22) 新增 big5_str_replace()
  此函数用法与 str_replace() 一样
  
  0.07 版(2002/4/12) 新增 int big5_stroke($string) 
  此函数可计算单一中文字的笔划 , 若输入的不是中文则return false
   
  0.08 版(2002/4/19) 新增 big5_unicode($string) , big5_utf8_encode(),big5_utf8_decode(), 修改 big5_stroke($string) 
  big5_unicode() 可以将中文转成多国语言给网页用的码
  big5_utf8_encode() 可以将中文转成 UTF8 码
  big5_utf8_decode() 可以将 UTF8 转成 BIG5 码
  big5_stroke() 改成开档方式 , 这样不用到此函数时比较省记忆体

  0.09 呕心版 (2002/4/20) 修正许多函数写法 , 提升效能
  据测试 : big5 转 utf 与 big5 转 unicode 提升效能 0.08 版效能 10 倍以上
  测试 1 万 个中文字转 utf8 大约需要 2.2 秒 , 比前一版(居然超过2分钟快上非常多)
  虽然还不是挺满意 , 不过已经可以接受
  另外 big5_substr , big5_strlen 改了一些写法所有快了一点点 ...
  
  0.10 版 (2002/4/21) 提升 bi5 转 utf8 , unicode , 效能再提升加快 2 倍
  据我自己的电脑测试 , 测试 1 万中文字转 utf8 已经可以低于 1 秒了 ...
  big5_substr() 重写也加快了一点点速度
  
*/

//define("BIG5_FILE_DIR" , DIR_FS_CATALOG . DIR_WS_INCLUDES . "tchinese");   // 本函式库存放的位置 , 很重要喔

define("BIG5_HB_MIN" , 0x81);	// 高位元组最小值
define("BIG5_HB_MAX" , 0xfe);	// 高位元组最大值
define("BIG5_LB1_MIN" , 0x40);	// 低位元组最小值
define("BIG5_LB1_MAX" , 0x7e);	// 低位元组最大值
define("BIG5_LB2_MIN" , 0xa1);	// 低位元组最小值
define("BIG5_LB2_MAX" , 0xfe);	// 低位元组最大值


function big5_isHB($c) {
  $asc = Ord($c);
  if($asc>=BIG5_HB_MIN && $asc<=BIG5_HB_MAX) return true;
  return false;
}

function big5_isLB($c) {
  $asc = Ord($c);
  if(($asc>=BIG5_LB1_MIN && $asc<=BIG5_LB1_MAX)  || ($asc>=BIG5_LB2_MIN && $asc<=BIG5_LB2_MAX))
      return true;
  return false;
}

function big5_global_func($str,$func)
{
   $return_str = "";
   for($i=0; $i<strlen($str); $i++)
   {
       $isHB = 0;		// BIG5 的高位元组识别用
       $isLB = 0;		// BIG5 的低位元组识别用
       $s1 = substr($str,$i,1);
       if(!$isHB && big5_isHB($s1)) // 第一个字符合高位元组
       {
           $isHB = 1;
           $s2 = substr($str,$i+1,1);
           if( big5_isLB($s2) )  // 第二个字符合低位元组
             $isLB = 1;   
       }
       if($isLB && $isHB) {
           $return_str.= $s1.$s2;
           $i++;
       }
       else
       {
           switch($func)
           {
               case "addslashes":
                   $return_str.= addslashes($s1);
                   break;
               case "stripslashes":
               
                   if($s1 == "\\")
                   {  
                       $s2 = substr($str,$i+1,1);
                       if($s2  == "\\")
                           $return_str .= "\\";
                       else
                           $return_str .=$s2 ;
                       $i++;

                   }
                   else $return_str .=$s1;
                   break;
               
               case "strtolower":
                   $return_str.= strtolower($s1);
                   break;
               case "strtoupper":
                   $return_str.= strtoupper($s1);           
                   break;
           }
       }
   }
   

   return $return_str;
}

function big5_addslashes($str) {
   return big5_global_func($str,"addslashes");
}
function big5_stripslashes($str) {
   return big5_global_func($str,"stripslashes");
}
function big5_strtolower($str) {
   return big5_global_func($str,"strtolower");
}
function big5_strtoupper($str) {
   return big5_global_func($str,"strtoupper");
}
function big5_str_replace($search , $replace, $subject)
{
   for($i=0; $i<strlen($subject); $i++)
   {
       $isHB = 0;		// BIG5 的高位元组识别用
       $isLB = 0;		// BIG5 的低位元组识别用
       $s1 = substr($subject,$i,1);
       if(!$isHB && big5_isHB($s1))
       {
           $isHB = 1;
           $s2 = substr($subject,$i+1,1);
           if( big5_isLB($s2) ) // 第二个字符合低位元组
             $isLB = 1;   
       }
       if($isLB && $isHB)
       {
           $first_str = $s1.$s2;
           if($first_str == substr($search,0,2))
           {
               if( substr($subject,$i,strlen($search)) == $search )
               {

                   $return_str .= $replace;
                   $i+=strlen($search)-1;
               }
               else 
               {
                   $return_str .= $first_str;
                   $i++;
               }
           }
           else
           {
               $return_str .= $first_str;
               $i++;
           }
       }
       else
       {
           $first_str = $s1;
           if($first_str == substr($search,0,1))
           {
               if( substr($subject,$i,strlen($search)) == $search )
               {

                   $return_str .=  $replace;
                   $i+=strlen($search)-1;
               }
               else $return_str .= $first_str;
           }
           else $return_str .= $first_str;
       }
   }
   return $return_str;
}


function big5_strlen($str)
{
   $return_len = 0;
   for($i=0; $i<strlen($str); $i++)
   {
       $isHB = 0;		// BIG5 的高位元组识别用
       $isLB = 0;		// BIG5 的低位元组识别用
       $s1 = $str[$i];
       if(!$isHB && big5_isHB($s1))
       {
           $isHB = 1;
           $s2 = $str[($i+1)];
           if( big5_isLB($s2) ) // 第二个字符合低位元组
             $isLB = 1;   
       }
       if($isLB && $isHB) $i++;
       $return_len++;
   }
   return $return_len;
}

function big5_substr($str,$start,$len=0)
{
   $offset = 0;
   if(!$len) $len = strlen($str);
   $str_len =  strlen($str);
   $start = $start-1;
   for($i=0; $i< $str_len; $i++)
   {
     if($offset>$start)
     {
       if(big5_isHB($str[$i]) && big5_isLB($str[($i+1)]))
       {
               $return_str .= $str[$i].$str[$i+1];
               $i++;
       }
       else $return_str .= $str[$i];
       if($offset-$start >= $len) break;
     }
     else if(big5_isHB($str[$i]) && big5_isLB($str[($i+1)]))
         $i++;
     $offset ++;
   }  
   return $return_str;
}



function big5_strpos($haystack ,$needle ,$offset=0) 
{
    $needle_len = big5_strlen($needle);
    $len =big5_strlen($haystack);
    for($i=$offset ; $i<$len ; $i++)
    {
        if(big5_substr($haystack,$offset+$i,$needle_len) == $needle)
            return $i;
    }
    return false;
}

function big5_chunk_split($str, $chunklen=76 , $end="\r\n")
{
   for($i=0 ; $i<big5_strlen($str) ; $i+=$chunklen)
      return big5_substr($str,$i,$chunklen) .$end;
}

// 计算中文字笔划
function big5_stroke($str)
{
    $tab=@File(BIG5_FILE_DIR  ."/big5_stroke.tab");
    if(!$tab)
    {
    	 echo "Can't Open file big5_stroke.tab, plz check define BIG5_FILE_DIR is valid";
    	 exit;
    }
    /* 读取转换表至阵列 $StrokeMapping */
    $i=0;
    while(list($key,$val)=Each($tab))
    {
        $StrokeMapping[$i] = split(" ",$val);
        $StrokeMapping[$i][1] = HexDec($StrokeMapping[$i][1]);
        $StrokeMapping[$i][2] = HexDec($StrokeMapping[$i][2]);
        $i++;
    }

    $s1 = substr($str,0,1);
    $s2 = substr($str,1,1);
    $s  = Hexdec(Bin2hex($s1.$s2));
    
    if( big5_isHB($s1) && big5_isLB($s2) )
    {
        for($i=0;$i<count($StrokeMapping);$i++)
             if($StrokeMapping[$i][1] <= $s && $StrokeMapping[$i][2] >= $s)
                 return $StrokeMapping[$i][0];
    }
    else
        return false;
}

function big5_unicode($str)
{
    $tab=@File(BIG5_FILE_DIR  ."/big5_uni.tab");
    
    if(!$tab)
    {
    	 echo "Can't Open file big5_uni.tab, plz check define BIG5_FILE_DIR is valid";
    	 exit;
    }
    /* 读取转换表至阵列 $UNICODE */
    while(list($key,$val)=Each($tab)) 
        $UNICODE[substr($val,0,4)] = substr($val,5,4);
    // unset($tab);
    $str_len =  strlen($str);

    for($i=0; $i< $str_len; $i++)
    {
      if(big5_isHB($str[$i]) && big5_isLB($str[($i+1)]))
      {
          $s = $str[$i].$str[$i+1];
          $i++;
      }
      else $s = $str[$i];

        if(strlen($s) == 1)
           $ret_str .= "&#" . Hexdec(bin2hex($s)) . ";";
        else
           $ret_str .= "&#" . hexdec($UNICODE[bin2hex($s)]) . ";";
    }  

    return $ret_str;
}



function big5_utf8_encode($str)
{
    // 读取 big5 转 utf8 表格
    $tab = unserialize(@fread(@fopen(BIG5_FILE_DIR  ."/big5_utf8.tab" , "r"),fileSize(BIG5_FILE_DIR  ."/big5_utf8.tab")));

    if(!is_array($tab))
    {
    	 echo "Can't Open file big5_utf8.tab, plz check define BIG5_FILE_DIR is valid";
    	 exit;
    }
   $str_len =  strlen($str);
   for($i=0; $i< $str_len; $i++)
   {
      if(big5_isHB($str[$i]) && big5_isLB($str[($i+1)]))
      {
          $s = $str[$i].$str[$i+1];
          $i++;
      }
      else $s = $str[$i];
      $ret_str.= $tab[bin2hex($s)];
   }  
   return $ret_str;
}

function big5_utf8_decode($str)
{
    // 读取 utf8 转 big5 表格
    $tab = unserialize(@fread(@fopen(BIG5_FILE_DIR  ."/utf8_big5.tab" , "r"),fileSize(BIG5_FILE_DIR  ."/utf8_big5.tab")));

    if(!$tab)
    {
    	 echo "Can't Open file utf8_big5.tab, plz check define BIG5_FILE_DIR is valid";
    	 exit;
    }

    $len = strlen($str);
    for($i=0 ; $i<$len ; $i++)
    {
    	$check = Ord($str[$i]);
        if( $check >> 7 == 0)
            $ret_str .= chr($check);

        else if ( $check>>5 == 6 ) // AscII > 127 的特殊符号
        {
            $ret_str .= $tab[bin2hex($str[$i].$str[$i+1])];
            $i++;
        }
        else if ( $check>> 4 == 0xe)
        {
             $ret_str .= $tab[bin2hex($str[$i].$str[$i+1].$str[$i+2])];
            $i+=2;
        }

    }
   return $ret_str;
}


?>
