微信公眾平臺圖書館查詢開發(fā)記錄

摘要:這篇文章記錄圖書館查詢微信公眾平臺開發(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é)果如下:

識別結(jié)果
識別結(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)真的可以獲取圖書的借閱信息。

掃描結(jié)果
掃描結(jié)果

于是查看了一下源碼,找到了生成二維碼的的地址。

    <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);
    }
?>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 編碼問題一直困擾著開發(fā)人員,尤其在 Java 中更加明顯,因為 Java 是跨平臺語言,不同平臺之間編碼之間的切換...
    x360閱讀 2,582評論 1 20
  • 可以看我的博客 lmwen.top 或者訂閱我的公眾號 簡介有稍微接觸python的人就會知道,python中...
    ayuLiao閱讀 3,400評論 1 5
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,323評論 25 708
  • 01 海邊有城。 我住在那城里。 父親為我取名林安平。 這年,住在我樓上的林家辰八歲,而我七歲。 這天,我們坐在屋...
    易安閱讀 566評論 0 1
  • 文/冬月之戀 艾潔躺在病床上,氣若游絲,她五十一歲的生命即將走到盡頭。她在醫(yī)院里與病魔搏斗了兩個多月,醫(yī)生對她丈夫...
    冬月之戀閱讀 1,000評論 1 41

友情鏈接更多精彩內(nèi)容