微信公众平台应用开发实战
上QQ阅读APP看书,第一时间看更新

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_dumpvar_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&timestamp=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画一个红色圆