<?php
class Chinese
{

	/**
	 * 存放簡體中文與拼音對照表
	 *
	 * @變量類型  數組
	 * @起始      1.0
	 * @最後修改  1.0
	 * @訪問      內部
	 */
	var $pinyin_table = array();

	
	/**
	 * 存放 GB <-> UNICODE 對照表的內容
	 * @變量類型  
	 * @起始      1.1
	 * @最後修改  1.2
	 * @訪問      內部
	 */
	var $unicode_table = array();

	/**
	 * 訪問中文繁簡互換表的文件指針
	 *
	 * @變量類型  對象
	 * @起始      1.0
	 * @最後修改  1.0
	 * @訪問      內部
	 */
	var $ctf;

	/**
	 * 等待轉換的字符串
	 * @變量類型
	 * @起始      1.0
	 * @最後修改  1.0
	 * @訪問      內部
	 */
	var $SourceText = "";

	/**
	 * Chinese 的運行配置
	 *
	 * @變量類型  數組
	 * @起始      1.0
	 * @最後修改  1.2
	 * @訪問      公開
	 */
	var $config  =  array(
		'codetable_dir'         => "./config/",           //  存放各種語言互換表的目錄
		'SourceLang'            => '',                    //  字符的原編碼
		'TargetLang'            => '',                    //  轉換後的編碼
		'GBtoBIG5_table'        => 'gb-big5.table',       //  簡體中文轉換為繁體中文的對照表
		'BIG5toGB_table'        => 'big5-gb.table',       //  繁體中文轉換為簡體中文的對照表
		'GBtoPinYin_table'      => 'gb-pinyin.table',     //  簡體中文轉換為拼音的對照表
		'GBtoUnicode_table'     => 'gb-unicode.table',    //  簡體中文轉換為UNICODE的對照表
		'BIG5toUnicode_table'   => 'big5-unicode.table'   //  繁體中文轉換為UNICODE的對照表
	);

	/**
	 * Chinese 的悉構函數
	 *
	 * 詳細說明
	 * @形參      字符串 $SourceLang 為需要轉換的字符串的原編碼
	 *            字符串 $TargetLang 為轉換的目標編碼
	 *            字符串 $SourceText 為等待轉換的字符串
	 *            字符串 $CodetableDir 編碼對應表的目錄
	 *
	 * @起始      1.0
	 * @最後修改  1.2
	 * @訪問      公開
	 * @返回值    無
	 * @throws
	 */
	function Chinese( $SourceLang , $TargetLang , $SourceString='', $CodetableDir='')
	{
		if ($SourceLang != '') {
		    $this->config['SourceLang'] = $SourceLang;
		}

		if ($TargetLang != '') {
		    $this->config['TargetLang'] = $TargetLang;
		}

		if ($SourceString != '') {
		    $this->SourceText = $SourceString;
		}

		// codes Added by Zeal Li on ver 1.6 begin.
		if ($CodetableDir != '') {
			if(! is_dir($CodetableDir)){
				echo "configuration directory [".$CodetableDir."] not exists!";
				exit;
			}
		    $this->config['codetable_dir'] = $CodetableDir;
		}
		// codes Added by Zeal Li on ver 1.6 end.

		$this->OpenTable();
	} // 結束 Chinese 的悉構函數


	/**
	 * 將 16 進制轉換為 2 進制字符
	 *
	 * 詳細說明
	 * @形參      $hexdata 為16進制的編碼
	 * @起始      1.5
	 * @最後修改  1.5
	 * @訪問      內部
	 * @返回      字符串
	 * @throws    
	 */
	function _hex2bin( $hexdata )
	{
		for ( $i=0; $i<strlen($hexdata); $i+=2 )
			$bindata.=chr(hexdec(substr($hexdata,$i,2)));

		return $bindata;
	}


	/**
	 * 打開對照表
	 *
	 * 詳細說明
	 * @形參      
	 * @起始      1.3
	 * @最後修改  1.3
	 * @訪問      內部
	 * @返回      無
	 * @throws    
	 */
	function OpenTable()
	{
	    
		// 假如原編碼為簡體中文的話
		if ($this->config['SourceLang']=="GB2312") {

			// 假如轉換目標編碼為繁體中文的話
			if ($this->config['TargetLang'] == "BIG5") {
				$this->ctf = fopen($this->config['codetable_dir'].$this->config['GBtoBIG5_table'], "r");
				if (is_null($this->ctf)) {
					echo "打開打開轉換表文件失敗！";
					exit;
				}
			}

			// 假如轉換目標編碼為拼音的話
			if ($this->config['TargetLang'] == "PinYin") {
				$tmp = @file($this->config['codetable_dir'].$this->config['GBtoPinYin_table']);
				if (!$tmp) {
					echo "打開打開轉換表文件失敗！";
					exit;
				}
				//
				$i = 0;
				for ($i=0; $i<count($tmp); $i++) {
					$tmp1 = explode("	", $tmp[$i]);
					$this->pinyin_table[$i]=array($tmp1[0],$tmp1[1]);
				}
			}

			// 假如轉換目標編碼為 UTF8 的話
			if ($this->config['TargetLang'] == "UTF8") {
				$tmp = @file($this->config['codetable_dir'].$this->config['GBtoUnicode_table']);
				if (!$tmp) {
					echo "打開打開轉換表文件失敗！";
					exit;
				}
				$this->unicode_table = array();
				while(list($key,$value)=each($tmp))
					$this->unicode_table[hexdec(substr($value,0,6))]=substr($value,7,6);
			}

			// 假如轉換目標編碼為 UNICODE 的話
			if ($this->config['TargetLang'] == "UNICODE") {
				$tmp = @file($this->config['codetable_dir'].$this->config['GBtoUnicode_table']);
				if (!$tmp) {
					echo "打開打開轉換表文件失敗！";
					exit;
				}
				$this->unicode_table = array();
				while(list($key,$value)=each($tmp))
					$this->unicode_table[hexdec(substr($value,0,6))]=substr($value,9,4);
			}
		}

		// 假如原編碼為繁體中文的話
		if ($this->config['SourceLang']=="BIG5") {
			// 假如轉換目標編碼為簡體中文的話
			if ($this->config['TargetLang'] == "GB2312") {
				$this->ctf = fopen($this->config['codetable_dir'].$this->config['BIG5toGB_table'], "r");
				if (is_null($this->ctf)) {
					echo "打開打開轉換表文件失敗！";
					exit;
				}
			}
			// 假如轉換目標編碼為 UTF8 的話
			if ($this->config['TargetLang'] == "UTF8") {
				$tmp = @file($this->config['codetable_dir'].$this->config['BIG5toUnicode_table']);
				if (!$tmp) {
					echo "打開打開轉換表文件失敗！";
					exit;
				}
				$this->unicode_table = array();
				while(list($key,$value)=each($tmp))
					$this->unicode_table[hexdec(substr($value,0,6))]=substr($value,7,6);
			}

			// 假如轉換目標編碼為 UNICODE 的話
			if ($this->config['TargetLang'] == "UNICODE") {
				$tmp = @file($this->config['codetable_dir'].$this->config['BIG5toUnicode_table']);
				if (!$tmp) {
					echo "打開打開轉換表文件失敗！";
					exit;
				}
				$this->unicode_table = array();
				while(list($key,$value)=each($tmp))
					$this->unicode_table[hexdec(substr($value,0,6))]=substr($value,9,4);
			}

			// 假如轉換目標編碼為拼音的話
			if ($this->config['TargetLang'] == "PinYin") {
				$tmp = @file($this->config['codetable_dir'].$this->config['GBtoPinYin_table']);
				if (!$tmp) {
					echo "打開打開轉換表文件失敗！";
					exit;
				}
				//
				$i = 0;
				for ($i=0; $i<count($tmp); $i++) {
					$tmp1 = explode("	", $tmp[$i]);
					$this->pinyin_table[$i]=array($tmp1[0],$tmp1[1]);
				}
			}
		}

		// 假如原編碼為 UTF8 的話
		if ($this->config['SourceLang']=="UTF8") {

			// 假如轉換目標編碼為 GB2312 的話
			if ($this->config['TargetLang'] == "GB2312") {
				$tmp = @file($this->config['codetable_dir'].$this->config['GBtoUnicode_table']);
				if (!$tmp) {
					echo "打開打開轉換表文件失敗！";
					exit;
				}
				$this->unicode_table = array();
				while(list($key,$value)=each($tmp))
					$this->unicode_table[hexdec(substr($value,7,6))]=substr($value,0,6);
			}

			// 假如轉換目標編碼為 BIG5 的話
			if ($this->config['TargetLang'] == "BIG5") {
				$tmp = @file($this->config['codetable_dir'].$this->config['BIG5toUnicode_table']);
				if (!$tmp) {
					echo "打開打開轉換表文件失敗！";
					exit;
				}
				$this->unicode_table = array();
				while(list($key,$value)=each($tmp))
					$this->unicode_table[hexdec(substr($value,7,6))]=substr($value,0,6);
			}
		}

	} // 結束 OpenTable 函數

	/**
	 * 打開本地或者遠程的文件
	 *
	 * 詳細說明
	 * @形參      字符串 $position 為需要打開的文件名稱，支持帶路徑或URL
	 *            布爾值 $isHTML 為待轉換的文件是否為html文件
	 * @起始      1.1
	 * @最後修改  1.1
	 * @訪問      公開
	 * @返回      無
	 * @throws    
	 */
	function OpenFile( $position , $isHTML=false )
	{
	    $tempcontent = @file($position);

		if (!$tempcontent) {
		    echo "打開文件失敗！";
			exit;
		}

		$this->SourceText = implode("",$tempcontent);

		if ($isHTML) {
			$this->SourceText = eregi_replace( "charset=".$this->config['SourceLang'] , "charset=".$this->config['TargetLang'] , $this->SourceText);

			$this->SourceText = eregi_replace("\n", "", $this->SourceText);

			$this->SourceText = eregi_replace("\r", "", $this->SourceText);
		}
	} // 結束 OpenFile 函數

	/**
	 * 打開本地或者遠程的文件
	 *
	 * 詳細說明
	 * @形參      字符串 $position 為需要打開的文件名稱，支持帶路徑或URL
	 * @起始      1.1
	 * @最後修改  1.1
	 * @訪問      公開
	 * @返回      無
	 * @throws    
	 */
	function SiteOpen( $position )
	{
	    $tempcontent = @file($position);

		if (!$tempcontent) {
		    echo "打開文件失敗！";
			exit;
		}

		// 將數組的所有內容轉換為字符串
		$this->SourceText = implode("",$tempcontent);

		$this->SourceText = eregi_replace( "charset=".$this->config['SourceLang'] , "charset=".$this->config['TargetLang'] , $this->SourceText);


//		ereg(href="css/dir.css"
	} // 結束 OpenFile 函數

	/**
	 * 設置變量的值
	 *
	 * 詳細說明
	 * @形參
	 * @起始      1.0
	 * @最後修改  1.0
	 * @訪問      公開
	 * @返回值    無
	 * @throws
	 */
	function setvar( $parameter , $value )
	{
		if(!trim($parameter))
			return $parameter;

		$this->config[$parameter] = $value;

	} // 結束 setvar 函數

	/**
	 * 將簡體、繁體中文的 UNICODE 編碼轉換為 UTF8 字符
	 *
	 * 詳細說明
	 * @形參      數字 $c 簡體中文漢字的UNICODE編碼的10進制
	 * @起始      1.1
	 * @最後修改  1.2
	 * @訪問      內部
	 * @返回      字符串
	 * @throws    
	 */
	function CHSUtoUTF8($c)
	{
		$str="";

		if ($c < 0x80) {
			$str.=$c;
		}

		else if ($c < 0x800) {
			$str.=(0xC0 | $c>>6);
			$str.=(0x80 | $c & 0x3F);
		}

		else if ($c < 0x10000) {
			$str.=(0xE0 | $c>>12);
			$str.=(0x80 | $c>>6 & 0x3F);
			$str.=(0x80 | $c & 0x3F);
		}

		else if ($c < 0x200000) {
			$str.=(0xF0 | $c>>18);
			$str.=(0x80 | $c>>12 & 0x3F);
			$str.=(0x80 | $c>>6 & 0x3F);
			$str.=(0x80 | $c & 0x3F);
		}

		return $str;
	} // 結束 CHSUtoUTF8 函數
	
