使用PDO并抓包分析


#乱炖


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

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

*图003*

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

*图004-1* *图004-2* *图004-3* *图004-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*

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

*图006-1* *图006-2* *图006-3* *图006-4*

图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

PDO的一些资料

PDO类

PDOStatement类

PHP数据对象



( 本文完 )