博客提綱
- 利用PHP連接mySQL數據庫
- 兩套接口:面向對象和面向過程
- 實現寫改刪查(CUBD)實例
- 通過prepare語句處理相同類型的不同SQL語句
- 通過bind_param()綁定參數,及相關注意事項
- 通過bind_result()綁定結果,以及相關注意事項
- 將文本寫入數據庫前應做的檢測和處理
- 檢查是否為空(未輸入值)
- 去首尾空格
- 魔鬼字符串轉義
一.利用PHP連接mySQL數據庫
這要從一個故事說起。
某一天,一位名叫MySQL的農夫的一把斧子(數據庫操作)掉進了一條名為PHP的河里,這時候,一位好心的河神出現了
PHP河的河神問他。。。。
下面,咱們還是說正經的把!。。。(:3 」∠)
在我主機(localhost)的penghuwan數據庫下,有張mytable的表如下圖所示
PHP針對mysql數據庫的操作有兩套接口:面向對象接口和面向過程接口;
- 面向對象接口:通過調用對象中的函數完成數據庫操作
- 面向過程接口:直接調用PHP內置的函數實現數據庫操作
因為執行寫改刪操作的PHP語句類似,所以這里只以“寫操作”和“查操作”為例子
讀操作:
面向對象:
<?php
@$mysqli = new mysqli('localhost', 'root', 'phw441423', 'penghuwan');//(主機,賬號,密碼,數據庫) 返回一個mysqli對象
if($mysqli->connect_error){//當有連接錯誤的時候,結束腳本運行並且報錯
die('連接錯誤,這個錯誤是'.$mysqli->connect_error);//die()函數:1結束腳本運行,2輸出一段文本(括號內)
}
$query = "SELECT * FROM mytable";//把一段SQL語句保存在$query變量中
$mysqli_result = $mysqli->query($query);//通過調用上面返回的mysqli對象中的方法,返回一個結果集對象(mysqli_result)
while($row = $mysqli_result->fetch_assoc()){//調用mysqli_result的方法fetch_assoc()后,返回的是一個數組變量$row
echo $row['name'];//訪問返回數組變量$row中的數組成員,對應mytable表中的name列
echo $row['number'];;//訪問返回數組變量$row中的數組成員,對應mytable表中的number
echo "<br/>";
}
$mysqli_result->free();//釋放結果集
$mysqli ->close();//關閉數據庫連接
?>
首先通過
new mysqli($host, $username, $passwd, $dbname)
獲取一個mysqli對象,然后在下面我們就可以通過調用對象中的方法query方法去實現寫改刪查
運行結果:
思維導圖

上面的例子中,一個關鍵的方法是mysqli對象的query方法,意為查詢.但實際上,它除了能運行“查”的SQL語句外,還能運行“寫改刪”的SQL語句。
關於query的返回值:
- 執行失敗,返回false
- 執行成功
- 如果執行的語句,即query是SELECT,SHOW,EXPLAIN 或 DESCRIBE,則返回一個結果集對象
- 如果是其他,則返回false
面向過程:
<?php
@$mysqli = mysqli_connect('localhost', 'root', 'phw441423', 'penghuwan');//(主機,賬號,密碼,數據庫) 返回一個mysqli對象
if(mysqli_connect_error()){//當有連接錯誤的時候,結束腳本運行並且報錯
die('連接錯誤,這個錯誤是'.mysqli_connect_error());;//die()函數:1結束腳本運行,2輸出一段文本(括號內)
}
$query = "SELECT * FROM mytable";//把一段SQL語句保存在$query變量中
$mysqli_result = mysqli_query($mysqli, $query);//在面向過程風格里,$mysqli對象成了該方法中的參數,也返回一個結果集對象(mysqli_result)
while($row = mysqli_fetch_assoc($mysqli_result)){// 返回的是一個數組變量$row
echo $row['name'];//訪問返回數組變量$row中的數組成員,對應mytable表中的name列
echo $row['number'];;//訪問返回數組變量$row中的數組成員,對應mytable表中的number
echo "<br/>";
}
mysqli_free_result($mysqli_result);//釋放結果集
mysqli_close($mysqli);//關閉數據庫連接
?>
【注意點】
- mysqli_fetch_assoc(面向過程)和fetch_assoc(面向對象)這兩個方法返回的是一個關聯數組變量$row
- 在命令行界面里,我們需要做選擇數據庫的選擇,即使用“USE 所選數據庫”這個命令,但在這里我們在一開始連接的時候就選擇了數據庫了。例如:mysqli_connect('localhost', 'root', 'phw441423', 'penghuwan');中我們選擇了數據庫penghuwan所以就不用寫USE語句了
- 最后記得要釋放結果集和關閉連接
擁有兩套接口固然增加了記憶難度,但如果你注意觀察的話,兩套接口函數的名稱是聯系緊密的。
-
如何記憶?
一般情況下:面向過程函數名= mysqli_ +面向對象函數名
例如:
返回結果集對象的方法:
面向對象:query 面向過程:mysqli_query
從結果集對象中返回某一行(形式為關聯數組)的方法:
面向對象:fetch_assoc 面向過程:mysqli_fetch_assoc -
兩者聯系
一般情況下,面向對象接口中的對象將會成為面向過程接口中的第一個參數
例如:
通過mysqli對象取得結果集的時候:
面向過程:$mysqli_result = mysqli_query($mysqli, $query);
面向對象:$mysqli_result = $mysqli->query($query);
寫操作:
面向對象:
<?php
@$mysqli = new mysqli('localhost', 'root', 'phw441423', 'penghuwan');//(主機,賬號,密碼,數據庫) 返回一個mysqli對象
if($mysqli->connect_error){//當有連接錯誤的時候,結束腳本運行並且報錯
die('連接錯誤,這個錯誤是'.$mysqli->connect_error);//die()函數:1結束腳本運行,2輸出一段文本(括號內)
}
$query = "INSERT INTO mytable VALUES('C',30)";//把一段SQL語句保存在$query變量中
$mysqli->query($query);// 此時返回的不是結果集對象,而是一個boolean,代表成功或失敗
$mysqli ->close();//關閉數據庫連接
?>
運行結果:
思維導圖

