明輝手游網(wǎng)中心:是一個免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺!

用PHP與MySQL構(gòu)建一個數(shù)據(jù)庫驅(qū)動的網(wǎng)站(6)

[摘要]摘要  在這一章內(nèi)我們會學(xué)習(xí)到如何在一個Web頁面中向數(shù)據(jù)庫中存儲信息并顯示它。(2002-08-29 14:11:25)--------------------------------------------------------------------------------By Wing,...
摘要

  在這一章內(nèi)我們會學(xué)習(xí)到如何在一個Web頁面中向數(shù)據(jù)庫中存儲信息并顯示它。

(2002-08-29 14:11:25)

--------------------------------------------------------------------------------
By Wing, 出處:Linuxaid


第四章: 用PHP訪問MySQL數(shù)據(jù)庫

  在這一章內(nèi)我們會學(xué)習(xí)到如何在一個Web頁面中向數(shù)據(jù)庫中存儲信息并顯示它。之前我們已經(jīng)安裝了MySQL這個關(guān)系型數(shù)據(jù)庫引擎以及PHP這個服務(wù)器端腳本語言,并學(xué)習(xí)了有關(guān)它們的基本知識。在學(xué)完這一章后,我們將明白如何綜合利用這兩個新的工具來構(gòu)建一個數(shù)據(jù)庫驅(qū)動的網(wǎng)站!

對前一部分的回顧

  在我們往下繼續(xù)之前,回顧一下我們學(xué)習(xí)的目的應(yīng)該是件有價值的事,F(xiàn)在有我們的系統(tǒng)中有了兩個強(qiáng)有力的新的工具:腳本語言PHP和數(shù)據(jù)庫引擎MySQL。搞清楚兩者是如果協(xié)同工作是很重要的。

  數(shù)據(jù)庫驅(qū)動的網(wǎng)站的實(shí)質(zhì)就是允許站點(diǎn)的內(nèi)容存在于一個數(shù)據(jù)庫中,并且可以通過這個數(shù)據(jù)庫來動態(tài)地產(chǎn)生Web頁面來讓我們的訪問者通過標(biāo)準(zhǔn)的Web瀏覽器來顯示它。所以在你的系統(tǒng)的一端是一個訪問你的站點(diǎn)的瀏覽者,他通過訪問http://www.yoursite.com/來獲得一個標(biāo)準(zhǔn)的HTML格式的Web頁面并在Web瀏覽器中顯示它。在你的系統(tǒng)的另一端是通過一個或幾個數(shù)據(jù)表存儲在一個只理解如何響應(yīng)SQL查詢(命令)的MySQL數(shù)據(jù)庫中的你的站點(diǎn)的內(nèi)容。

  PHP腳本語言承擔(dān)了兩者之間的聯(lián)絡(luò)員的角色,使用PHP,你可以編寫一個標(biāo)準(zhǔn)HTML的“模板”,這個“模板”決定了你的站點(diǎn)的外觀(包括圖畫和頁面設(shè)計(jì))。這時內(nèi)容是屬于這個“模板”的,你可以使用一些PHP代碼來連接MySQL數(shù)據(jù)庫并且使用SQL查詢來獲得數(shù)據(jù)并在其相應(yīng)位置顯示它,這里的SQL查詢是和我們在第二章中用來建立笑話數(shù)據(jù)表時一樣的。

  現(xiàn)在對于訪問者在訪問你的數(shù)據(jù)庫驅(qū)動的網(wǎng)站的一個頁面時,到底會發(fā)生什么事,你應(yīng)該有個明確的認(rèn)識了:

  訪問者的Web瀏覽器使用一個標(biāo)準(zhǔn)的URL請求這個頁面。

  Web服務(wù)器軟件(Apache、IIS或其他)認(rèn)定被請求的頁面是一個PHP腳本,因而在響應(yīng)這個頁面請求之前用它的PHP插件來解釋它。

  一些PHP命令(我們還沒學(xué)到)會連接MySQL數(shù)據(jù)庫并向數(shù)據(jù)庫請求屬于這個Web頁面的內(nèi)容。

  MySQL數(shù)據(jù)庫作出響應(yīng)并且向PHP腳本發(fā)出被請求的內(nèi)容。

  PHP腳本將內(nèi)容存儲到一個或幾個PHP變量中,并使用我們熟悉的echo函數(shù)將其作為Web頁面的一部分輸出。

  PHP插件完成處理并將生成的HTML副本返回到Web服務(wù)器。

  Web服務(wù)器將這個HTML副本發(fā)送到Web瀏覽器,這將是一個標(biāo)準(zhǔn)的HTML文件,只不過它不是直接來自于一個HTML文件,而是來自于PHP插件提供的輸出。

用PHP連接MySQL

  在我們從我們的MySQL數(shù)據(jù)庫中獲取我們的Web頁面所包含的內(nèi)容之前,我們首先必須知道如何建立與MySQL的連接。在第二章中,我們使用了一個叫mysql的程序來做這樣的連接。PHP不需要這樣的一個程序,對連接MySQL的支持是語言內(nèi)置的。下面的這個函數(shù)用來建立這樣的連接:

mysql_connect(<address>, <username>, <password>);


  在這里,<address>是MySQL服務(wù)軟件在其上運(yùn)行的計(jì)算機(jī)的IP地址或主機(jī)名(如果這與運(yùn)行Web服務(wù)軟件的計(jì)算機(jī)是同一臺,你可以使用"localhost"),<username>和<password>就是你在第二章中用來連接到MySQL服務(wù)器的用戶名及口令。

  你可能還記得PHP中的函數(shù)在被調(diào)用時往往會返回(輸出)一個值。請不要擔(dān)心我們沒有提醒你,我們在最初接觸一個函數(shù)時都會為你詳細(xì)詳細(xì)它。絕大多數(shù)的函數(shù)在被調(diào)用后,都會返回一個可以在存儲在變量中的值以備下次使用。例如我們上面介紹的mysql_connect函數(shù),會返回一個數(shù)字來標(biāo)識已經(jīng)建立的連接。因?yàn)槲覀儠褂眠@個連接,所以我們必須保存這個值。下面是一個關(guān)于如何連接我們的MySQL數(shù)據(jù)庫的一個實(shí)例:

$dbcnx = mysql_connect("localhost", "root", "mypasswd");


  需要說明的是,對于你的MySQL服務(wù)器,上面這個函數(shù)中的三個參數(shù)的值可能是不同的。你應(yīng)該注意到在這兒我們的mysql_connect 返回了一個值(我們稱之為一個連接標(biāo)識),這個值被我們存儲在變量$dbcnx中。

  因?yàn)镸ySQL是一個完全分布式的軟件,我們必須考慮到這些可能性:服務(wù)不可用、網(wǎng)絡(luò)堵塞或者是我們的用戶名及口令不匹配。在這些情況下,mysql_connect函數(shù)不能返回一個連接標(biāo)識(因?yàn)檫B接未被建立)。這時,會返回一個邏輯假。這使得我們可以用一個if語句來處理連接的情況: $dbcnx = @mysql_connect("localhost", "root", "mypasswd");


if (!$dbcnx) {
echo( "<P>Unable to connect to the " .
"database server at this time.</P>" );
exit();
}



  在上面的代碼段中出現(xiàn)了三個新的東西,首先,我們在mysql_connect函數(shù)前加了一個@符號。包括mysql_connect在內(nèi)的許多函數(shù)會在失敗后顯示難看的錯誤信息。在函數(shù)名前加一個@符號可以告訴這個函數(shù)當(dāng)執(zhí)行失敗時,允許我們顯示我們自己友好的出錯信息。

  其次,在我們的if語句的條件中,$dbcnx變量前面加了一個驚嘆號。這個驚嘆號是PHP中的“否運(yùn)算符”。也就是說將邏輯真變?yōu)檫壿嫾,將邏輯假變(yōu)檫壿嬚。這樣,如果這個連接是失敗的,mysql_connect會返回一個邏輯假,!$dbcnx將等于邏輯真,這樣我們的if語句將被執(zhí)行。相反,如果這個連接是成功的,存儲在$dbcnx 中的連接標(biāo)識將等于邏輯真(在PHP中,任何非零的數(shù)字都被認(rèn)為是邏輯真),所以!$dbcnx會等于邏輯假,if語句將不會被執(zhí)行。

  最后一個是exit函數(shù),這是我們遇到的第一個沒有參數(shù)的函數(shù)。這個函數(shù)的全部作用就是導(dǎo)致PHP停止對本頁的閱讀。如果數(shù)據(jù)庫連接失敗這是一個很好的響應(yīng),因?yàn)榻^大多數(shù)情況下,如果不能連接到數(shù)據(jù)庫,這一頁不會顯示任何有用的信息。

  和我們在第二章做過的一樣,連接被建立后下一步就是選擇工作的數(shù)據(jù)庫。我們將要在第二章中所建立的笑話數(shù)據(jù)庫中工作。這個數(shù)據(jù)庫被命名為jokes。在PHP中用來選擇數(shù)據(jù)庫的另外一個函數(shù):

mysql_select_db("jokes", $dbcnx);


  請注意我們在這兒使用了$dbcnx變量來指出了這個函數(shù)所使用的連接標(biāo)識。這個參數(shù)實(shí)際上是可省略的。當(dāng)省略這個參數(shù)時,函數(shù)會自動使用最后開啟的那一個連接。這個函數(shù)成功后返回邏輯真,失敗后返回邏輯假。為了謹(jǐn)慎起見,我們也用了一個if語句來處理錯誤:


if (! @mysql_select_db("jokes") ) {
echo( "<P>Unable to locate the joke " .
"database at this time.</P>" );
exit();
}



  當(dāng)建立了連接并選擇了數(shù)據(jù)庫之后,我們可以開始使用存儲在數(shù)據(jù)庫中的數(shù)據(jù)了。

在PHP中執(zhí)行SQL查詢

  在第二章中,我們使用一個叫mysql的程序來連接到MySQL數(shù)據(jù)庫服務(wù)器,在這個程序中,我們可以輸入SQL查詢(命令)并立即顯示查詢結(jié)果。在PHP中,有著類似的機(jī)制:mysql_query函數(shù)。

mysql_query(<query>, <connection id>);


  在這兒,<query>是一個包含將執(zhí)行的SQL命令的字符串。和mysql_select_db一樣,連接標(biāo)識這個參數(shù)也是可選的。

  這個函數(shù)的返回決定于發(fā)出的查詢的類型。對于絕大多數(shù)的SQL命令來說,mysql_query返回邏輯真或邏輯假來標(biāo)明執(zhí)行是否成功。請參看下面這個例子,這是用來建立我們在第二章中建立的Jokes數(shù)據(jù)表的:


$sql = "CREATE TABLE Jokes ( " .
 "ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY, " .
 "JokeText TEXT, " .
 "JokeDate DATE NOT NULL " .
 ")";
if ( mysql_query($sql) ) {
echo("<P>Jokes table successfully created!</P>");
} else {
echo("<P>Error creating Jokes table: " .
 mysql_error() . "</P>");
}



  這兒使用的mysql_error將以字符串的形式返回MySQL服務(wù)器最后發(fā)出的錯誤信息。

  對于DELETE、 INSERT以及UPDATE(用來修改存儲的數(shù)據(jù)),MySQL可以知道有多少數(shù)據(jù)行被這個查詢影響。參看下面的SQL命令,這個命令我們曾在第二章中用來設(shè)置所有包含單詞“chicken”的笑話的日期:


$sql = "UPDATE Jokes SET JokeDate='1990-04-01' " .
 "WHERE JokeText LIKE '%chicken%'";
當(dāng)我們執(zhí)行這個查詢時,我們可以使用mysql_affected_rows函數(shù)來顯示這個修改所影響的數(shù)據(jù)行的數(shù)目:
if ( mysql_query($sql) ) {
echo("<P>Update affected " .
mysql_affected_rows() . " rows.</P>");
} else {
echo("<P>Error performing update: " .
 mysql_error() . "</P>");
}



  SELECT命令會有一些不同,因?yàn)樗鼤玫皆S多信息,而PHP必須提供方法來處理這些信息。

處理SELECT結(jié)果集

  對于絕大多數(shù)的SQL查詢來說,mysql_query函數(shù)僅僅返回邏輯真或邏輯假。而對于SELECT查詢來說,僅僅這樣顯然是不夠的。你應(yīng)該還記得SELECT查詢是用來顯示數(shù)據(jù)庫中存儲的數(shù)據(jù)的。除了指出查詢成功還是失敗之外,PHP還必須得到查詢的結(jié)果。作為一個結(jié)果,當(dāng)我們執(zhí)行一個SELECT查詢的時候,mysql_query會返回一個標(biāo)識“結(jié)果集”的數(shù)字,這將包含了這個查詢返回的所有行的列表。如果查詢失敗,函數(shù)仍然是返回一個邏輯假。


$result = mysql_query("SELECT JokeText FROM Jokes");
if (!$result) {
echo("<P>Error performing query: " .
 mysql_error() . "</P>");
exit();
}



  假定在執(zhí)行查詢時沒有遇到錯誤,上面的代碼會定位一個有關(guān)存儲在笑話庫中所有笑話的正文的結(jié)果集,這個定位被存儲在變量$result中。因?yàn)閿?shù)據(jù)庫中的笑話的數(shù)目是沒有限制的,這個結(jié)果集可能非常龐大。

  我們之前曾經(jīng)提到過while循環(huán)對于處理大量的數(shù)據(jù)來說是一個非常有用的控制語句,這是我們逐個處理結(jié)果集中數(shù)據(jù)行的代碼的基本格式:


while ( $row = mysql_fetch_array($result) ) {
// process the row...
}



  在這個while循環(huán)中的條件可能看上去與我們曾經(jīng)使用過的有所不同,所以我們有必要在這里解釋它的工作機(jī)理。你可以先把這個條件看成一個獨(dú)立的語句:

$row = mysql_fetch_array($result);


  mysql_fetch_array函數(shù)以一個參數(shù)(對于這個例子來說是存儲在$result變量中)接受到一個結(jié)果集,并以一個數(shù)據(jù)的形式返回結(jié)果集中的下一行。如果你還不熟悉數(shù)組的概念,不要擔(dān)心,我們會在下面詳細(xì)討論它。如果在這個結(jié)果集中不再有其它數(shù)據(jù)行時,mysql_fetch_array返回邏輯假。

  現(xiàn)在,我們上面的語句定義了一個值到$row變量中,與此同時,整個語句也獲得了同樣的值。這就是我們在while循環(huán)的條件中使用這個語句的原因,因?yàn)閣hile循環(huán)會一直執(zhí)行循環(huán)直到條件等于邏輯假,結(jié)果集有幾行,這個循環(huán)就會執(zhí)行幾次,每一次$row都會得到一個下一行的值,現(xiàn)在剩下的就是如何在循環(huán)中從$row變量中獲得相應(yīng)的值了。

  結(jié)果集中的行被描述成一個數(shù)組。數(shù)組是一個特殊類型的變量,這個變量可以包含多個值,如果你把一個變量看成是值的容器,你可以把數(shù)組看成是有間隔的容器,在每一個間隔中可以存儲一個單獨(dú)的值。對于我們的數(shù)據(jù)行來說,這個間隔是以數(shù)據(jù)表的列名命名的。如果$row是我們結(jié)果集中的一行,那么$row["JokeText"]就是這一行中JokeText列的值。所以如果我們想要顯示我們的數(shù)據(jù)庫中所在笑話的正文,while循環(huán)應(yīng)該是這樣的:


