- 微信公眾平臺應用開發實戰(第2版)
- 鐘志勇 何威俊 馮煜博
- 1139字
- 2019-01-01 00:44:56
1.5 相關技術介紹
1.5.1 PHP
PHP是一種創建動態交互站點的強有力的服務器端腳本語言。PHP語法非常類似于Perl和C。PHP常常搭配Apache(web服務器)一起使用,不過它也支持ISAPI,并且可以運行于Windows的微軟IIS平臺。
PHP和其他的語言相比,最大的優勢是它集成了700多個內建的函數且有非常多的擴展,配合Apache服務器,使得它處理HTTP的請求非常方便。另一方面,它對MySQL的支持也非常好,有很多的訪問擴展庫。本書會使用一種比較輕量的訪問MySQL的擴展mysqli。接下來先介紹一下PHP的基本語法。由于本書的主題是微信公眾平臺的開發,所以不會詳細介紹PHP的語法。如果你有C、C++或者Java等其他語言的開發經驗,那么閱讀本書的PHP語法介紹之后就可以基本掌握PHP語法了。如果你沒有其他語言的開發經驗,建議你購買一本專門介紹PHP語法的書籍學習。當然如果你做過PHP的開發,那可以直接跳過本節。
1.PHP的基本語法
PHP的腳本塊以“<?php”開始,以“?>”結束。可以把PHP的腳本塊放置在文檔中的任何位置。當然,在支持簡寫的服務器上,可以使用“<?”和“?>”來開始和結束腳本塊。不過,為了達到最好的兼容性,推薦使用標準形式(<?php),而不是簡寫形式。下面的代碼就是PHP腳本的一個簡單應用,其實現的是打印一個簡單的字符串:hello world!。
<?php echo "hello world!"; ?>
右擊Test工程,在彈出的快捷菜單中選擇“New”選項,然后選擇“PHP File”選項,在彈出的“新建PHP文件”對話框的“File Name”文本框中鍵入“test.php”,單擊“Finish”按鈕。接著在新建的test.php文件里輸入以上代碼,并通過Ctrl+S快捷鍵保存,如圖1-22所示。

圖1-22 test.php
然后打開瀏覽器,在地址欄里輸入http://127.0.0.1/Test/test.php,瀏覽器中將顯示“hello world!”,如圖1-23所示。

圖1-23 test.php在google Chrome中的運行結果
test.php文件的創建和運行展示了最基本的使用Apache和zendstudio開發和測試PHP腳本的過程:
1)在zendstudio中創建文件,并編寫相應的代碼。
2)在瀏覽器中運行腳本,查看腳本輸出是否正確。如果代碼有語法錯誤或者出現了異常,瀏覽器會打印出語法錯誤提示和拋出的異常描述。
本書中的所有PHP代碼都是這樣編寫并調試的。
PHP的注釋和C語言的注釋是一致的,用“//”作為單行注釋的開始,用“/*”和“*/”包含多行注釋,如圖1-24所示。

圖1-24 單行注釋和多行注釋
2.PHP的變量
PHP中所有的變量都是以$符號開始的。PHP是一門松散類型的語言,在變量設置中不需要明確聲明該變量的數據類型。根據變量被設置的方式,PHP會自動把變量轉換為正確的數據類型。在C、C++和Java等強類型的語言中,必須在變量被使用前顯式聲明它的類型。另外,PHP的變量不需要提前聲明,在使用時會被自動聲明。在Test中新建一個文件,命名為test2.php,鍵入以下代碼:
<?php $a = 5; echo $a; echo "<BR>"; $b = "this is a string"; echo $b; echo "<BR>"; echo "$a, $b"; echo "<BR>"; echo '$a, $b'; ?>
上述代碼的分析如下:
?echo "<BR>"是打印一個網頁換行符。
?我們聲明了兩個變量—$a和$b,因為把$a設置成了5,所以PHP會自動把$a設置成整型變量;同樣的,會把$b設置成字符串變量。
?注意其中的echo "$a, $b"和echo '$a, $b',對應不同的輸出。在雙引號中變量會自動解析成它的值,而在單引號中,變量不會做任何轉義。這和Shell腳本是一致的。
在瀏覽器中執行http://127.0.0.1/Test/test2.php,結果如圖1-25所示。