面向過程:
和第一個“查”的例子類似,這里不多加贅述。
二.通過prepare語句處理相同類型的不同SQL語句
通過bind_param()綁定參數,及相關注意事項
在實際操作中,我們可能需要處理大量相同類型的不同SQL語句,例如
"SELECT * FROM mytable WHERE name = ‘A’"
或者
"SELECT * FROM mytable WHERE name = ‘B’"
這樣的語句。你可能會試圖自己封裝函數來避免寫一大堆相同類型的語句。但實際上,PHP已經給我們封裝好了一系列的內置函數,它就是prepare語句:
我們接下來實現這樣一段PHP腳本:
通過prepare語句給mytable插入兩行數據(類型相同的不同SQL語句)
我們原來的mytable表長這樣:
我們下面向其中插入兩行
列1 | 列2 |
---|---|
D | 40 |
E | 50 |
<?php
@$mysqli = new mysqli('localhost', 'root', 'phw441423', 'penghuwan');//(主機,賬號,密碼,數據庫) 返回一個mysqli對象
if($mysqli->connect_error){//當有連接錯誤的時候,結束腳本運行並且報錯
die('連接錯誤,這個錯誤是'.$mysqli->connect_error);//die()函數:1結束腳本運行,2輸出一段文本(括號內)
}
$query = "INSERT INTO mytable VALUES(?,?)";//,“?”表示模板中要被實際替換的變量
$stmt = $mysqli->prepare($query);//通過prepare函數生成mysqli_statement對象
$name1 = 'D';
$number1 = 40;
$stmt->bind_param("si",$name1,$number1);//通過mysqli_statement對象的bind_param方法用實際的變量替換模板中的"?"
$stmt->execute();//第一次執行
$name2 = 'E';
$number2 = 50;
$stmt->bind_param("si",$name2,$number2);//通過mysqli_statement對象的bind_param方法用實際的變量替換模板中的"?"
$stmt->execute();//第二次執行
$stmt->close();//關閉mysqli_statement
$mysqli ->close();//關閉數據庫連接
?>
思維導圖

運行結束后:
關鍵的一個方法是bind_param()方法,它接受多個參數,其中
第一個參數代表后面參數的類型。
第一個參數是一個字符串,由固定順序的字符組成,這些字符包括“s”,”i”,”d”,”b”,分別表示字符串,整型,雙精度和二進制文本,依次代表后面參數的類型。
字符 | 代表類型 |
---|---|
“s” | 字符串 |
“i” | 整型 |
“d” | 雙精度 |
“b” | 二進制文本 |
例如:我們上面的$stmt->bind_param("si",$name1,$number1);代表:$name1是字符串類型,,$number1是整型
【注意】
- 不能直接向bind_param()第二個即以后的參數中寫入具體的變量值!否則會報錯:
例如,我們把:
<?PHP
$name1 = 'D';
$number1 = 40;
$stmt->bind_param("si",$name1,$number1);
?>
改成:
<?PHP
$stmt->bind_param("si",'D',40);
?>
運行:
【注意】
- 你只能寫入變量的名稱而不能寫具體的類型值——
一個bind_param()函數對應一個execute()函數,如果連續寫多個bind_param()再寫execute()函數,相當於最后一個bind_param()覆蓋前面寫的的 bind_param()
例如我們把上面的
$name1 = 'D';
$number1 = 40;
$stmt->bind_param("si",$name1,$number1);//通過mysqli_statement對象的bind_param方法用實際的變量替換模板中的"?"
$stmt->execute();//第一次執行
$name2 = 'E';
$number2 = 50;
$stmt->bind_param("si",$name2,$number2);//通過mysqli_statement對象的bind_param方法用實際的變量替換模板中的"?"
$stmt->execute();//第二次執行
改成:
$name1 = 'D';
$number1 = 40;
$stmt->bind_param("si",$name1,$number1);//通過mysqli_statement對象的bind_param方法用實際的變量替換模板中的"?"
$name2 = 'E';
$number2 = 50;
$stmt->bind_param("si",$name2,$number2);//通過mysqli_statement對象的bind_param方法用實際的變量替換模板中的"?"
$stmt->execute();//第二次執行
運行結果:
它並不會批量執行$name1,$number1和$name2,$number2的插入,而是只插入了$name2,$number2,因為最后一個bind_param()覆蓋前面寫的的 bind_param()
通過bind_result()綁定結果,及相關注意事項
上面的例子中我們演示了如何綁定參數,下面我來演示如何綁定結果,這里將用到bind_result()函數:
<?php
@$mysqli = new mysqli('localhost', 'root', 'phw441423', 'penghuwan');//(主機,賬號,密碼,數據庫) 返回一個mysqli對象
if($mysqli->connect_error){//當有連接錯誤的時候,結束腳本運行並且報錯
die('連接錯誤,這個錯誤是'.$mysqli->connect_error);//die()函數:1結束腳本運行,2輸出一段文本(括號內)
}
$query = "SELECT * FROM mytable";//prepare函數的參數
$stmt = $mysqli->prepare($query);//通過prepare函數生成mysqli_statement對象
$stmt->bind_result($name,$number);//將執行結果綁定到$name和,$number中
$stmt->execute();// 執行生成查詢結果
while($stmt->fetch()){// 將查詢結果中的第一行的列值分別賦給$name和,$number,同時游標移到下一行
echo $name.' '.$number;//輸出mytable中當前行各個列的列值
echo "<br/>";
}
$stmt->close();//關閉mysqli_statement
$mysqli ->close();//關閉數據庫連接
?>
思維導圖

運行結果如下:
【注意】
- bind_param必須放在execute語句的前面,但bind_result放在execute前后均可
例如:我們將上面對應的代碼改成:
$stmt->execute();// 執行生成查詢結果
$stmt->bind_result($name,$number);//將執行結果綁定到$name和,$number中
運行結果同上(但注意bind_result應放在fetch語句前)
- excute()執行完畢的時候,$name,$number仍為空,直到fetch()第一次執行的時候,$name,$number才取到對應行的列值
將上面例子中對應代碼改成:
$stmt->bind_result($name,$number);//將執行結果綁定到$name和,$number中
$stmt->execute();// 執行生成查詢結果
echo 'execute執行后$name的值為';
var_dump($name);
運行結果:
- 同一個prepare模板可多次使用,但前后使用兩個prepare模板中間,必須關閉現有的mysqli_statement
$query1 = "SELECT name FROM mytable";
$stmt = $mysqli->prepare($query1);
$stmt->execute();//執行第一個prepare模板語句
$query2 = "SELECT number FROM mytable";//prepare函數的參數
$stmt = $mysqli->prepare($query2);
$stmt->execute();//執行第二個prepare模板語句 [注],這就是24行
提示的錯誤是,我對一個boolean值調用了execute函數
我嘗試輸出$stmt(最下面那個),輸出為false(這里不做展示了)
這說明執行第二個prepare模板語句的時候失敗了,那這時候該怎么辦呢?
讓我們在兩段prepare模板語句間加上
$stmt->close():
即:
<?PHP
$query1 = "SELECT name FROM mytable";
$stmt = $mysqli->prepare($query1);
$stmt->execute();//執行第一個prepare模板語句
$stmt->close();
$query2 = "SELECT number FROM mytable";//prepare函數的參數
$stmt = $mysqli->prepare($query2);
$stmt->execute();//執行第二個prepare模板語句
?>
運行:報錯消失
三.將字符串寫入數據庫前應做的檢測和處理
應該注意的是三個方面的事情:
- 檢查輸入是否為空值,這點就不加贅述了
- 去除首尾空格(假設我們在錄入數據庫前沒有去除空格的話,例如將“【空格】彭湖灣”錄入數據庫,那么在進行“【空格】彭湖灣”===“彭湖灣”的匹配時便會返回false)
- 對魔術字符串轉義(如果不進行轉義,字符串中的雙引號和單引號會對我們的SQL語句造成干擾)
<?php
$text = $_GET['text'];// 從from表單中name屬性為“text”的輸入框中取得值
if(!$text){//如果text為空則輸出警告,並結束腳本
echo '您還沒有輸入任何值哦';
exit();
}
$text = trim($text);//去除首尾空格
if(!get_magic_quotes_gpc()){//檢查是否自動開啟了魔術字符串轉義,如果沒有,則手動轉義魔術字符串
$text = addslashes($text);
}
echo '經過處理后的值'.$text;
echo "<br/>";
echo '重新取出值'.stripslashes($text);
?>
輸入空值的時候:
輸入帶空格和魔術字符串的文本——“【空格】penghuwan”
參考資料
《php和mysql的web開發》--(澳)威利,(澳)湯姆森 著
PHP官方文檔 鏈接:http://php.net/manual/zh/
stackOverFlow社區 鏈接: https://stackoverflow.com/