while ( $row = mysql_fetch_array($result) ) {
echo("<P>" . $row["JokeText"] . "</P>");
}



  最后,作為一個總結(jié),這是一段完整的PHP的Web頁面的代碼,它用來連接我們的數(shù)據(jù)庫,取出數(shù)據(jù)庫中所有笑話的正文,并將其在HTML中顯示出來:


<HTML>
<HEAD>
<TITLE> Our List of Jokes </TITLE>
</HEAD>
<BODY>
<?php

// Connect to the database server
$dbcnx = @mysql_connect("localhost",
 "root", "mypasswd");
if (!$dbcnx) {
echo( "<P>Unable to connect to the " .
"database server at this time.</P>" );
exit();
}

// Select the jokes database
if (! @mysql_select_db("jokes") ) {
echo( "<P>Unable to locate the joke " .
"database at this time.</P>" );
exit();
}

?>
<P> Here are all the jokes in our database: </P>
<BLOCKQUOTE>

<?php
// Request the text of all the jokes
$result = mysql_query(
"SELECT JokeText FROM Jokes");
if (!$result) {
echo("<P>Error performing query: " .
 mysql_error() . "</P>");
exit();
}

// Display the text of each joke in a paragraph
while ( $row = mysql_fetch_array($result) ) {
echo("<P>" . $row["JokeText"] . "</P>");
}
?>
</BLOCKQUOTE>
</BODY>
</HTML>



向數(shù)據(jù)庫中插入數(shù)據(jù)

  在這一節(jié)里,我們會看到我們會如何綜合利用這些工具來讓我們站點(diǎn)的訪問者向數(shù)據(jù)庫中添加他們自己的笑話。如果你喜歡挑戰(zhàn),你可以試試在向下看之前想想大致上應(yīng)該怎么做。在這一節(jié)里只有很少新的東西。對于我們學(xué)過的東西來說,這只是一個簡單的應(yīng)用。

  如果我們想要讓訪問者能夠輸入新的笑話,我們首先需要一個表單,這兒是這個表單的代碼:


<FORM ACTION="<?php echo($PHP_SELF); ?>" METHOD=POST>
<P>Type your joke here:<BR>
<TEXTAREA NAME="joketext" ROWS=10 COLS=40 WRAP></TEXTAREA><BR>
<INPUT TYPE=SUBMIT NAME="submitjoke" VALUE="SUBMIT">
</FORM>



  正如我們上面看到的那樣,這個表單在提交時會載入同一個頁面(因?yàn)槲覀冊诒韱蔚腁CTION屬性中使用了$PHP_SELF變量),但是在再次載入時請求中包含了兩個變量,首先是$joketext,這是在text域中輸入的笑話的正文,另一個是$submitjoke,這個變量的值將始終是"SUBMIT",這用來標(biāo)志笑話已被提交。

   要將已提交的笑話添加到數(shù)據(jù)庫中,我們需要用mysql_query來運(yùn)行一個INSERT查詢,這個查詢中將包含已經(jīng)提交的$joketext變量的值:


if ("SUBMIT" == $submitjoke) {
$sql = "INSERT INTO Jokes SET " .
 "JokeText='$joketext', " .
 "JokeDate=CURDATE()";
if (mysql_query($sql)) {
echo("<P>Your joke has been added.</P>");
} else {
echo("<P>Error adding submitted joke: " .
 mysql_error() . "</P>");
}
}



  在全部的內(nèi)容中只有SQL代碼中出現(xiàn)了一個新的東西。在這里我們使用了一個MySQL函數(shù)CURDATE()來將新插入數(shù)據(jù)庫的笑話的JokeDate列的值置為當(dāng)前日期。事實(shí)上,MySQL有很多這樣的函數(shù),但是我們只會在使用到他們時才會介紹他們,要得到一個完整的函數(shù)的說明,你可以參看MySQL參考手冊。