圖1-25 test2.php的執行結果
PHP中有一個非常簡便的連接操作符:.(一個英文的句號)。它可以連接字符串,當操作數中有非字符串時,會先轉換成字符串,然后再做字符串連接操作。繼續上面的例子,我們在上面代碼的末尾加入以下代碼:
<?php echo "<BR>"; echo $a . $b; echo "<BR>"; echo $a . $a; ?>
在瀏覽器中執行修改后的代碼,結果如1-26所示。

圖1-26 連接操作符的結果
可以看到其他$a和$b的連接形成了“5this is a string”,$a先轉成了一個字符串再和$b做連接操作。在語句$a . $a中,連接操作符兩邊的$a都被轉成了字符串再做連接操作,于是得到結果“55”。
3.PHP的運算符
PHP的運算符包括算術運算符、賦值運算符、比較運算符和邏輯運算符。這些運算符的定義和C、C++和Java中的都是一樣的,本書不做詳細介紹,下面以表格的方式列出這些運算符的定義。
?算術運算符,其具體定義如表1-1所示。
表1-1 算術運算符
?賦值運算符,其具體定義如表1-2所示。
表1-2 賦值運算符
?比較運算符,其具體定義如表1-3所示。
表1-3 比較運算符
?邏輯運算符,其具體定義如表1-4所示。
表1-4 邏輯運算符
4.PHP數組
PHP的數組和其他語言的有很大的不同,這也是PHP語言的特色之一。PHP有三種類型的數組:數值數組、關聯數組和多維數組。
(1)數值數組
數值數組存儲的每一個元素都帶有一個數值ID鍵,這和C、C++、Java中的數組是一樣的。可以使用不同的方式來創建數值數組,例如下面這種定義方式:
<?php $animal = array("dog","cat","sheep"); ?>
這種以定義一個array的方式創建的數組,系統會自動為數組中的每個值分配一個從0開始的鍵值。它等同于下面的方式:
<?php $animal[0] = "dog"; $animal[1] = "cat"; $animal[2] = "sheep"; ?>
下面我們測試一下采用上面這種方式新建的數組,建立新的測試文件或者刪除test2.php文件中的代碼,輸入下面的代碼:
<?php $animal[0] = "dog"; $animal[1] = "cat"; $animal[2] = "sheep"; echo $animal[0].",".$animal[1]."and".$anima[2]."are animals!" ?>
在瀏覽器中測試,結果如圖1-27所示。

圖1-27 數組測試結果
可以把數組的定義方式換成使用array的方式,得到的結果是一樣的。需要注意的一點是數組中各個元素的類型不需要一樣。可以定義以下的數組:
<?php $arr = array("string", 5, 1); ?>
這是PHP語言和其他語言(C/C++/Java)相比最大的不同之處。
(2)關聯數組
和數值數組不同,關聯數組的key可以為整型或者字符串。和數值數組一樣,關聯數組也有兩種定義方式。下面展示的是第一種方式:
<?php $animal = array( 'dog' => 23, 'cat' => 26, 'sheep' => 35 ); ?>
下面第二種方式:
<?php $animal['dog'] = 23; $animal['cat'] = 26; $animal['sheep'] = 35; ?>
這和C++的STL的map容器類似。但是它比map容器更靈活,因為STL的map在聲明的時候就規定好了key的類型和value的類型,PHP的關聯數組中每個key和每個value的類型都可以不一樣。以下的定義方式是合法的:
<?php $animal = array( 'dog' => 23, 'cat' => 26, 'sheep' => 35, 1 => 45, 0 => 47 ); ?>
這和下面的定義是一致的:
<?php $animal['dog'] = 23; $animal['cat'] = 26; $animal['sheep'] = 35; $animal[1] = 45; $animal[0] = 47; ?>
(3)多維數組
在多維數組中,如果主數組是一個數值數組,那么它的元素還可以是一個數組(關聯數組或者數值數組),如下面的代碼所示:
<?php $arr = array( array(1,2,3), array( "cat" => 10, "dog" => 21, "sheep" => 46 ) ); ?>
如果主數組是一個關聯數組,那么它的value可以是一個數組(關聯數組或者數值數組),如以下代碼所示:
<?php $arr = array( "cat" =>array(1,2,3), "dog" =>array( "cat" => 45, "dog" => 23 ) ); ?>
PHP的數組是PHP中最靈活的數據類型,可以任意組合各種數據類型,下面的數組也是合法的:
<?php $arr = array( 'hello', 'cat' => array('hello', 'world'), 'dog' => 1, 'sheep' ); ?>
PHP會為沒有key的元素自動分配一個從0開始的key值,上面代碼中創建的數組中的元素'hello'的key為0,'sheep'的key為1。為了證實這個結論,我們先引入兩個PHP的內建函數var_dump和var_export。
5.常用函數
(1)var_dump和var_export
var_dump可以把變量以字符串形式打印出來,而var_export可以把變量以字符串形式打印出來或者返回。先看下面的代碼:
<?php $arr = array( 'hello', 'cat' => array('hello', 'world'), 'dog' => 1, 'sheep' ); var_dump($arr); ?>
執行結果如圖1-28所示。

