2015年3月6日 星期五

使用 PHP-MySQL, PHP-MySQLi, PDO 連線資料庫

最底層常見PHP連資料庫的方法有:
mysql_connect - 最原始的,大多數教科書使用的
mysqli - i 代表 Improvement ,提更了相對進階的功能,就 Extension 而言,本身也增加了安全性
pdo - (PHP Data Object) 則是提供了一個 Abstraction Layer 來操作資料庫

下面範例讀取trade資料庫的salary資料表,範例資料內容:
mysql> desc salary;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | int(11)      | NO   | PRI | NULL    | auto_increment |
| is_traded   | tinyint(1)   | NO   |     | NULL    |                |
| ps          | varchar(255) | NO   | UNI | NULL    |                |
| update_time | datetime     | NO   |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+

mysql> select * from salary;
+----+-----------+--------+---------------------+
| id | is_traded | ps     | update_time         |
+----+-----------+--------+---------------------+
|  1 |         0 | test11 | 2015-03-02 10:08:16 |
|  3 |         1 | test   | 2015-03-02 10:08:45 |
|  6 |         1 | 456456 | 2015-03-04 11:53:57 |
|  7 |         1 | 151656 | 2015-03-04 14:35:40 |
+----+-----------+--------+---------------------+

使用mysql_connect
mysql_connect("localhost", "uaername", "password");
mysql_select_db("trade");

$is_traded = 1;
$result = mysql_query("SELECT * FROM `salary` WHERE is_traded = '$is_traded'");

while ($row = mysql_fetch_array($result,  MYSQL_ASSOC)) {
 echo $row['ps']."\n";
}

mysql_free_result($result);

缺點:
$is_traded 的地方容易被 SQL Injection。必須使用mysql_escape_string() (備註:5.3.0之後棄用) 以及 mysql_real_escape_string(),但這樣敘述會變得複雜且醜陋,而且如果欄位多了,可以想見會是怎樣的情形...

mysql_connect使用mysql_real_escape_string()避免SQL Injection
mysql_connect("localhost", "root", "123123");
mysql_select_db("trade");

$is_traded = 1;
$query = sprintf("SELECT * FROM `salary` WHERE is_traded ='%s'", mysql_real_escape_string($is_traded));
echo "$query\n";
$result = mysql_query($query);

while ($row = mysql_fetch_array($result,  MYSQL_ASSOC)) {
 echo $row['ps']."\n";
}

mysql_free_result($result);

使用mysqli
$mysqli = new mysqli("localhost", "username", "password", "trade");
$is_traded = 1;
$result = $mysqli->query("SELECT * FROM `salary` WHERE is_traded = '$is_traded'");
while ($row = $result->fetch_assoc()) {
 echo "result is \$row['id']:{$row['id']}, \$row['is_traded']:{$row['is_traded']}, \$row['ps']:{$row['ps']}, \$row['update_time']:{$row['update_time']}\n";
}
一樣 $is_traded 的地方容易被 SQL Injection。

使用mysqli避免SQL Injection
$mysqli = new mysqli("localhost", "root", "123123", "trade");
$stmt = $mysqli->prepare(
  "SELECT * FROM `salary` WHERE is_traded =?");
$is_traded = "1'";
$stmt->bind_param( "s", $is_traded);
// "ss' is a format string, each "s" means string
$stmt->execute();

$stmt->bind_result($id, $is_traded, $ps, $update_time);
// then fetch and close the statement
while($stmt->fetch()){
    echo "result is \$id:$id, \$is_traded:$is_traded, \$ps:$ps, \$update_time:$update_time\n";
}
缺點:select * 時必須按照順序用bind_result榜定各欄位因fetch_assoc()不屬於$stmt的函數,所以不能叫他
優點:可以Bind Column。多援 Transaction, Multi Query,提供了 Object oriented style

使用PDO
$dsn = "mysql:host=localhost;dbname=trade";
$dbh = new PDO($dsn, "root", "123123");

$sql = "SELECT * FROM `salary` WHERE is_traded =?";
$sth = $dbh->prepare($sql);

$sth->execute(array(1));

while ($result = $sth->fetch(PDO::FETCH_OBJ)) {
 print_r($result);
}

$dbh = NULL;
優點:
可以回傳欄位名稱的大小

但,實務上我們都用framework的DBI( database interface )來連資料庫,如ActiveRecord

參考資料:
http://blog.roga.tw/2010/06/%E6%B7%BA%E8%AB%87-php-mysql-php-mysqli-pdo-%E7%9A%84%E5%B7%AE%E7%95%B0/

1 則留言: