|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
学习了六个多月PHP了,还是个新手,在这里受到了很多人的帮助,谢谢你们! 用ip2addr函数直接读取IP数据库文件是效力最高的,比拟用MySQL数据库存储IP数据,用SQL查询是效力最低的。然而IP数据库文件QQWry.dat是GB2312编码的。如今我需求UTF-8编码的地舆地位了局。假如用MySQL办法,可以在数据存入数据库时就转换为UTF-8编码,与日俱增。然而QQWry.dat文件又没法修正,只能把ip2addr函数的输入了局再停止静态转换。
静态转换GB->UTF-8编码最少有四种办法:
用PHP的iconv扩大转换
用PHP的mb_string扩大转换
用对调表转换,对调表存储在MySQL数据库中
用对调表转换,对调表存储在文本文件中
前两种办法要办事器作了响应设置(编译装置了响应扩大)才干利用。我的虚拟主机没有这两个扩大,只好思索后两种办法。前两个办法本文也不停止测评。
测评法式以下(func_ip.php拜见《IP地址->地舆地位转换的测评》一文):
<?php
require_once ("func_ip.php");
function u2utf8($c) {
$str = "";
if ($c < 0x80) {
$str .= $c;
} elseif ($c < 0x800) {
$str .= chr(0xC0 | $c >> 6);
$str .= chr(0x80 | $c & 0x3F);
} elseif ($c < 0x10000) {
$str .= chr(0xE0 | $c >> 12);
$str .= chr(0x80 | $c >> 6 & 0x3F);
$str .= chr(0x80 | $c & 0x3F);
} elseif ($c < 0x200000) {
$str .= chr(0xF0 | $c >> 18);
$str .= chr(0x80 | $c >> 12 & 0x3F);
$str .= chr(0x80 | $c >> 6 & 0x3F);
$str .= chr(0x80 | $c & 0x3F);
}
return $str;
}
function GB2UTF8_SQL($strGB) {
if (!trim($strGB)) return $strGB;
$strRet = "";
$intLen = strlen($strGB);
for ($i = 0; $i < $intLen; $i++) {
if (ord($strGB{$i}) > 127) {
$strCurr = substr($strGB, $i, 2);
$intGB = hexdec(bin2hex($strCurr)) - 0x8080;
$strSql = "SELECT code_unicode FROM nnstats_gb_unicode
WHERE code_gb = ".$intGB." LIMIT 1"
;
$resResult = mysql_query($strSql);
if ($arrCode = mysql_fetch_array($resResult)) $strRet .= u2utf8($arrCode["code_unicode"]);
else $strRet .= "??";
$i++;
} else {
$strRet .= $strGB{$i};
}
}
return $strRet;
}
function GB2UTF8_FILE($strGB) {
if (!trim($strGB)) return $strGB;
$arrLines = file("gb_unicode.txt");
foreach ($arrLines as $strLine) {
$arrCodeTable[hexdec(substr($strLine, 0, 6))] = hexdec(substr($strLine, 7, 6));
}
$strRet = "";
$intLen = strlen($strGB);
for ($i = 0; $i < $intLen; $i++) {
if (ord($strGB{$i}) > 127) {
$strCurr = substr($strGB, $i, 2);
$intGB = hexdec(bin2hex($strCurr)) - 0x8080;
if ($arrCodeTable[$intGB]) $strRet .= u2utf8($arrCodeTable[$intGB]);
else $strRet .= "??";
$i++;
} else {
$strRet .= $strGB{$i};
}
}
return $strRet;
}
function EncodeIp($strDotquadIp) {
$arrIpSep = explode('.', $strDotquadIp);
if (count($arrIpSep) != 4) return 0;
$intIp = 0;
foreach ($arrIpSep as $k => $v) $intIp += (int)$v * pow(256, 3 - $k);
return $intIp;
//return sprintf('%02x%02x%02x%02x', $arrIpSep[0], $arrIpSep[1], $arrIpSep[2], $arrIpSep[3]);
}
function GetMicroTime() {
list($msec, $sec) = explode(" ", microtime());
return ((double)$msec + (double)$sec);
}
for ($i = 0; $i < 100; $i++) { // 随机发生100个ip地址
$strIp = mt_rand(0, 255).".".mt_rand(0, 255).".".mt_rand(0, 255).".".mt_rand(0, 255);
$arrAddr[$i] = ip2addr(EncodeIp($strIp));
}
$resConn = mysql_connect("localhost", "netnest", "netnest");
mysql_select_db("test");
// 测评MySQL查询的编码转换
$dblTimeStart = GetMicroTime();
for ($i = 0; $i < 100; $i++) {
$strUTF8Region = GB2UTF8_SQL($arrAddr[$i]["region"]);
$strUTF8Address = GB2UTF8_SQL($arrAddr[$i]["address"]);
}
$dblTimeDuration = GetMicroTime() - $dblTimeStart;
// 测评停止并输入了局
echo $dblTimeDuration; echo "\r\n";
// 测评文本文件查询的编码转换
$dblTimeStart = GetMicroTime();
for ($i = 0; $i < 100; $i++) {
$strUTF8Region = GB2UTF8_FILE($arrAddr[$i]["region"]);
$strUTF8Address = GB2UTF8_FILE($arrAddr[$i]["address"]);
}
$dblTimeDuration = GetMicroTime() - $dblTimeStart;
// 测评停止并输入了局
echo $dblTimeDuration; echo "\r\n";
?>
测评两次了局(准确到3位小数,单元是秒):
MySQL查询转换:0.112
文本查询转换:10.590
MySQL查询转换:0.099
文本查询转换:10.623
可见此次是MySQL办法遥遥抢先于文件查询法。然而如今还不急于利用MySQL办法,由于文本文件办法之所以如斯耗时,次要由于它每次转换都要把全部gb_unicode.txt读入内存,而gb_unicode.txt又是文本文件,格局以下:
0x2121 0x3000 # IDEOGRAPHIC SPACE
0x2122 0x3001 # IDEOGRAPHIC COMMA
0x2123 0x3002 # IDEOGRAPHIC FULL STOP
0x2124 0x30FB # KATAKANA MIDDLE DOT
0x2125 0x02C9 # MODIFIER LETTER MACRON (Mandarin Chinese first tone)
……
0x552A 0x6458 # <CJK>
0x552B 0x658B # <CJK>
0x552C 0x5B85 # <CJK>
0x552D 0x7A84 # <CJK>
……
0x777B 0x9F37 # <CJK>
0x777C 0x9F3D # <CJK>
0x777D 0x9F3E # <CJK>
0x777E 0x9F44 # <CJK>
文本文件效力较低,因而思索把文本文件转换为二进制文件,然后用折半法查找这个文件,而不需求把全部文件读入内存。文件格局为:文件头2字节,存储纪录数;接着一条接一笔记录存入文件,每笔记录4字节,前2字节对应GB代码,后2字节对应Unicode代码。转换法式以下:
<?php
$arrLines = file("gb_unicode.txt");
foreach ($arrLines as $strLine) {
$arrCodeTable[hexdec(substr($strLine, 0, 6))] = hexdec(substr($strLine, 7, 6));
}
ksort($arrCodeTable);
$intCount = count($arrCodeTable);
$strCount = chr($intCount % 256) . chr(floor($intCount / 256));
$fileGBU = fopen("gbu.dat", "wb");
fwrite($fileGBU, $strCount);
foreach ($arrCodeTable as $k => $v) {
$strData = chr($k % 256) . chr(floor($k / 256)) . chr($v % 256) . chr(floor($v / 256));
fwrite($fileGBU, $strData);
}
fclose($fileGBU);
?>
履行法式后就取得了二进制的GB->Unicode对比表gbu.dat,而且数据纪录按GB代码排了序,便于折半法查找。利用gbu.dat停止转码的函数以下:
function GB2UTF8_FILE1($strGB) {
if (!trim($strGB)) return $strGB;
$fileGBU = fopen("gbu.dat", "rb");
$strBuf = fread($fileGBU, 2);
$intCount = ord($strBuf{0}) + 256 * ord($strBuf{1});
$strRet = "";
$intLen = strlen($strGB);
for ($i = 0; $i < $intLen; $i++) {
if (ord($strGB{$i}) > 127) {
$strCurr = substr($strGB, $i, 2);
$intGB = hexdec(bin2hex($strCurr)) - 0x8080;
$intStart = 1;
$intEnd = $intCount;
while ($intStart < $intEnd - 1) { // 折半法查找
$intMid = floor(($intStart + $intEnd) / 2);
$intOffset = 2 + 4 * ($intMid - 1);
fseek($fileGBU, $intOffset);
$strBuf = fread($fileGBU, 2);
$intCode = ord($strBuf{0}) + 256 * ord($strBuf{1});
if ($intGB == $intCode) {
$intStart = $intMid;
break;
}
if ($intGB > $intCode) $intStart = $intMid;
else $intEnd = $intMid;
}
$intOffset = 2 + 4 * ($intStart - 1);
fseek($fileGBU, $intOffset);
$strBuf = fread($fileGBU, 2);
$intCode = ord($strBuf{0}) + 256 * ord($strBuf{1});
if ($intGB == $intCode) {
$strBuf = fread($fileGBU, 2);
$intCodeU = ord($strBuf{0}) + 256 * ord($strBuf{1});
$strRet .= u2utf8($intCodeU);
} else {
$strRet .= "??";
}
$i++;
} else {
$strRet .= $strGB{$i};
}
}
return $strRet;
}
把其加到本来的测评法式,对三种办法同时测评2次失掉数据(准确到3位小数,单元:秒):
MySQL办法:0.125
文本文件办法:10.873
二进制文件折半法:0.106
MySQL办法:0.102
文本文件办法:10.677
二进制文件折半法:0.092
可见二进制文件折半法还比MySQL法略有优势。然而上述测评都是对短的地舆地位停止转码,假如对较长的文本转码又若何呢?我找来5个Blog的RSS 2.0文件,都是GB2312编码。测评三种办法对5个文件编码消耗的工夫,2次丈量数据以下(准确到3位小数,单元:秒):
MySQL办法:7.206
文本文件办法:0.772
二进制文件折半法:5.022
MySQL办法:7.440
文本文件办法:0.766
二进制文件折半法:5.055
可见对长的文本是用文本文件的办法最优,由于转码对比表读入内存后,转码就能够很高效了。既然如斯,咱们还可以测验考试改善一下,把文本文件办法改成:转码对比表从二进制文件gbu.dat读入内存,而不是文本文件。测评数据以下(精度和单元同上):
从文本文件读入对比表:0.766
从二进制文件读入对比表:0.831
从文本文件读入对比表:0.774
从二进制文件读入对比表:0.833
标明此次改善掉败了,从文本文件读入转码对比表更高效。
总结:用PHP对GB编码到UTF-8编码的静态转换,假如每次转换的文本很小,合适用二进制文件联合折半法转换;假如每次转换的文本较大,合适用文本文件存储转码对比表,并在转换前一次性把对比表读入内存。
那么接下来,这就算学会啦?NO,NO,NO,还早呢,你至尽还没碰过OOP之类的吧?模板呢? |
|