圖1-28 var_dump測試結果
仔細查看圖1-28中的輸出,最開始的“array(4)”,表明var_dump函數的入參“$srr”是一個大小為4的數組(數組第一維的長度為4)。接下來的一個花括號包含的是這個數組的說明,數組的每一個元素的key都在一個中括號中,然后每個元素的value是由類型和它的值組成的。仔細觀察數組中每個元素的下標:第一個元素“hello”的下標為0,最后一個元素“sheep”的下標為1;其他的元素的下標都是我們在程序中指定的。這證實了我們的結論:對沒有設定下標的元素,PHP會自動為它們設定從0開始的下標。
var_export函數和var_dump類似,不同之處是它接受第二個參數:一個bool值(true/false)。當var_export不傳入第二個參數的時候,它輸出變量的字符串表示的是和var_dump的類似(此時第二個參數的為默認值false)的。當設定第二個參數為true時,它會把變量的字符串當作返回值返回,而不是直接輸出。看下面的例子:
<?php $arr = array( 'hello', 'cat' => array('hello', 'world'), 'dog' => 1, 'sheep' ); $ret = var_export($arr, true); echo "var_export result: " . $ret ; ?>
執行結果如圖1-29所示。

圖1-29 var_export的輸出
仔細觀察var_export的輸出會發現,和var_dump的輸出不同之處是它不輸出類型信息。但是這些類型信息基本上可以一眼看出。
var_dump和var_export這兩個函數給調試代碼帶來了非常大的方便。有了這兩個函數可以在需要查看復雜變量值的時候,加入類似上面例子中的代碼。可能學過Java、使用過Eclipse的人更傾向于使用zendstudio內建的調試功能,因為zendstuio也是基于Eclipse開發的。我們不評論這兩種方法的優劣,只談偏好吧。筆者覺得通過寫日志的方式來查看程序邏輯可能存在的錯誤是最合適的,因為它可以真實地反映代碼執行的先后順序。另外PHP是一種腳本語言,不需要編譯即可執行,這樣在修改完代碼后到執行之間不需要花很多時間來編譯。根據筆者多年的PHP開發經驗,使用這種寫日志的方式來排錯是非常高效的。既然談到寫日志,下面介紹一個最簡單的寫日志的函數file_put_contents。
(2)file_put_contents
file_put_contents是一個可以寫字符串到文件的函數,有四個入參,但我們只要關心前三個。第一個入參是表示文件地址的字符串;第二個是需要寫入的字符串;第三個是寫入的模式,我們一般用宏定義FILE_APPEND,表示追加寫入。看下面的例子。
<?php file_put_contents("C:\\AppServ\\tmp.txt", "start\n", FILE_APPEND); $arr = array( 'hello', 'cat' => array('hello', 'world'), 'dog' => 1, 'sheep' ); $ret = var_export($arr, true); file_put_contents("C:\\AppServ\\tmp.txt","var_export result:".$ret."\n",FILE_APPEND); file_put_contents("C:\\AppServ\\tmp.txt", "end\n", FILE_APPEND); ?>
執行這段代碼,然后打開文件tmp.txt,查看file_put_contents輸出,如圖1-30所示。

