2013-11-27
PDO是什么?
PHP Data Objects (PDO) is an interface for accessing databases.
创建table
先在MySQL5的数据库test下创建users表:
CREATE TABLE `test`.`users` (
`id` INT NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(45) NOT NULL ,
`email` VARCHAR(45) NOT NULL ,
`passwd` VARCHAR(45) NOT NULL ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `name_UNIQUE` (`name` ASC)
) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;
创建文件connection.php
connection.php内容如下:
<?php
$dsn = 'mysql:dbname=test;host=127.0.0.1';
$user = 'root';
$password = '123456';
try {
$db = new PDO($dsn, $user, $password);
$db->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
将PDO::ATTR_EMULATE_PREPARES
属性设置为false,是为了禁止PDO只是在语法上模仿预处理。
创建文件insert1.php
insert1.php内容如下:
<?php
include_once 'connection.php';
$user1 = ['id' =--> 1,'name' => 'a', 'email' => 'a@163.com', 'passwd' => 'aaa'];
$user2 = ['id' => 2,'name' => 'b', 'email' => 'b@163.com', 'passwd' => 'bbb'];
$db->exec("DELETE FROM users;");
$stmt = $db->prepare("INSERT INTO users (id, name, email, passwd) VALUES (:id, :name, :email, :passwd)");
$stmt->bindParam(':id', $user1['id']);
$stmt->bindParam(':name', $user1['name']);
$stmt->bindParam(':email', $user1['email']);
$stmt->bindParam(':passwd', $user1['passwd']);
$stmt->execute();
$stmt = $db->prepare("INSERT INTO users (id, name, email, passwd) VALUES (:id, :name, :email, :passwd)");
$stmt->bindParam(':id', $user2['id']);
$stmt->bindParam(':name', $user2['name']);
$stmt->bindParam(':email', $user2['email']);
$stmt->bindParam(':passwd', $user2['passwd']);
$stmt->execute();
执行命令:
sudo tcpdump -i lo 'port 3306' -w insert1.cap
运行insert1.php:
php insert1.php
用wireshark分析insert1.cap文件。可以看到叫做MySQL的协议。

图001
上图显示了授权的过程。展开上图中的第一个数据包,能够看到下面的信息:
.....
Charset: latin1 COLLATE latin1_swedish_ci (8)
Username: root
Password: ************
Schema: test
.....
注:Password后是密码加密后的字符,这里用*代替了。图001的第三个数据包的内容如下:

图002
我们在插入第一个用户的信息时候,经过了以下过程:

图004-1、图004-2、图004-3、图004-4分别是[1]、[2]、[3]、[4]这四个包的具体信息。




创建文件insert2.php
这次看一下事务的数据包,insert2.php内容如下:
<?php
include_once 'connection.php';
$user1 = ['id' =--> 1,'name' => 'a', 'email' => 'a@163.com', 'passwd' => 'aaa'];
$db->exec("DELETE FROM users;");
$db->beginTransaction();
$stmt = $db->prepare("INSERT INTO users (id, name, email, passwd) VALUES (:id, :name, :email, :passwd)");
$stmt->bindParam(':id', $user1['id']);
$stmt->bindParam(':name', $user1['name']);
$stmt->bindParam(':email', $user1['email']);
$stmt->bindParam(':passwd', $user1['passwd']);
$stmt->execute();
$db->commit();
准备抓包:
sudo tcpdump -i lo 'port 3306' -w insert2.cap
运行insert2.php:
php insert2.php
使用wireshark分析数据包insert2.cap,这个事务过程大致如下:


图005的8个主要过程的具体信息分别对应006-1到 006-8:





图006-5

图006-6

图006-7

图006-8
注意到在图006-2中server status的In transaction位被设置为了1。
创建文件select1.php
select1.php内容如下:
<?php
include_once 'connection.php';
$stmt = $db->prepare("SELECT * FROM users;");
if ($stmt->execute()) {
print_r($stmt->fetchAll());
}
先运行insert2.php:
php insert2.php
执行命令以抓包:
sudo tcpdump -i lo 'port 3306' -w select1.cap
运行select1.php:
php select1.php
运行结果如下:
Array
(
[0] => Array
(
[id] => 1
[0] => 1
[name] => a
[1] => a
[email] => a@163.com
[2] => a@163.com
[passwd] => aaa
[3] => aaa
)
)
fetchAll()函数产生的数据包的内容如下:

图007-1

图007-2

图007-3

图007-4