	/**
	 * 簡體、繁體中文 <-> UTF8 互相轉換的函數
	 *
	 * 詳細說明
	 * @形參      
	 * @起始      1.1
	 * @最後修改  1.5
	 * @訪問      內部
	 * @返回      字符串
	 * @throws    
	 */
	function CHStoUTF8(){

		if ($this->config["SourceLang"]=="BIG5" || $this->config["SourceLang"]=="GB2312") {
			$ret="";

			while($this->SourceText != ""){

				if(ord(substr($this->SourceText,0,1))>127){

					if ($this->config["SourceLang"]=="BIG5") {
						$utf8=$this->CHSUtoUTF8(hexdec($this->unicode_table[hexdec(bin2hex(substr($this->SourceText,0,2)))]));
					}
					if ($this->config["SourceLang"]=="GB2312") {
						$utf8=$this->CHSUtoUTF8(hexdec($this->unicode_table[hexdec(bin2hex(substr($this->SourceText,0,2)))-0x8080]));
					}
					for($i=0;$i<strlen($utf8);$i+=3)
						$ret.=chr(substr($utf8,$i,3));

					$this->SourceText=substr($this->SourceText,2,strlen($this->SourceText));
				}
				
				else{
					$ret.=substr($this->SourceText,0,1);
					$this->SourceText=substr($this->SourceText,1,strlen($this->SourceText));
				}
			}
			$this->unicode_table = array();
			$this->SourceText = "";
			return $ret;
		}

		if ($this->config["SourceLang"]=="UTF8") {
			$out = "";
			$len = strlen($this->SourceText);
			$i = 0;
			while($i < $len) {
				$c = ord( substr( $this->SourceText, $i++, 1 ) );
				switch($c >> 4)
				{ 
					case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
						// 0xxxxxxx
						$out .= substr( $this->SourceText, $i-1, 1 );
					break;
					case 12: case 13:
						// 110x xxxx   10xx xxxx
						$char2 = ord( substr( $this->SourceText, $i++, 1 ) );
						$char3 = $this->unicode_table[(($c & 0x1F) << 6) | ($char2 & 0x3F)];

						if ($this->config["TargetLang"]=="GB2312")
							$out .= $this->_hex2bin( dechex(  $char3 + 0x8080 ) );

						if ($this->config["TargetLang"]=="BIG5")
							$out .= $this->_hex2bin( $char3 );
					break;
					case 14:
						// 1110 xxxx  10xx xxxx  10xx xxxx
						$char2 = ord( substr( $this->SourceText, $i++, 1 ) );
						$char3 = ord( substr( $this->SourceText, $i++, 1 ) );
						$char4 = $this->unicode_table[(($c & 0x0F) << 12) | (($char2 & 0x3F) << 6) | (($char3 & 0x3F) << 0)];

						if ($this->config["TargetLang"]=="GB2312")
							$out .= $this->_hex2bin( dechex ( $char4 + 0x8080 ) );

						if ($this->config["TargetLang"]=="BIG5")
							$out .= $this->_hex2bin( $char4 );
					break;
				}
			}

			// 返回結果
			return $out;
		}
	} // 結束 CHStoUTF8 函數

	/**
	 * 簡體、繁體中文轉換為 UNICODE編碼
	 *
	 * 詳細說明
	 * @形參      
	 * @起始      1.2
	 * @最後修改  1.2
	 * @訪問      內部
	 * @返回      字符串
	 * @throws    
	 */
	function CHStoUNICODE()
	{

		$utf="";

		while($this->SourceText != "")
		{
			if (ord(substr($this->SourceText,0,1))>127)
			{

				if ($this->config["SourceLang"]=="GB2312")
					$utf.="&#x".$this->unicode_table[hexdec(bin2hex(substr($this->SourceText,0,2)))-0x8080].";";

				if ($this->config["SourceLang"]=="BIG5")
					$utf.="&#x".$this->unicode_table[hexdec(bin2hex(substr($this->SourceText,0,2)))].";";

				$this->SourceText=substr($this->SourceText,2,strlen($this->SourceText));
			}
			else
			{
				$utf.=substr($this->SourceText,0,1);
				$this->SourceText=substr($this->SourceText,1,strlen($this->SourceText));
			}
		}
		return $utf;
	} // 結束 CHStoUNICODE 函數

	/**
	 * 簡體中文 <-> 繁體中文 互相轉換的函數
	 *
	 * 詳細說明
	 * @起始      1.0
	 * @訪問      內部
	 * @返回值    經過編碼的utf8字符
	 * @throws
	 */
	function GB2312toBIG5()
	{
		// 獲取等待轉換的字符串的總長度
		$max=strlen($this->SourceText)-1;

		for($i=0;$i<$max;$i++){

			$h=ord($this->SourceText[$i]);

			if($h>=160){

				$l=ord($this->SourceText[$i+1]);

				if($h==161 && $l==64){
					$gb="  ";
				}
				else{
					fseek($this->ctf,($h-160)*510+($l-1)*2);
					$gb=fread($this->ctf,2);
				}

				$this->SourceText[$i]=$gb[0];
				$this->SourceText[$i+1]=$gb[1];
				$i++;
			}
		}
		fclose($this->ctf);

		// 將轉換後的結果賦予 $result;
		$result = $this->SourceText;

		// 清空 $thisSourceText
		$this->SourceText = "";

		// 返回轉換結果
		return $result;
	} // 結束 GB2312toBIG5 函數

	/**
	 * 根據所得到的編碼搜尋拼音
	 *
	 * 詳細說明
	 * @起始      1.0
	 * @最後修改  1.0
	 * @訪問      內部
	 * @返回值    字符串
	 * @throws
	 */
	function PinYinSearch($num){

		if($num>0&&$num<160){
			return chr($num);
		}

		elseif($num<-20319||$num>-10247){
			return "";
		}

		else{

			for($i=count($this->pinyin_table)-1;$i>=0;$i--){
				if($this->pinyin_table[$i][1]<=$num)
					break;
			}

			return $this->pinyin_table[$i][0];
		}
	} // 結束 PinYinSearch 函數

	/**
	 * 簡體、繁體中文 -> 拼音 轉換
	 *
	 * 詳細說明
	 * @起始      1.0
	 * @最後修改  1.3
	 * @訪問      內部
	 * @返回值    字符串，每個拼音用空格分開
	 * @throws
	 */
	function CHStoPinYin(){
		if ( $this->config['SourceLang']=="BIG5" ) {
			$this->ctf = fopen($this->config['codetable_dir'].$this->config['BIG5toGB_table'], "r");
			if (is_null($this->ctf)) {
				echo "打開打開轉換表文件失敗！";
				exit;
			}

			$this->SourceText = $this->GB2312toBIG5();
			$this->config['TargetLang'] = "PinYin";
		}

		$ret = array();
		$ri = 0;
		for($i=0;$i<strlen($this->SourceText);$i++){

			$p=ord(substr($this->SourceText,$i,1));

			if($p>160){
				$q=ord(substr($this->SourceText,++$i,1));
				$p=$p*256+$q-65536;
			}

			$ret[$ri]=$this->PinYinSearch($p);
			$ri = $ri + 1;
		}

		// 清空 $this->SourceText
		$this->SourceText = "";

		$this->pinyin_table = array();

		// 返回轉換後的結果
		return implode(" ", $ret);
	} // 結束 CHStoPinYin 函數

	/**
	 * 輸出轉換結果
	 *
	 * 詳細說明
	 * @形參
	 * @起始      1.0
	 * @最後修改  1.2
	 * @訪問      公開
	 * @返回      字符換
	 * @throws
	 */
	function ConvertIT()
	{
		// 判斷是否為中文繁、簡轉換
		if ( ($this->config['SourceLang']=="GB2312" || $this->config['SourceLang']=="BIG5") && ($this->config['TargetLang']=="GB2312" || $this->config['TargetLang']=="BIG5") ) {
			return $this->GB2312toBIG5();
		}

		// 判斷是否為簡體中文與拼音轉換
		if ( ($this->config['SourceLang']=="GB2312" || $this->config['SourceLang']=="BIG5") && $this->config['TargetLang']=="PinYin" ) {
			return $this->CHStoPinYin();
		}

		// 判斷是否為簡體、繁體中文與UTF8轉換
		if ( ($this->config['SourceLang']=="GB2312" || $this->config['SourceLang']=="BIG5" || $this->config['SourceLang']=="UTF8") && ($this->config['TargetLang']=="UTF8" || $this->config['TargetLang']=="GB2312" || $this->config['TargetLang']=="BIG5") ) {
			return $this->CHStoUTF8();
		}

		// 判斷是否為簡體、繁體中文與UNICODE轉換
		if ( ($this->config['SourceLang']=="GB2312" || $this->config['SourceLang']=="BIG5") && $this->config['TargetLang']=="UNICODE" ) {
			return $this->CHStoUNICODE();
		}

	} // 結束 ConvertIT 函數

} // 結束類庫

/**
*/

?>
