分类:
2008-05-29 22:30:00
对前一部分的回顾
在我们往下继续之前,回顾一下我们学习的目的应该是件有价值的事。现在有我们的系统中有了两个强有力的新的工具:脚本语言PHP和数据库引擎MySQL。搞清楚两者是如果协同工作是很重要的。
数据库驱动的网站的实质就是允许站点的内容存在于一个数据库中,并且可以通过这个数据库来动态地产生Web页面来让我们的访问者通过标准的Web浏览器来显示它。所以在你的系统的一端是一个访问你的站点的浏览者,他通过访问HTTP://WWW.YOURSITE.COM来获得一个标准的HTML格式的Web页面并在Web浏览器中显示它。在你的系统的另一端是通过一个或几个数据表存储在一个只理解如何响应SQL查询(命令)的MySQL数据库中的你的站点的内容。
PHP脚本语言承担了两者之间的联络员的角色,使用PHP,你可以编写一个标准HTML的“模板”,这个“模板”决定了你的站点的外观(包括图画和页面设计)。这时内容是属于这个“模板”的,你可以使用一些PHP代码来连接MySQL数据库并且使用SQL查询来获得数据并在其相应位置显示它,这里的SQL查询是和我们在第二章中用来建立笑话数据表时一样的。
现在对于访问者在访问你的数据库驱动的网站的一个页面时,到底会发生什么事,你应该有个明确的认识了:
访问者的Web浏览器使用一个标准的URL请求这个页面。
Web服务器软件(Apache、IIS或其他)认定被请求的页面是一个PHP脚本,因而在响应这个页面请求之前用它的PHP插件来解释它。
一些PHP命令(我们还没学到)会连接MySQL数据库并向数据库请求属于这个Web页面的内容。
MySQL数据库作出响应并且向PHP脚本发出被请求的内容。
PHP脚本将内容存储到一个或几个PHP变量中,并使用我们熟悉的echo函数将其作为Web页面的一部分输出。
PHP插件完成处理并将生成的HTML副本返回到Web服务器。
Web服务器将这个HTML副本发送到Web浏览器,这将是一个标准的HTML文件,只不过它不是直接来自于一个HTML文件,而是来自于PHP插件提供的输出。
用PHP连接MySQL
在我们从我们的MySQL数据库中获取我们的Web页面所包含的内容之前,我们首先必须知道如何建立与MySQL的连接。在第二章中,我们使用了一个叫mysql的程序来做这样的连接。PHP不需要这样的一个程序,对连接MySQL的支持是语言内置的。下面的这个函数用来建立这样的连接:
mysql_connect ( , |
在这里,
是MySQL服务软件在其上运行的计算机的IP地址或主机名(如果这与运行Web服务软件的计算机是同一台,你可以使用"localhost"),你可能还记得PHP中的函数在被调用时往往会返回(输出)一个值。请不要担心我们没有提醒你,我们在最初接触一个函数时都会为你详细详细它。绝大多数的函数在被调用后,都会返回一个可以在存储在变量中的值以备下次使用。例如我们上面介绍的mysql_connect函数,会返回一个数字来标识已经建立的连接。因为我们会要使用这个连接,所以我们必须保存这个值。下面是一个关于如何连接我们的MySQL数据库的一个实例:
$dbcnx = mysql_connect ( "localhost", "root", "mypassword" ); |
需要说明的是,对于你的MySQL服务器,上面这个函数中的三个参数的值可能是不同的。你应该注意到在这儿我们的mysql_connect 返回了一个值(我们称之为一个连接标识),这个值被我们存储在变量$dbcnx中。
因为MySQL是一个完全分布式的软件,我们必须考虑到这些可能性:服务不可用、网络堵塞或者是我们的用户名及口令不匹配。在这些情况下,mysql_connect函数不能返回一个连接标识(因为连接未被建立)。这时,会返回一个逻辑假。这使得我们可以用一个if语句来处理连接的情况:
$dbcnx = @mysql_connect( "localhost", "root", "mypassword" ); if ( !$dbcnx ) { echo ( " Unable to connect to the database server at this time. " );exit (); } |
在上面的代码段中出现了三个新的东西,首先,我们在mysql_connect函数前加了一个@符号。包括mysql_connect在内的许多函数会在失败后显示难看的错误信息。在函数名前加一个@符号可以告诉这个函数当执行失败时,允许我们显示我们自己友好的出错信息。
其次,在我们的if语句的条件中,$dbcnx变量前面加了一个惊叹号。这个惊叹号是PHP中的“否运算符”。也就是说将逻辑真变为逻辑假,将逻辑假变为逻辑真。这样,如果这个连接是失败的,mysql_connect会返回一个逻辑假,!$dbcnx将等于逻辑真,这样我们的if语句将被执行。相反,如果这个连接是成功的,存储在$dbcnx中的连接标识将等于逻辑真(在PHP中,任何非零的数字都被认为是逻辑真),所以!$dbcnx会等于逻辑假,if语句将不会被执行。
最后一个是exit函数,这是我们遇到的第一个没有参数的函数。这个函数的全部作用就是导致PHP停止对本页的阅读。如果数据库连接失败这是一个很好的响应,因为绝大多数情况下,如果不能连接到数据库,这一页不会显示任何有用的信息。
和我们在第二章做过的一样,连接被建立后下一步就是选择工作的数据库。我们将要在第二章中所建立的笑话数据库中工作。这个数据库被命名为jokes。在PHP中用来选择数据库的另外一个函数:
mysql_select_db ( "jokes", $dbcnx ); |
请注意我们在这儿使用了$dbcnx变量来指出了这个函数所使用的连接标识。这个参数实际上是可省略的。当省略这个参数时,函数会自动使用最后开启的那一个连接。这个函数成功后返回逻辑真,失败后返回逻辑假。为了谨慎起见,我们也用了一个if语句来处理错误:
if (! @mysql_select_db("jokes") ) { echo ( " Unable to locate the joke database at this time. " );exit (); } |
当建立了连接并选择了数据库之后,我们可以开始使用存储在数据库中的数据了。
在PHP中执行SQL查询
在第二章中,我们使用一个叫mysql的程序来连接到MySQL数据库服务器,在这个程序中,我们可以输入SQL查询(命令)并立即显示查询结果。在PHP中,有着类似的机制:mysql_query函数。
mysql_query ( |
在这儿,
这个函数的返回决定于发出的查询的类型。对于绝大多数的SQL命令来说,mysql_query返回逻辑真或逻辑假来标明执行是否成功。请参看下面这个例子,这是用来建立我们在第二章中建立的Jokes数据表的:
$sql = "CREATE TABLE Jokes ( ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, JokeText TEXT, JokeDate DATE NOT NULL )"; if ( mysql_query($sql) ) { echo ( " Jokes table successfully created! " );} else { echo ( " Error creating Jokes table: " . mysql_error () . ". " );} |
这儿使用的mysql_error将以字符串的形式返回MySQL服务器最后发出的错误信息。
对于DELETE、 INSERT以及UPDATE(用来修改存储的数据),MySQL可以知道有多少数据行被这个查询影响。参看下面的SQL命令,这个命令我们曾在第二章中用来设置所有包含单词“chicken”的笑话的日期:
$sql = "UPDATE Jokes SET JokeDate = '1990-04-01' WHERE JokeText LIKE '%chicken%'"; |
当我们执行这个查询时,我们可以使用mysql_affected_rows函数来显示这个修改所影响的数据行的数目:
if ( mysql_query($sql) ) { echo (" Update affected " . mysql_affected_rows() . " rows. ");} else { echo (" Error performing update: " . mysql_error () . ". ");} |
SELECT命令会有一些不同,因为它会得到许多信息,而PHP必须提供方法来处理这些信息。
处理SELECT结果集
对于绝大多数的SQL查询来说,mysql_query函数仅仅返回逻辑真或逻辑假。而对于SELECT查询来说,仅仅这样显然是不够的。你应该还记得SELECT查询是用来显示数据库中存储的数据的。除了指出查询成功还是失败之外,PHP还必须得到查询的结果。作为一个结果,当我们执行一个SELECT查询的时候,mysql_query会返回一个标识“结果集”的数字,这将包含了这个查询返回的所有行的列表。如果查询失败,函数仍然是返回一个逻辑假。
$result = mysql_query ( "SELECT JokeText FROM Jokes" ); if ( !$result ) { echo (" Error performing query: " . mysql_error () . ". ");exit (); } |
假定在执行查询时没有遇到错误,上面的代码会定位一个有关存储在笑话库中所有笑话的正文的结果集,这个定位被存储在变量$result中。因为数据库中的笑话的数目是没有限制的,这个结果集可能非常庞大。
我们之前曾经提到过while循环对于处理大量的数据来说是一个非常有用的控制语句,这是我们逐个处理结果集中数据行的代码的基本格式:
while ( $row = mysql_fetch_array($result) ) { // process the row... } |
在这个while循环中的条件可能看上去与我们曾经使用过的有所不同,所以我们有必要在这里解释它的工作机理。你可以先把这个条件看成一个独立的语句:
$row = mysql_fetch_array ( $result ); |
mysql_fetch_array函数以一个参数(对于这个例子来说是存储在$result变量中)接受到一个结果集,并以一个数据的形式返回结果集中的下一行。如果你还不熟悉数组的概念,不要担心,我们会在下面详细讨论它。如果在这个结果集中不再有其它数据行时,mysql_fetch_array返回逻辑假。
现在,我们上面的语句定义了一个值到$row变量中,与此同时,整个语句也获得了同样的值。这就是我们在while循环的条件中使用这个语句的原因,因为while循环会一直执行循环直到条件等于逻辑假,结果集有几行,这个循环就会执行几次,每一次$row都会得到一个下一行的值,现在剩下的就是如何在循环中从$row变量中获得相应的值了。
结果集中的行被描述成一个数组。数组是一个特殊类型的变量,这个变量可以包含多个值,如果你把一个变量看成是值的容器,你可以把数组看成是有间隔的容器,在每一个间隔中可以存储一个单独的值。对于我们的数据行来说,这个间隔是以数据表的列名命名的。如果$row是我们结果集中的一行,那么$row["JokeText"]就是这一行中JokeText列的值。所以如果我们想要显示我们的数据库中所在笑话的正文,while循环应该是这样的:
while ( $row = mysql_fetch_array($result) ) { echo ( " " . $row["JokeText"] . " " );} |
最后,作为一个总结,这是一段完整的PHP的Web页面的代码,它用来连接我们的数据库,取出数据库中所有笑话的正文,并将其在HTML中显示出来:
//连接到MySQL服务器 //Connect to the database server. $dbcnx = @mysql_connect( "localhost", "root", "" ); if ( !$dbcnx ) { echo ( " Unable to connect to the database server at this time. " );exit (); } //选择jokes数据库 //Select the jokes database. if ( !@mysql_select_db( "jokes", $dbcnx ) ) { echo ( " Unable to locate the jokes database at this time. " );exit (); } ?> Here are all the jokes in our database:
|
向数据库中插入数据
在这一节里,我们会看到我们会如何综合利用这些工具来让我们站点的访问者向数据库中添加他们自己的笑话。如果你喜欢挑战,你可以试试在向下看之前想想大致上应该怎么做。在这一节里只有很少的新的东西。对于我们学过的东西来说,这只是一个简单的应用。
如果我们想要让访问者能够输入新的笑话,我们首先需要一个表单,这儿是这个表单的代码:
正如我们上面看到的那样,这个表单在提交时会载入同一个页面(因为我们在表单的ACTION属性中使用了$PHP_SELF变量),但是在再次载入时请求中包含了两个变量,首先是$joketext,这是在text域中输入的笑话的正文,另一个是$submitjoke,这个变量的值将始终是"SUBMIT",这用来标志笑话已被提交。
要将已提交的笑话添加到数据库中,我们需要用mysql_query来运行一个INSERT查询,这个查询中将包含已经提交的$joketext变量的值:
if ("SUBMIT" == $submitjoke) { $sql = "INSERT INTO Jokes SET " . "JokeText='$joketext', " . "JokeDate=CURDATE()"; if (mysql_query($sql)) { echo(" Your joke has been added. ");} else { echo(" Error adding submitted joke: " . } } |
在全部的内容中只有SQL代码中出现了一个新的东西。在这里我们使用了一个MySQL函数CURDATE()来将新插入数据库的笑话的JokeDate列的值置为当前日期。事实上,MySQL有很多这样的函数,但是我们只会在使用到他们时才会介绍他们,要得到一个完整的函数的说明,你可以参看MySQL参考手册。
现在我们已经有了允许用户输入一个笑话并将其加入到我们的数据库中的程序代码。现在剩下的就是将其加入到我们已做好的笑话显示页面。因为绝大多数的用户只会想要看看笑话,所以我们不想对我们的页面做大的更改,除非用户表示想要添加一个新的笑话。因为这个原因,我们的应用程序应该是一个多功能的页面。下面是程序的代码:
//if the user wants to add a joke. if ( isset($addjoke) ): ?> else: //连接到MySQL服务器 //Connect to the database server. $dbcnx = @mysql_connect( "localhost", "root", "" ); if ( !$dbcnx ) { echo ( " Unable to connect to the database server at this time. " );exit (); } //选择jokes数据库 //Select the jokes database. if ( !@mysql_select_db( "jokes", $dbcnx ) ) { echo ( " Unable to locate the jokes database at this time. " );exit (); } ?> Here are all the jokes in our database:
|
现在我们有了一个单独的文件,这个文件包含不太多的PHP代码,通过这个文件,我们可以显示我们的MySQL数据库中的笑话并能向我们的MySQL数据库中添加笑话。
一个挑战
作为家庭作业,你可以看看你是不是能解决这么一个问题:在页面上显示的每一个笑话后面放置一个叫“Delete this Joke”的超连接,当单击这个连接时,会从数据库中删除这个笑话并显示更改过以后的笑话列表。下面是对你的一些提示:
你可以还在一个多功能页面完成全部的功能。
你需要使用SQL的DELETE命令,这个命令我们曾在第二章中学习过。
这是一个关键的问题。要删除一个指定的数据库,你需要能够唯一地标识它。Jokes表中的ID可以完成这个功能。你必须将要被删除的笑话的ID传递到删除笑话的请求中。将这个值放到“Delete this Joke”连接的查询字符串中是比较合适的。
如果你觉得你已经有了答案,或者你只想知道解决方案,那就去看看下一页。祝你好运!
结语
在这一章中,我们学习了一些新的用来实现与MySQL数据库服务接口的PHP函数。使用这些函数,我们建立了我们的第一个数据库驱动的网站,我们的这个网站可以在线地发布我们数据库中笑话并允许访问者向其中添加他们自己的笑话。
在第五章中,我们会回到MySQL命令行去学习如何使用关系型数据库的原理以及其他一些更高级的SQL查询去描述更为复杂的信息,并给予访问者对他们自己添加的笑话以特别的权限!
挑战的解决
这是我们上面提出的“家庭作业”的解决方案。要在每一个笑话后面添加一个“Delete this Joke”连接,必须作下面的改动:
之前,我们曾经在我们的页面的底端的“Add a Joke!”连接中传递过一个$addjoke变量,通过这个变量来通知我们的脚本不再显示通常的笑话列表,而是显示一个录入笑话的表单。与此相类似,我们在我们的“Delete this Joke”连接中传递一个$deletejoke变量来表示我们想要删除一个笑话。
在获得每一个笑话的JokeText列的同时,我们还获得了ID列的值,所以我们获得了与数据库中每一个笑话关联的ID。
我们将要删除的笑话的ID值赋予$deletejoke变量。这是通过将从数据库中获得的ID值插入到每一个笑话的“Delete this Joke”连接中来实现的。
使用了一个if 语句,如果在载入这一页时,我们的$deletejoke被赋予了一个值(使用isset函数),我们会在一个SQLDELETE语句中使用这个值(将被删除的笑话的ID)来删除指定的笑话。
这儿是全部的源代码:
... // If the user wants to add a joke if (isset($addjoke)): ?> else: // Connect to the database server $dbcnx = @mysql_connect( "localhost", "root", "mypasswd"); if (!$dbcnx) { echo( " Unable to connect to the " . exit(); } // Select the jokes database if (! @mysql_select_db("jokes") ) { echo( " Unable to locate the joke " . exit(); } // If a joke has been submitted, // add it to the database. if ("SUBMIT" == $submitjoke) { $sql = "INSERT INTO Jokes SET " . "JokeText='$joketext', " . "JokeDate=CURDATE()"; if (mysql_query($sql)) { echo(" Your joke has been added. ");} else { echo(" Error adding submitted joke: " . } } // If a joke has been deleted, // remove it from the database. if (isset($deletejoke)) { $sql = "DELETE FROM Jokes " . "WHERE ID=$deletejoke"; if (mysql_query($sql)) { echo(" The joke has been deleted. ");} else { echo(" Error deleting joke: " . } } echo(" Here are all the jokes " . // Request the ID and text of all the jokes $result = mysql_query( "SELECT ID, JokeText FROM Jokes"); if (!$result) { echo(" Error performing query: " . exit(); } // Display the text of each joke in a paragraph // with a "Delete this Joke" link next to each. while ( $row = mysql_fetch_array($result) ) { $jokeid = $row["ID"]; $joketext = $row["JokeText"]; echo(" $joketext " . } // When clicked, this link will load this page // with the joke submission form displayed. echo(""); endif; ?> |