圖1-30 file_put_contents輸出
我們在執行這段之前并沒有手工建立tmp.txt文件,這說明file_put_contents在沒有文件的情況下會自動創建文件。另外var_export的輸出和在Chrome里輸出的不一樣,文件里的格式更好看,因為對齊了。這是因為var_export是用ASCII碼中的\t和來做對齊處理的,但是這些字符串的意義在瀏覽器中是不能正常解析的,但是在文本處理器editplus中可以正常解析。
PHP的基本語法就介紹到這里,它的其他的特性和其他語言相差不大,在后面介紹其他預備知識和具體使用到的時候再介紹。
介紹到這里,我有一些經驗和讀者分享。學習一門語言不能上來就使用一本很厚的書,這樣花很長時間看完書,接受了太多的信息,反而不知道從何處下手。從最基本最簡單的開始,邊用邊學新的特性,這樣會學得更扎實、更實用。在使用一段時間后再通讀一下大部頭的名著,才會真正吸收里面的內容,使自己對這門語言有全面的了解,讓自己有實質性的提高。
1.5.2 HTTP
HTTP(HyperText Transport Protocol)即超文本傳輸協議,它詳細規定了瀏覽器和萬維網服務器之間互相通信的規則,是通過因特網傳送萬維網文檔的數據傳送協議。Rfc2612(http://www.ietf.org/rfc/rfc2616.txt)使用了176頁的“天書”來描述這個協議。微信后臺在向我們的公眾平臺服務器發消息的時候(圖1-1中的第2步)使用的就是HTTP協議。看起來我們好像遇到了大麻煩,幸運的是我們并不需要看完這些文檔才能開始使用它。在使用PHP來做HTTP的服務端的時候,Apache為我們解析好了大部分的協議,并提供了非常方便的方法以供我們獲取需要的信息。其中,我們需要關心的是兩個全局變量$_GET和$HTTP_RAW_ POST_DATA。Apache解析好請求中的HTTP協議,把請求中get數據和post變量寫入$_GET和$HTTP_RAW_POST_DATA變量中。我們只要直接使用$_GET和$HTTP_RAW_POST_DATA就能取到微信后臺傳給我們的數據。
筆者在meiri10futu的部署機器上運行tcpdump抓包,圖1-31是抓到并用wireshark分析的一個完整的請求和返回包。

圖1-31 公眾平臺服務器的HTTP請求和返回包
圖1-31所示的數據中,“HTTP/1.1 200 OK”之前的部分是微信后臺發給公眾賬號服務器的請求(圖1-1中的第2步),之后的部分是公眾賬號服務器返回給微信后臺的數據。我們現在重點關注請求部分,先把這部分數據以文本形式粘貼到下面:
POST /interface.php?signature=771f6bd01508e46b02061b0a1330a6ad67e1ad77&time stamp=1364458805&nonce=1364226029 HTTP/1.0 User-Agent: Mozilla/4.0 Accept: */* Host: 42.96.142.129 Content-Type: text/xml Content-Length: 276 Pragma: no-cache Connection: Keep-Alive <xml><ToUserName><![CDATA[gh_a8b0ebbe91f5]]></ToUserName> <FromUserName><![CDATA[owI97jpNpdfSpOsR9kG97g_wRtvY]]></FromUserName> <CreateTime>1364458805</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[...]]></Content> <MsgId>5860305944314258860</MsgId> </xml>
請求分為頭部(head)和正文(body)兩部分,數據之間用一個空行分割(實際上是兩個“\r\n”),即上面的“Keep-Alive”下面的空行之后的數據為body,之前的部分為head。接下來我們來看GET數據和POST數據在哪里。
(1)HTTP請求中的GET數據
注意上面的請求數據中的第一行中如下的數據:
signature=771f6bd01508e46b02061b0a1330a6ad67e1ad77×tamp=136445880 5&nonce=1364226029
這些用“&”分隔的字符串就是GET數據,我們把用“&”分割之后的字符串列出來:
?signature=771f6bd01508e46b02061b0a1330a6ad67e1ad77 ?timestamp=1364458805 ?nonce=1364226029
這樣看起來就非常清楚了,等號左邊是GET數據的key,右邊是GET數據的value,具體如何在PHP程序中獲取這些GET數據,等講完POST數據之后會有一個統一的例子。
(2)HTTP請求中POST數據
上面請求中的body部分就是POST數據,POST數據和GET數據不同,它不會有key值。POST數據一般都比較大,GET數據往往比較小。下面的程序展示了如何獲取GET數據和POST數據。我們把test2.php的內容改成如下形式:
<?php file_put_contents("C:\\AppServ\\tmp.txt", var_export($_GET, true), FILE_APPEND); file_put_contents("C:\\AppServ\\tmp.txt", "\n", FILE_APPEND); file_put_contents("C:\\AppServ\\tmp.txt", var_export($HTTP_RAW_POST_DATA, true), FILE_APPEND); ?>
然后我們使用Fiddler的Request Bilder向test2.php發一個POST請求,請求中帶的GET數據及POST數據和上面的示例一樣,如圖1-32所示。

圖1-32 用Fiddler向test2.php發POST請求
然后查看tmp.txt中的輸出,如圖1-33所示。

圖1-33 GET和POST數據在文本中的輸出
注意 在Fiddler中輸入GET數據時不是在Request Header輸入框中輸入,而是在請求URL后先輸入一個問號,然后輸入所有的GET字符串。
可以看到,$_GET是一個數組;key是各個GET數據的key;$HTTP_RAW_ POST_DATA是一個字符串,包含body的所有內容。在設置這些變量的同時,Apache還為我們設置了一個$_POST變量,它是用來存前臺HTML的form表達提交的數據,本書使用不到。大家不要誤以為$_POST變量是我們想要的POST數據,一定要區分開。
注意 我們在這里沒有使用editplus來打開tmp.txt,而是用的寫字板。如果你試了用editplus打開的話會發現,腳本中我們特意輸出和var_export自動輸出的“\n”都沒有當成換行符來顯示,使得格式很難看。這是因為當文件中既有“\r\n”又有“\n”時,editplus會自動選擇其中的一種作為換行符,而忽略其他的方式。在打開tmp.txt時editplus就選擇了HTTP的body中的“\r”作為換行符而忽略了“\n”。
在這一小節中我們用到了三個非常有用的工具:
1)tcpdump是一個Linux上的抓包命令,有非常多的選項和表達式。可以結合自己的需求,使用相應的選項和表達式來抓取需要的網絡包。
2)wireshark是一個Windows上的抓包工具。它的功能和tcpdump是一樣的,但是它的優點在于其圖形化界面,對數據包的可視化做得非常好,同時也能打開tcpdump的數據包文件。我就喜歡用tcpdump在Linux機器上抓包之后再到Windows上用wireshark打開來分析。
3)fiddler是一個非常強大的HTTP調試代理,它能夠記錄并檢查所有你的電腦和互聯網之間的HTTP通信,設置斷點,查看fiddle中所有“進出”的數據(指cookie、HTML,JS,CSS等文件,這些都可以讓你胡亂修改)。我們這里使用它來代替Chrome瀏覽器構造請求包,因為Chrome瀏覽器不能讓我們靈活地自定義GET數據和POST數據。請讀者到fiddler的官網(http://www.fiddler2.com/ fiddler2/)下載fiddler并安裝好,稍后還會用到它。
使用好這些工具對于自己的工作和學習有非常大的幫助。有興趣的讀者可以到網絡上搜索這些工具的高級教程。
HTTP協議相關的內容非常多,本書中需要用到的就只有這些了。讀者如果有興趣的話可以專門找一些介紹HTTP協議的資料進行學習,或者認真閱讀一下rfc2612。
1.5.3 XML
XML(Extensible Markup Language)是一種可擴展的標記語言,可以用來標記數據、定義數據類型,是一種允許用戶對自己的標記語言進行定義的源語言。關于它的完整的、標準的描述,可以參看w3c的官方文檔http://www.w3.org/ TR/REC-xml/。之所以這里要講這種語言,是因為微信后臺發給我們的公眾賬號服務器的POST數據就是用這種語言描述的。上一小節中的$HTTP_RAW_POST_ DATA就是XML描述的數據。似乎我們又遇到了大麻煩,不過很幸運的是,我們不需要關注XML語言的太多細節,只要知道如何用PHP解析它就可以了。
XML的語法的基本模式是:分別用“<itemName>”和“</itemName>”來表示一個條目的開始和結束,“itemName”可以是任意字符。每個條目也可以有屬性,在開始的<itemName attrName1=“1”attrName2=“2” >中表示,微信后臺給我們發的XML沒有屬性字段。條目的值可以是數字和字符串,也可以是一個或者多個條目,也就是可以嵌套。字符串用“<![CDATA[text]]>”表示,其中text可以是任意字符串。用CDATA包起來的目的是讓text中的內容不會解析成別的條目,只會解析成字符串。整個XML文檔必須要有一個根條目,該條目可以是任意名字。微信后臺的信息中的根條目是以“<xml>”開始,以“</xml>”結束的。仔細觀察圖1-33所示的POST數據,整個XML文檔有6個條目,都沒有嵌套。第一個條目是ToUserName,它是一個字符串,值為“gh_a8b0ebbe91f5”;第三個條目是CreateTime,它是一個整型變量,值是1364458805。其他四個條目也都類似。
PHP為我們提供了一個很簡單的函數來解析XML—simplexml_load_string。它接受五個參數,第一個是需要解析的XML字符串,其他四個參數都是可選的。在解析成功的時候會返回一個SimpleXMLElement的對象,如果解析失敗則返回false。一般在入參中傳入的XML數據不符合規范的時候才會解析失敗進而返回false。代碼清單1-1所示的例子展示了如何使用simplexml_load_string來解析XML。這個例子繼續上一節,我們用simplexml_load_string來解析$HTTP_RAW_ POST_DATA,并輸出解析后的數據。
代碼清單1-1
<?php $postXmlStr = $HTTP_RAW_POST_DATA; $xmlObj = simplexml_load_string($postXmlStr); if(false === $xmlObj) { echo "parse xml string error! \n"; exit(0); } $toUser = $xmlObj->ToUserName; echo "to User: " . $toUser . "\n"; $fromUser = $xmlObj->FromUserName; echo "from User: " . $fromUser . "\n"; $createTime = $xmlObj->CreateTime; echo "create time: " . $createTime . "\n"; $msgType = $xmlObj->MsgType; echo "msg type: " . $msgType . "\n"; $content = $xmlObj->Content; echo "content: " . $content . "\n"; $msgId = $xmlObj->MsgId; echo "msg id: " . $msgId . "\n"; ?>
重新按照上一節的方法,用fiddler向test2.php發送請求,然后單擊選中fiddler左邊的請求列表中對應到這次請求的條目,雙擊,在右側會顯示請求的詳細返回信息,如圖1-34所示。

圖1-34 fiddler中的請求test2.php的結果
可以在圖1-34所示界面右下側的TextView中看到我們在程序中echo的輸出。可以看到我們是通過對象$xmlObj的成員變量來訪問XML的條目的,引用成員的方式和C++中通過對象指針訪問它的public成員變量是一樣的。PHP的對象在本書后面的實例中會用到。限于篇幅,這里不過多介紹,讀者可以查閱其他資料做更多的了解。
注意 在代碼清單1-1中判斷simplexml_load_string的結果是否為false使用的是三個等于號“===”。這是PHP的“全等于”符號,只有當全等號左邊和右邊的表達式的大小和類型完全相等時才返回true。雖然PHP是弱類型語言,但并不表示變量沒有類型。兩個等于號(“==”)只能判斷兩邊的值是否相等。在兩個等于號的情況下:false、空字符串、空數組、0都是相等的。但是使用全等號的判斷可以把它們區分開,因為它們的類型不相同。
1.5.4 MySQL
MySQL是開源的關系型數據庫,我們介紹它是因為在后面的案例中,需要存儲用戶信息的時候會用到它。相信很多人在學習數據庫的時候都學過SQL Server,MySQL和它類似,都支持數據存儲和SQL語句查詢。和SQL Server相比,MySQL顯得更輕便簡潔,并且移植性更好。對于MySQL來說,Windows的版本和Linux的版本使用方法完全一樣。
Java和.NET等語言在訪問數據庫的時候通常都是通過一些封裝好的db connector或者driver實現的,PHP也一樣。PHP訪問MySQL的封裝庫有三種連接方式:ext/mysqli、PDO_MySql和ext/mysql。ext/mysqli是ext/mysql的增強版(i代表improved),并且ext/mysql已經不再做升級了,因此不推薦使用ext/mysql。表1-5詳細比較了這三種連接MySQL封裝庫方式的異同。
表1-5 MySQL的三種PHP連接方式的異同
本書中使用ext/mysqli來訪問MySQL,下面就描述一下如何使用ext/mysqli。ext/mysqli的每個函數都包含一個面向對象風格的函數和一個過程化風格函數。這以過程化風格的函數為例進行講解。連接并發起對MySQL數據庫的查詢,一般有以下幾個步驟:
1)使用mysqli_init初始化ext/mysqli,這個函數會返回一個ext/mysqli資源,用來做下一個函數的入參。
2)使用mysqli_real_connect打開一個對MySQL服務器的連接,這個函數需要MySQL服務器的地址、端口、數據庫名、用戶名和密碼。
3)使用mysqli_query進行查詢SQL語句的操作。
4)如果上一步中的返回結果是一個數據集(select操作的返回),可使用mysqli_fetch_array獲取返回結果集。這個函數有兩個參數:第一個參數用于表示mysqli_query的返回數據集;第二個參數用于描述mysqli_fetch_array的返回是關聯數組(MYSQLI_ASSOC)、數值數組(MYSQLI_NUM)或者兩種都返回(MYSQLI_BOTH),兩種都返回是默認方式,不過我們這里使用第一種方式,只返回關聯數組。
5)使用mysqli_close關閉和數據庫的連接,這個步驟可以省略,因為PHP在腳本執行完畢的時候會釋放并關閉所有的fd,其中也包括對數據庫的連接。
我們首先創建用來測試的數據庫和數據表。登錄phpMyAdmin,然后創建一個名為test2的數據庫(MySQL默認會生成一個名為test的數據庫),如圖1-35所示。

圖1-35 使用phpMyAdmin創建test2數據庫
數據庫創建完成后會進入數據庫test2的管理界面。在管理界面中選擇名為SQL的tab,在輸入框中輸入建表語句,如圖1-36所示。

圖1-36 使用phpMyadmin創建表test
可以看到使用phpMyAdmin管理MySQL數據庫非常方便,現在已經有了數據庫和數據表,我們在zendstudio中把test.php的代碼替換成以下形式:
<?php $conn = mysqli_init(); if(!$conn) { echo "mysqli_init error !"; exit(0); } $ret = mysqli_real_connect($conn, "localhost", "root", "root", "test2", 3306, "test", MYSQLI_CLIENT_FOUND_ROWS); if(!$ret) { echo "mysqli_real_connect error!"; exit(0); } //插入記錄 $sql = 'insert into test values(1, "tom" )'; $ret = mysqli_query($conn, $sql); if(!$ret) { echo "mysqli_query error!"; exit(0); } //查詢記錄 $sql = 'select * from test'; $ret = mysqli_query($conn, $sql); //獲取查詢結果 while (($row = mysqli_fetch_array($ret, MYSQLI_ASSOC)) != NULL) { echo "id: " . $row['id'] . "<BR>"; echo "name: " . $row['name'] . "<BR>"; } ?>
在Chrome中執行上面的程序,結果如圖1-37所示。

圖1-37 數據庫操作示例的執行結果
我們在程序的最后并沒有調用mysqli_close,這也是大部分的腳本的做法。當然如果你堅持認為這樣不好,并一定要加上它,那也是沒有問題的。
1.5.5 HTML5
HTML5在微信公眾平臺推出以后又火了一把。“微信的入口夢應由HTML5承載”,“微信創業猜想:社交游戲將引爆微信HTML5游戲”,在百度上用關鍵字“微信”和“HTML5”搜索,立即可以看到很多類似標題的文章。2010年2月,喬布斯極力推崇用HTML5代替flash,并且指出了flash的很多問題和HTML5的很多優點,這讓HTML5瞬間到了風口浪尖。后來Adobe公司自己也放棄繼續開發flash的移動版本,這更加讓人堅信HTML5將會大面積普及。隨后發生的一件事讓大家對HTML5又重新冷靜地思考了一把:Facebook的HTML5的移動版本因為性能問題被原生版本代替。現在微信公眾平臺的誕生又讓大家把目光聚集到了HTML5上。新技術出現的時候,IT圈的新聞總是讓人很糾結。到底HTML5前途怎么樣,估計沒有人能夠看得清。在這種情況下,腳踏實地地做一些事情會是好的選擇。如果大家想嘗試在微信上開發HTML5的應用,可以看一下接下來對HTML5的介紹。
HTML5是用于取代1999年所制定的HTML 4.01和XHTML 1.0 標準的HTML標準版本,現在仍處于發展階段,但大部分瀏覽器已經支持某些 HTML5技術。簡單地說,HTML5其實是HTML4的一個更高級的版本,并不是一個完全的新技術。往往人們提到HTML5時還包括CSS的新版本CSS3,以及相關的JavaScript。通過這一整套的技術,在瀏覽器上可以實現復雜的富界面應用。HTML5在頁面上表現能力一點兒也不遜于PC原生的應用。而在HTML4上實現這些應用往往要一些其他的插件的支持,如Adobe Flash、Microsoft Silverlight、Oracle JavaFX等。
目前大部分的瀏覽器都支持HTML5,包括國外的Firefox(火狐瀏覽器)、IE9及其更高版本、Chrome(谷歌瀏覽器)、Safari、Opera等,及國內的傲游瀏覽器(Maxthon)、基于IE或Chromium(Chrome的工程版或稱實驗版)所推出的360瀏覽器、搜狗瀏覽器、QQ瀏覽器、獵豹瀏覽器等。需要注意的是,這些瀏覽器稍早的版本都不支持HTML5,特別是IE,而國內的大部分用戶都是使用IE的低版本來瀏覽網頁的,在實際設計產品的時候需要特別注意這一點。
微信是一個手機上的應用,沒有PC版本。因此我們更關心的是移動端是否支持HTML5。好消息是無論是IOS還是Android都對HTML5有很好的支持。壞消息是HTML5目前還存在性能問題,由于手機處理能力和PC相比還有差距,所以大規模的HTML5應用在手機端運行還是會有問題的。不過可以肯定的是,手機的處理能力在不斷地、快速地提升,如今四核的手機已經很常見了,所以也許在不久的將來,大規模的HTML5應用在手機端的運行將不再有問題。
相比HTML4,HTML5有以下的一些新的特性:
?語義特性,HTML5賦予網頁更好的意義和結構。隨著HTML5對RDFa的微數據與微格式等方面的支持,其所支持的標簽將更加豐富,其將可構建對程序、對用戶都更有價值的數據驅動的Web。HTML5提供了更多的標簽,表1-6是這些新增標簽的簡介。
表1-6 HTML5新增標簽
?本地存儲特性。基于HTML5開發的網頁APP擁有更短的啟動時間、更快的聯網速度,這些全得益于HTML5 APP Cache,以及本地存儲功能。
?設備兼容特性。自從Geolocation功能的API文檔公開以來,HTML5為網頁應用開發者們提供了更多功能上的優化選擇,帶來了更多體驗功能的優勢。HTML5提供了前所未有的數據與應用接入開放接口,使外部應用可以直接與瀏覽器內部的數據直接相連,例如視頻影音可直接與microphones及攝像頭相連。
?連接特性。更有效的連接工作效率,使得基于頁面的實時聊天、更快速的網頁游戲體驗、更完美的在線交流得到了實現。HTML5擁有更有效的服務器推送技術,Server-Sent Event和WebSockets就是其中的兩個特性,這兩個特性能夠幫助我們實現服務器將數據“推送”到客戶端的功能。服務端推送技術一直是Web端服務的難題。現有的技術有基于長連接的COMET、內嵌flash、基于ajax的長輪詢,這些都有各自的缺點,不是HTML原生支持的。
?網頁多媒體特性。支持網頁端的Audio、Video等多媒體功能,與網站自帶的APPS、攝像頭、影音等功能相得益彰。
?三維圖形及特效特性。基于SVG、Canvas、WebGL及CSS3的3D功能,用戶會驚嘆于在瀏覽器中所呈現的視覺效果。
?性能與集成特性。沒有用戶會永遠等待你的Loading—HTML5會通過 XMLHttpRequest2等技術,幫助您的Web應用和網站在多樣化的環境中更快速地工作。
?CSS3特性。在不犧牲性能和語義結構的前提下,CSS3中提供了更多的風格和更強的效果。此外,較之以前的Web版本,HTML5的開放字體格式(WOFF)也提供了更高的靈活性和控制性。
在這些特性中,最受關注的是其中的三維圖形的特性,也就是HTML5提供的<canvas>標簽。HTML的其他標簽就像一個一個的圖形,我們可以自定義圖標的顏色、大小以及單擊它之后的響應,然后把它“貼”到網頁上。而這個<canvas>標簽就像是給了我們一個畫板,在網頁上給了我們一塊區域,可以讓我們在上面直接畫出任何我們需要的形狀,并且可以響應我們的輸入。下面給出一個非常簡單的示例,這個示例實現的是使用canvas在網頁上畫一個紅色的圓形。新建一個PHP文件,輸入以下的代碼:
<html> <body> <canvas id="myCanvas" width="200" height="100" style="border:1px solid #c3c3c3;"> Your browser does not support the canvas element. </canvas> <script type="text/javascript"> var c=document.getElementById("myCanvas"); var cxt=c.getContext("2d"); cxt.fillStyle="#FF0000"; cxt.beginPath(); cxt.arc(70,18,15,0,Math.PI*2,true); cxt.closePath(); cxt.fill(); </script> </body> </html>
在Chrome中執行上述PHP文件,結果如圖1-38所示。
仔細觀察上面JavaScript代碼中對變量cxt的使用,會發現這些函數調用方式和openGL的一些基本函數很像。Canvas給了瀏覽器畫圖的能力,提供了圖形學的一些基本函數,基于這些基本函數,開發者可以開發出復雜的二維、三維的應用。
HTML5的內容非常多,這里沒有辦法面面俱到,我們只能給出一個簡單的介紹,有興趣的讀者可以找相關的資料深入學習。

圖1-38 使用canvas畫一個紅色圓