摘要:這篇文章記錄圖書館查詢微信公眾平臺開發(fā)全過程,主要內(nèi)容包括:(1)Fidder2解析圖書館登入系統(tǒng)過程(2)模擬圖書館登入系統(tǒng)過程(3)機器識別驗證碼(4)Unicode轉(zhuǎn)UTF-8編碼過程(5)微信公眾賬號的綁定(6)Memcache緩存技術(shù)(7)正則表達(dá)式
這是一篇記錄我的第一個微信應(yīng)用——福建農(nóng)林大學(xué)圖書館服務(wù)的開發(fā)記錄,應(yīng)用架設(shè)在Sina App Engine,開發(fā)目標(biāo)是解決手機登入web查看圖書不便的問題,并提供響應(yīng)的服務(wù)功能,比如(1)圖書5天內(nèi)圖書到期的提醒(2)圖書的查詢服務(wù)(3)圖書借閱的查詢服務(wù)(4)暫時圖書館沒有藏書的到書提醒(5)免驗證碼登陸,算是對自己多天折騰的總結(jié)并提供有相關(guān)需求的朋友一些思路。
Fidder2解析圖書館登入系統(tǒng)過程
Fidder2介紹
Fiddler是一個http協(xié)議調(diào)試代理工具,它能夠記錄并檢查所有你的電腦和互聯(lián)網(wǎng)之間的http通訊,設(shè)置斷點,查看所有的“進(jìn)出”Fiddler的數(shù)據(jù)(指cookie,html,js,css等文件,這些都可以讓你胡亂修改的意思)。 Fiddler 要比其他的網(wǎng)絡(luò)調(diào)試器要更加簡單,因為它不僅僅暴露http通訊還提供了一個用戶友好的格式。
利用Fidder可以方便的從數(shù)據(jù)連接中扒取鏈接的信息,即使是表單是通過_POST,我們也能夠很方便的從數(shù)據(jù)流中截取用戶發(fā)送的信息,從而將機器偽裝成人肉對服務(wù)器進(jìn)行請求,實現(xiàn)模擬登入。
通過Fidder查看圖書館登入過程
首先,打開Fidder,開始對通信進(jìn)行監(jiān)聽,登入我們的目標(biāo)站點——福建農(nóng)林大學(xué)圖書館的登入頁面http://210.34.85.114:8080/reader/login.php,輸入學(xué)號,密碼和驗證碼(正不正確不重要,這里主要查看數(shù)據(jù)的發(fā)送格式),選擇證件號,點擊登入,打開Fidder,選擇驗證服務(wù)器的urlhttp://210.34.85.114:8080/reader/redr_verify.php,在Inspectors下的Raw標(biāo)簽下可以看到發(fā)送的信息,如下
POST http://210.34.85.114:8080/reader/redr_verify.php HTTP/1.1
Host: 210.34.85.114:8080
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://210.34.85.114:8080/reader/login.php
Cookie: PHPSESSID=ordh88pv46g9jco23d32pvqer3
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 70
number=3125002076&passwd=147qj9&captcha=1173&select=cert_no&returnUrl=
發(fā)送的目標(biāo)地址
POST http://210.34.85.114:8080/reader/redr_verify.php HTTP/1.1
用戶進(jìn)行瀏覽器的頭文件為:
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
用戶發(fā)送的信息格式為:
number=3125002076&passwd=147qj9&captcha=1173&select=cert_no&returnUrl=
后頭我們將對這些信息進(jìn)行封裝,通過curl POST至目標(biāo)地址http://210.34.85.114:8080/reader/redr_verify.php HTTP/1.1。
由于本文涉及到驗證碼的機器識別,所以我們還需要獲取生成驗證碼的服務(wù)器地址,F(xiàn)idder中我們可以找到生成驗證碼的urlhttp://210.34.85.114:8080/reader/captcha.php,返回數(shù)據(jù)格式為captcha.gif
模擬圖書館登入系統(tǒng)過程
//*-----------------------------------WXLibSearch.php--------------------------------------*//
<?php
include ('Valite.php'); //驗證碼識別類
include ('u2utf82gb.php'); //NCR轉(zhuǎn)GB2312類
//獲取用戶鍵入的信息
function getborrowedbookinfo ($keyword){
/*
*正則表達(dá)式檢測用戶輸入信息是否為"學(xué)號(10位)+密碼"
*如果是則進(jìn)行模擬登入獲取借閱信息
*如果輸入錯誤則返回"請按照格式輸入學(xué)號和密碼"
*/
if (preg_match_all("/^(\d{10})\+\S+/",$keyword,$info")){
//切割字符串,學(xué)號為前10位(0-9),密碼為第11后(10-)
$num=substr($info,0,9); //學(xué)號
$pass=substr($info,11); //密碼
//獲取驗證碼url
$url = "http://210.34.85.114:8080/reader/captcha.php";
//保存cookie在當(dāng)前路徑下的"valid.tmp"文件之中,跨頁面?zhèn)鬟f用戶信息
$cookie = dirname(__FILE__)."/valid.tmp";
//curl訪問驗證碼圖片網(wǎng)址,把返回的cookie保存為valid.tmp文件
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //設(shè)定返回 的數(shù)據(jù)是否自動顯示
curl_setopt($curl, CURLOPT_COOKIEFILE, $cookie);
curl_setopt($curl, CURLOPT_COOKIEJAR, $cookie); // 把返回來的cookie信息保存在$cookie文件中
$data = curl_exec($curl);
curl_close($curl);
//保存驗證碼圖片
$fp = fopen("valid.gif","wb");
fwrite($fp, $data);
fclose($fp);
//識別驗證碼圖片
$valid = new Valite();
$valid->setImage("valid.gif");
$valid->getHec();
$validCode = $valid->run();
//組裝數(shù)據(jù)
$data = "number=".$num."&passwd=".$pass."&captcha=".$validCode."&select=cert_no&returnUrl=";
//頭文件
$headers = array(
"User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0","Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3",
"Accept-Encoding: gzip, deflate",
);
//curl發(fā)送數(shù)據(jù)進(jìn)行登陸
$url = "http://210.34.85.114:8080/reader/redr_verify.php";
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); /設(shè)定是否顯示頭信息
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_COOKIEFILE, $cookie);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl,CURLOPT_POSTFIELDS,$data);
$src = curl_exec($curl);
curl_close($curl);
//利用cookie進(jìn)行借閱圖書查詢
$url = "http://210.34.85.114:8080/reader/book_lst.php";
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_COOKIEFILE, $cookie);
$src = curl_exec($curl);
curl_close($curl);
//截取出html中的書名
$booknum = preg_match_all('/<a[^>]+>\S+<\/a>/',$src,$bookinfo);
$hadborrowed = $booknum-23; //當(dāng)前借閱量
$bookborrowed = "當(dāng)前借閱量:$hadborrowed";
$bookborrowed = iconv('UTF-8', 'GB2312', $bookborrowed);
$books = ""; //建立容器儲存書名
$n = 0; //用于為標(biāo)題名前加上標(biāo)號
for ($i=23;$i<$booknum;$i++){
$n = $n+1;
$str1 = ""; //建立容器用于儲存轉(zhuǎn)化為GB2312的字符,每循環(huán)一次數(shù)據(jù)清空,儲存到$books容器之中
//unicode轉(zhuǎn)化為utf-8
//通過explode,標(biāo)記為";"將字符串切割成單個Uincode編碼字符
$bookinf = explode(';',$bookinfo[0][$i]);
foreach($bookinf as $bookinfx){ //遍歷字符串字符進(jìn)行轉(zhuǎn)碼
$bookinfx = preg_replace('/<[^>]+>/','',$bookinfx); //除去頭尾字符的html標(biāo)簽
$code = substr($bookinfx,3); //除去16位NCR編碼的表示部分"&#x"
$unicode = hexdec($code); //16進(jìn)制轉(zhuǎn)化我10進(jìn)制
$string = u2utf82gb($unicode); //Unicode轉(zhuǎn)GB2312
$str1 = $str1.$string; //將轉(zhuǎn)碼后的單個字符拼接起來
}
$books = $books.$n.".".$str1; //將每個書名拼接起來并加上標(biāo)號"$n."
}
echo $bookborrowed."\n".$books; //輸出借閱的圖書量加上書名輸出測試
}
}
?>
機器識別驗證碼
驗證碼識別一般分為以下幾個步驟:
一、取出字模
識別驗證碼,畢竟不是專業(yè)的OCR識別,并且,由于各個網(wǎng)站的驗證碼各不相同,所以,最常見的方法就是就是建立這個驗證碼的特征碼庫。去字模時,我們需要多下載幾張圖片,使這些圖片中,包括所有的字符,我們這里的圖片里只有數(shù)字,所以,只要收集到包括0-9的數(shù)字圖片即可。
1、多刷新幾次驗證碼,將驗證碼圖片保存起來,要搜集齊0-9的圖片,這里我收集了4張驗證碼才湊齊0~9 10位數(shù)字。
2、用圖片處理軟件打開圖片,我用的是Photoshop,按住ctrl+可以將圖片的視圖放大,這樣就能很清楚地觀察到圖片的每個像素。
可以發(fā)現(xiàn),每個數(shù)字的寬是8px,高是10px,數(shù)字的間隔是4px,第一個數(shù)字左邊偏移了6px,頂部偏移了16px。這些數(shù)字后面都是要用到的。
3、將每個數(shù)字截出來保存為圖片,大小為8*10(雖然數(shù)字1的寬只占了7個像素,但是還是要截取8個像素的寬度)。
二、圖片二值化
二值化就是把圖片上的驗證數(shù)字上每個象素用數(shù)字1表示,其它部分用0表示。把要識別的圖片,進(jìn)行二值化,將數(shù)據(jù)保存到二維數(shù)組里,得到圖片特征數(shù)組。
1、首先要將數(shù)字和背景色和干擾色區(qū)分開來,用屏幕取色器觀察顏色的規(guī)律。
可以得出一個結(jié)論:背景顏色的R、G、B值都是大于200的,而數(shù)字的顏色的R、G、B值的某一項有小于200,因此可以很容易區(qū)分。
2、下面的php代碼只是為了演示二維數(shù)組,為了直觀看出數(shù)字,所以把1和0改為了0和-:
echo '<br><img src="captcha.gif"><br><br>';
getHec("captcha.gif"); //"captcha.gif"中的值為8690
function getHec($imagePath) {
$res = imagecreatefromjpeg($imagePath);
$size = getimagesize($imagePath);
for ($i = 0; $i < $size[1]; ++$i) {
for ($j = 0; $j < $size[0]; ++$j) {
$rgb = imagecolorat($res, $j, $i);
$rgbarray = imagecolorsforindex($res, $rgb);
if ($rgbarray['red'] < 200 || $rgbarray['green']<200 || $rgbarray['blue'] < 200) {
echo "0";
}else{
echo "-";
}
}
echo "<br>";
}
}
二值化的結(jié)果如下圖所示:
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
--------0000--------0000--------0000---------00-------------
-------00--00------00--00------00--00-------0000------------
------00----00----00----0-----00----00-----00--00-----------
-------00--00-----00----------00----00----00----00----------
--------0000------00-000-------00--000----00----00----------
-------00--00-----000--00-------000-00----00----00----------
------00----00----00----00----------00----00----00----------
------00----00----00----00-----0----00-----00--00-----------
-------00--00------00--00------00--00-------0000------------
--------0000--------0000--------0000---------00-------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
如果圖片的背景顏色比較復(fù)雜,處理方法也是一樣的,總能找到臨界值來區(qū)分,具體要靠自己觀察了。
三、數(shù)字字模二值化
計算出每個數(shù)字字模的二值化的數(shù)據(jù),記錄下這些數(shù)據(jù),當(dāng)作key即可。
1、將0-9的數(shù)字字模圖片進(jìn)行二值化,逐個取出圖片的像個像素的顏色,然后獲取每個像素的R、G、B值,再進(jìn)行判斷,代碼如下:
for ($i = 0; $i < 10; $i++) {
echo "'$i'=>'";
echo getHec("$i.jpg")."',<br>";
}
function getHec($imagePath) {
$res = imagecreatefromjpeg($imagePath);
$size = getimagesize($imagePath);
for ($i = 0; $i < $size[1]; ++$i) {
for ($j = 0; $j < $size[0]; ++$j) {
$rgb = imagecolorat($res, $j, $i);
$rgbarray = imagecolorsforindex($res, $rgb);
if ($rgbarray['red'] < 200 || $rgbarray['green']<200 || $rgbarray['blue'] < 200) {
echo "1";
}else{
echo "0";
}
}
}
}
輸出結(jié)果:
'0' => '011110100001100001100001100001100001100001100001100001011110',
'1' => '001000111000001000001000001000001000001000001000001000111110',
'2' => '011110100001100001000001000010000100001000010000110011111111',
'3' => '011110100001100001000010001100000010000001100001100001011110',
'4' => '000100000100001100010100100100100100111111000100001100001111',
'5' => '111111100000100000101110110001000001000001100001100001011110',
'6' => '001110010001100000100000101110110001100001100001100001011110',
'7' => '111111100010100010000100000100001000001000001000001000001000',
'8' => '011110100001100001100001011110010010100001100001100001011110',
'9' => '011100100010100001100001100011011101000001000001100010011100',
四、對照樣本
把步驟二中的圖片特征碼和步驟三中的驗證碼的字模進(jìn)行對比,得到驗證圖片上的數(shù)字。
算法過程:
1、將圖片二值化后的值保存到二維數(shù)組里。
2、通過循環(huán),求出每一個數(shù)字的位置,要用到前面得到的數(shù)字的寬、高、間隔、左邊偏移、頂部偏移。
例如:第i個數(shù)字左邊偏移 =(數(shù)字寬 + 間隔)* i + 左邊偏移。
3、知道了數(shù)字的偏移位置,就可以計算出數(shù)字在二維數(shù)組里的位置,通過循環(huán)將數(shù)字的6*10=60個數(shù)據(jù)取出來拼接在一起,就形成了與數(shù)字字模類似的字符串。
4、將字符串與每一個字模的字符串比較,求其相似度,取最高的相似度對應(yīng)的數(shù)字,或者相似度達(dá)到95%以上就可以斷定是某個數(shù)字。
5、識別結(jié)果如下:
使用目前這種方法,對驗證碼的識別基本上可以做到100%。
通過以上步驟,您可能說了,并沒有發(fā)現(xiàn)如何取出干擾素?。∑鋵嵢〕龈蓴_素的方法很簡單,干擾素的一個重要特征是,不能影響驗證碼的顯示效果,所以制作干擾素時它的RGB可能低于或者高于某個特定值,比如我給的例子中的圖片,干擾素的RGB各項值是不會小于200的,所以,這樣我們就很容易去掉干擾素了。
//*-----------------------------------Valite.php--------------------------------------*//
<?php
define('WORD_WIDTH',8); //定義每個字符的高度
define('WORD_HIGHT',10); //定義每個字的寬度
define('OFFSET_X',6); //左偏移的像素數(shù)
define('OFFSET_Y',16); //高偏移的像素數(shù)
define('WORD_SPACING',4); //字符間的像素數(shù)
class valite
{
public function setImage($Image) //打開二維碼圖片
{
$this->ImagePath = $Image;
}
public function getData()
{
return $data;
}
public function getResult()
{
return $DataArray;
}
public function getHec() //除去干擾像素的方法
{
$res = imagecreatefromgif($this->ImagePath); //創(chuàng)建圖像
$size = getimagesize($this->ImagePath); //獲取圖像長寬
$data = array();
for($i = 0; $i < $size[1]; ++$i) //循環(huán)遍歷寬度
{
for($j = 0; $j < $size[0]; ++$j) //循環(huán)遍歷長度
{
$rgb = imagecolorat($res,$j,$i); //取得某像素的顏色索引值
$rgbarray = imagecolorsforindex($res, $rgb); // 取出red,green,blue 和 alpha 的鍵名的關(guān)聯(lián)數(shù)組
if($rgbarray['red'] < 160 || $rgbarray['green'] < 160 || $rgbarray['blue'] < 160) //比較RGB值
{
$data[$i][$j]=1; //數(shù)字輸出1
}else{
$data[$i][$j]=0; //背景輸出0
}
}
}
$this->DataArray = $data; //返回數(shù)據(jù)
$this->ImageSize = $size;
}
public function run() //獲取每個像素點的坐標(biāo)
{
$result = "";
$data = array("","","","");
for($i = 0; $i < 4; ++$i) //循環(huán),切割四個數(shù)字
{
$x = ($i * (WORD_WIDTH + WORD_SPACING)) + OFFSET_X; //計算每個數(shù)字的起始水平像素的值X
$y = OFFSET_Y;
for($h = $y; $h < (OFFSET_Y + WORD_HIGHT); ++$h) //循環(huán)獲取每個數(shù)字的豎直像素值
{
for($w = $x; $w < ($x + WORD_WIDTH); ++$w) //循環(huán)獲取水平像素值
{
$data[$i] .= $this->DataArray[$h][$w]; //儲存每個數(shù)字的二值碼
}
}
}
foreach($data as $numKey => $numString) //循環(huán)每個數(shù)字的二值碼
{
$max = 0.0;
$num = 0;
foreach($this->Keys as $key => $value) //匹配每個的字模二值碼
{
$percent = 0.0; //初始相似百分比
similar_text($value, $numString, $percent); //計算兩個字符串的相似度(以百分比計)
if(intval($percent) > $max) //當(dāng)前相似度與前一次循環(huán)的相似度比較,如果比前一次相似度高則
{
$max = $percent; //儲存最大相似度百分比
$num = $key; //儲存最大百分比的數(shù)字
if(intval($percent) > 95) //將字符串與每一個字模的字符串比較,求其相似度,取最高的相似度對應(yīng)的數(shù)字,或者相似度達(dá)到95%以上就可以斷定是某個數(shù)字
break;
}
}
$result .= $num;
}
$this->data = $result;
return $result;
}
public function Draw() //按順序取出每個相熟點的值(0/1)
{
for($i = 0; $i < $this->ImageSize[1]; ++$i)
{
for($j = 0; $j < $this->ImageSize[0]; ++$j)
{
echo $this->DataArray[$i][$j];
}
echo "\n";
}
}
public function __construct() //二值化的每個數(shù)字
{
$this->Keys = array(
'0'=>'00011000001111000110011011000011110000111100001111000011011001100011110000011000',
'1'=>'00011000001110000111100000011000000110000001100000011000000110000001100001111110',
'2'=>'00111100011001101100001100000011000001100000110000011000001100000110000011111111',
'3'=>'01111100110001100000001100000110000111000000011000000011000000111100011001111100',
'4'=>'00000110000011100001111000110110011001101100011011111111000001100000011000000110',
'5'=>'11111110110000001100000011011100111001100000001100000011110000110110011000111100',
'6'=>'00111100011001101100001011000000110111001110011011000011110000110110011000111100',
'7'=>'11111111000000110000001100000110000011000001100000110000011000001100000011000000',
'8'=>'00111100011001101100001101100110001111000110011011000011110000110110011000111100',
'9'=>'00111100011001101100001111000011011001110011101100000011010000110110011000111100',
);
}
protected $ImagePath;
protected $DataArray;
protected $ImageSize;
protected $data;
protected $Keys;
protected $NumStringArray;
}
?>
NRC轉(zhuǎn)UTF-8編碼過程
UTF-8的編碼規(guī)則很簡單,只有二條:
1)對于單字節(jié)的符號,字節(jié)的第一位設(shè)為0,后面7位為這個符號的unicode碼。因此對于英語字母,UTF-8編碼和ASCII碼是相同的。
2)對于n字節(jié)的符號(n>1),第一個字節(jié)的前n位都設(shè)為1,第n+1位設(shè)為0,后面字節(jié)的前兩位一律設(shè)為10。剩下的沒有提及的二進(jìn)制位,全部為這個符號的unicode碼。
下表總結(jié)了編碼規(guī)則,字母x表示可用編碼的位。
<table><tr><td>Unicode符號范圍(十六進(jìn)制)</td><td>UTF-8編碼方式(二進(jìn)制)</td></tr>
<tr><td>0000 0000-0000 007F</td><td>0xxxxxxx</td></tr>
<tr><td>0000 0080-0000 07FF</td><td>110xxxxx 10xxxxxx</td></tr>
<tr><td>0000 0800-0000 FFFF</td><td>1110xxxx 10xxxxxx 10xxxxxx</td></tr>
<tr><td>0001 0000-0010 FFFF</td><td>11110xxx 10xxxxxx 10xxxxxx 10xxxxxx</td></tr></table>
下面,還是以漢字“嚴(yán)”為例,演示如何實現(xiàn)UTF-8編碼。
已知“嚴(yán)”的unicode是4E25(100111000100101),根據(jù)上表,可以發(fā)現(xiàn)4E25處在第三行的范圍內(nèi)(0000 0800-0000 FFFF),因此“嚴(yán)”的UTF-8編碼需要三個字節(jié),即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,從“嚴(yán)”的最后一個二進(jìn)制位開始,依次從后向前填入格式中的x,多出的位補0。這樣就得到了,“嚴(yán)”的UTF-8編碼是“11100100 10111000 10100101”,轉(zhuǎn)換成十六進(jìn)制就是E4B8A5。
//*-----------------------------------u2utf82gb.php--------------------------------------*//
<?php
function u2utf82gb($c){
$str="";
if ($c < 0x80) {
$str.=chr($c); //當(dāng)NRC編碼位于0000 0000-0000 007F區(qū)段時,UTF-8編碼轉(zhuǎn)換為0xxxxxxx
} else if ($c < 0x800) {
$str.=chr(0xC0 | $c>>6); //當(dāng)NRC編碼位于0000 0080-0000 07FF區(qū)段時,UTF-8編碼轉(zhuǎn)換為110xxxxx 10xxxxxx
$str.=chr(0x80 | $c & 0x3F);
} else if ($c < 0x10000) {
$str.=chr(0xE0 | $c>>12); //當(dāng)NRC編碼位于0000 0800-0000 FFFF區(qū)段時,UTF-8編碼轉(zhuǎn)換為1110xxxx 10xxxxxx 10xxxxxx
$str.=chr(0x80 | $c>>6 & 0x3F);
$str.=chr(0x80 | $c & 0x3F);
} else if ($c < 0x200000) {
$str.=chr(0xF0 | $c>>18); //當(dāng)NRC編碼位于0001 0000-0010 FFFF區(qū)段時,UTF-8編碼轉(zhuǎn)換為11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
$str.=chr(0x80 | $c>>12 & 0x3F);
$str.=chr(0x80 | $c>>6 & 0x3F);
$str.=chr(0x80 | $c & 0x3F);
}
return iconv('UTF-8', 'GB2312', $str);
}
?>
通過QR獲取借閱信息
<2014/7/25更新>今天靈(nao)機(can)一動想到一個新想法,能否利用當(dāng)前借閱最下邊的二維碼來獲取圖書的有關(guān)信息,于是用手機掃了一下二維碼,發(fā)現(xiàn)真的可以獲取圖書的借閱信息。

于是查看了一下源碼,找到了生成二維碼的的地址。
<img src="../opac/ajax_qr.php?qrcode=6K%2B76ICF44CQMzEyNTAwMjA3NuOAkeeahOWcqOWAn%2BS5puWIiijpopjlkI0v5bqU6L%2BY5pel5pyfKe%2B8mg0KTHVh56iL5bqP6K6%2B6K6hIDIwMTQtMDktMTQgICAgICAgIA0KUEhQ5a6e5L6L57K%2B6YCaIDIwMTQtMDktMTQgICAgICAgIA0KQXJkdWlub%2BS4gOivleWwseS4iuaJiy4y54mILi4gMjAxNC0wOS0xNCAgICAgICAgDQrkuK3lm73lhpnmhI%2FnlLvlhaXpl6jovbvmnb7lraYs56u55a2QLi4gMjAxNC0wOS0xNCAgICAgICAgDQpBbmRyb2lk54Ot6Zeo5bqU55So5byA5Y%2BR6K%2Bm6KejLi4gMjAxNC0wOS0xNCAgICAgICAgDQrkuK3lm73lhpnmhI%2FnlLvlhaXpl6jovbvmnb7lraYs6I2J5pys6Iqx5Y2JLi4gMjAxNC0wOS0xNCAgICAgICAgDQrlkI3lrrblm73nlLvor77loIIu6Iqx6bif56%2BHLi4gMjAxNC0wOS0xNCAgICAgICAgDQpBcmR1aW5v5oqA5pyv5YaF5bmVIDIwMTQtMDktMTQgICAgICAgIA0K55av54uCQW5kcm9pZOiusuS5iS4y54mILi4gMjAxNC0wOS0xNCAgICAgICAgDQpqUXVlcnnlvIDlj5HmioDmnK%2For6bop6MuLiAyMDE0LTA5LTE0ICAgICAgICANCg%3D%3D" border="0" /></a></span>
這個二維碼是由http://210.34.85.114:8080/opac/ajax_qr.php這個服務(wù)器生成的,后面的qrcode應(yīng)該是GB2312轉(zhuǎn)UTF-8后url編碼產(chǎn)生,這里不去管它。
由于直接利用PHP無法解析二維碼,所以調(diào)用http://zxing.org/w/decode.jspx這一個網(wǎng)頁服務(wù)來對二維碼解析。
用Fidder分析數(shù)據(jù)發(fā)送,該頁面是通過_GET方法http://zxing.org/w/decode?u=后接查詢圖片的url來傳遞數(shù)據(jù),這里的url是http://210.34.85.114:8080/opac/ajax_qr.php這個服務(wù)器生成的二維碼的地址。
GET http://zxing.org/w/decode?u=http%3A%2F%2F210.34.85.114%3A8080%2Fopac%2Fajax_qr.php%3Fqrcode%3D6K%252B76ICF44CQMzEyNTAwMjA3NuOAkeeahOWcqOWAn%252BS5puWIiijpopjlkI0v5bqU6L%252BY5pel5pyfKe%252B8mg0KTHVh56iL5bqP6K6%252B6K6hIDIwMTQtMDktMTQgICAgICAgIA0KUEhQ5a6e5L6L57K%252B6YCaIDIwMTQtMDktMTQgICAgICAgIA0KQXJkdWlub%252BS4gOivleWwseS4iuaJiy4y54mILi4gMjAxNC0wOS0xNCAgICAgICAgDQrkuK3lm73lhpnmhI%252FnlLvlhaXpl6jovbvmnb7lraYs56u55a2QLi4gMjAxNC0wOS0xNCAgICAgICAgDQpBbmRyb2lk54Ot6Zeo5bqU55So5byA5Y%252BR6K%252Bm6KejLi4gMjAxNC0wOS0xNCAgICAgICAgDQrkuK3lm73lhpnmhI%252FnlLvlhaXpl6jovbvmnb7lraYs6I2J5pys6Iqx5Y2JLi4gMjAxNC0wOS0xNCAgICAgICAgDQrlkI3lrrblm73nlLvor77loIIu6Iqx6bif56%252BHLi4gMjAxNC0wOS0xNCAgICAgICAgDQpBcmR1aW5v5oqA5pyv5YaF5bmVIDIwMTQtMDktMTQgICAgICAgIA0K55av54uCQW5kcm9pZOiusuS5iS4y54mILi4gMjAxNC0wOS0xNCAgICAgICAgDQpqUXVlcnnlvIDlj5HmioDmnK%252For6bop6MuLiAyMDE0LTA5LTE0ICAgICAgICANCg%253D%253D HTTP/1.1
Host: zxing.org
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1883.0 Safari/537.36
Referer: http://zxing.org/w/decode.jspx
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4
//*-----------------------------------qrcode.php--------------------------------------*//
<?php
function qrcode($src){
//切割html字符串獲取圖片url
preg_match_all('/<img\ssrc=\"[^\"]+\"/',$src,$qr);
//截取的""中間的url
preg_match_all('/\"[^\"]+/',$qr[0][0],$qrcode);
//除去開頭的 ..
$qrcode = preg_replace('/\.\./','',$qrcode[0][0]);
//除去開頭的 "
$qrcode = preg_replace('/\"/','',$qrcode);
//拼接url
$qrcode = 'http://210.34.85.114:8080'.$qrcode;
//url編碼
$qrcode = urlencode($qrcode);
//拼接查詢url
$url = 'http://zxing.org/w/decode?u='.$qrcode;
//獲取數(shù)據(jù)
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$infomation = curl_exec($curl);
curl_close($curl);
//獲取QRcode信息
preg_match_all('/讀者[^<]+/',$infomation,$info);
//UTF-8轉(zhuǎn)GB2312
$info = iconv('UTF-8','GB2312',$info[0][0]);
print_r($info);
}
?>