【PHP】當mysql遇上PHP


博客提綱

  • 利用PHP連接mySQL數據庫
    • 兩套接口:面向對象和面向過程
    • 實現寫改刪查(CUBD)實例
  • 通過prepare語句處理相同類型的不同SQL語句
    • 通過bind_param()綁定參數,及相關注意事項
    • 通過bind_result()綁定結果,以及相關注意事項
  • 將文本寫入數據庫前應做的檢測和處理
    • 檢查是否為空(未輸入值)
    • 去首尾空格
    • 魔鬼字符串轉義

一.利用PHP連接mySQL數據庫

這要從一個故事說起。
某一天,一位名叫MySQL的農夫的一把斧子(數據庫操作)掉進了一條名為PHP的河里,這時候,一位好心的河神出現了

PHP河的河神問他。。。。

下面,咱們還是說正經的把!。。。(:3 」∠)

在我主機(localhost)penghuwan數據庫下,有張mytable的表如下圖所示

1

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);//關閉數據庫連接
?>

【注意點】

  1. mysqli_fetch_assoc(面向過程)和fetch_assoc(面向對象)這兩個方法返回的是一個關聯數組變量$row
  2. 在命令行界面里,我們需要做選擇數據庫的選擇,即使用“USE 所選數據庫”這個命令,但在這里我們在一開始連接的時候就選擇了數據庫了。例如:mysqli_connect('localhost', 'root', 'phw441423', 'penghuwan');中我們選擇了數據庫penghuwan所以就不用寫USE語句了
  3. 最后記得要釋放結果集和關閉連接

擁有兩套接口固然增加了記憶難度,但如果你注意觀察的話,兩套接口函數的名稱是聯系緊密的。

  • 如何記憶?
    一般情況下:面向過程函數名= 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();//關閉數據庫連接
?>

運行結果:

3

思維導圖

面向過程:

和第一個“查”的例子類似,這里不多加贅述。

二.通過prepare語句處理相同類型的不同SQL語句

通過bind_param()綁定參數,及相關注意事項

在實際操作中,我們可能需要處理大量相同類型的不同SQL語句,例如

"SELECT * FROM mytable WHERE name = ‘A’"

或者

"SELECT * FROM mytable WHERE name = ‘B’"

這樣的語句。你可能會試圖自己封裝函數來避免寫一大堆相同類型的語句。但實際上,PHP已經給我們封裝好了一系列的內置函數,它就是prepare語句

我們接下來實現這樣一段PHP腳本
通過prepare語句給mytable插入兩行數據(類型相同的不同SQL語句)

我們原來的mytable表長這樣

4

我們下面向其中插入兩行

列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();//關閉數據庫連接
 
?>

思維導圖

運行結束后

5

關鍵的一個方法是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);
?>

運行:

6
【注意】

  • 你只能寫入變量的名稱而不能寫具體的類型值——
    一個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();//第二次執行

運行結果:

7

它並不會批量執行$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();//關閉數據庫連接
?>

思維導圖

運行結果如下:

8

【注意】

  • 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);

運行結果:

9

  • 同一個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模板語句
?>

運行:報錯消失

三.將字符串寫入數據庫前應做的檢測和處理

應該注意的是三個方面的事情:

  1. 檢查輸入是否為空值,這點就不加贅述了
  2. 去除首尾空格(假設我們在錄入數據庫前沒有去除空格的話,例如將“【空格】彭湖灣”錄入數據庫,那么在進行“【空格】彭湖灣”===“彭湖灣”的匹配時便會返回false)
  3. 對魔術字符串轉義(如果不進行轉義,字符串中的雙引號和單引號會對我們的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);
    ?>

輸入空值的時候:

10

輸入帶空格和魔術字符串的文本——“【空格】penghuwan”

11

參考資料
《php和mysql的web開發》--(澳)威利,(澳)湯姆森 著
PHP官方文檔 鏈接:http://php.net/manual/zh/
stackOverFlow社區 鏈接: https://stackoverflow.com/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM