文档章节

为什么说PHP必须要用PDO?

金拱门
 金拱门
发布于 2014/06/13 09:55
字数 1572
阅读 1184
收藏 11
点赞 1
评论 9

根据PHP官方计划,PHP6正式到来之时,数据库链接方式统一为PDO。但是总有一小撮顽固分子,趁PHP官方还没正式统一时,还用老式的MYSQL驱动链接数据库。即使现在有部分程序改用Mysqli/pdo,只要没用到预编译,均和老式的Mysql驱动没多大区别。在此,我就不点评国内的PHP生态环境了。

回归主题,为什么说PHP必须要用PDO?除了官方要求之外,我认为作为PHP程序员,只要你目前是做开发的话,那么请选择用PDO的程序/框架!PDO除了安全和万金油式数据库链接,还有一点是我目前觉得非常好用的!下面我就用我最近的切身体会来说。

业务环境:公司某老架构,数据库设计的人员太菜了,设计过程完全没有按照数据库范式进行。各种表中使用大量的序列化形式保存(补充:json同理)。

出现问题:销售的客服反馈,网站某用户在编辑地址时,Mysql报错了。

问题猜想:不用说了。肯定是引号,反斜杠引起序列化入库不正常。

下面就来正题,由于涉及到公司的机密。我就模拟一下当时的业务环境。

用户提交的数据以下面数组形式显示:

        $array = array(
            'firstname' => 'Orthopedics',
            'lastname' => "O\"\\s\\'\'\'\''''china\\\'dddddd",
            'address' => "Oschina net s'e'x"
        );

上述数据为了数据的直白性,我加了一些反斜杠了单引号。实际上用户是在地址是输入了类似:Los Angeles Highway's 52。

正常来说,老式的程序都对数据进行addslashes函数过滤处理。数组就是下面这个形式了:

$array = array(
    'firstname' => 'Orthopedics',
    'lastname' => addslashes("O\"\\s\\'\'\'\''''china\\\'dddddd"),
    'address' => addslashes("Oschina net s'e'x")
);

上面数据是非常典型的PHP写法了!用户提交什么数据,我都给你过滤。

接着,上文已经说过了,数据库很多地方都以序列化的形式保存。所以,下面插入数据库的代码就类似这样了。

$content = serialize($array);
$sql = "INSERT INTO  `test`.`test` (`content`)
    VALUES ('{$content}')";
$res = mysql_query($sql);

恩,很好。看似一个完整的安全过滤系统,什么注入漏洞都跑不过我的法眼。上面的插入语句是正确,并插入了数据!

可是,当系统要读取用户数据时,哈哈!百分百出问题!下面再来段数据读取的代码。

$sql = "select * from test";
$res = mysql_query($sql);
$temp = array();
while ($row = mysql_fetch_array($res)) {
    echo "入库后的序列化: {$row['content']}<br />";
    echo "还原序列化数组:<br />";
    print_r(unserialize($row['content']));
}

为了给大家验证数据的统一性,我就做了一些数据打印,方便大家理解和阅读。下面就是整个程序的执行结果截图。

很好!从数据库读取序列化保存数据 和 原本的序列化数据 已经不一致了!导致这种现象,是由于数据过滤后,入库时数据库误以为这玩意是用来转义的。 

上面这样说太抽象了,来个实例的:数据序列化时,

s:7:"fuck\'u"

上面的fuck\'s 长度为 7。但是入库时,\' 会被转义成 ' !再从库里面读取的话,那么长度已经不一致了。序列化也必然是失败的!

导致这种奇葩的现象,除了数据库设计不当,还有是因为老式的程序架构中,数据都是先做过滤,在入库导致的。当然,如果你不过滤数据,先序列化再入库的话,要是用户提交 反斜杠\ , 依旧可能会出现这种 破问题。

至于要解决这种问题,我有几个方案:

  1. 选用PDO。 后文我再说实例。

  2. 序列化后的数据,再做base64保存。

  3. 序列化的数据尽量剔除掉单引号,反斜杠等歧义字符。

  4. 改表结构吧。序列化之类的数据,只用于保存一些不常用的东西(后台数据为主)。

文章最后,我就来介绍本文的主角,PDO。 

由于PDO使用预编译的形式进行操作数据库,因此只要不是底层的漏洞(php 5.3.8之前的PDO存在漏洞),可以100%抵挡注入漏洞!具体的说明,看客自行谷歌吧。

得益于PDO的安全机制,在操作刚才的业务环境,用户提交的数据,我们几乎不用作任何处理(注意XSS还是必须的)!下面是基于我写的PDO类库进行操作的代码。

    public function fuck() {
        $array = array(
            'firstname' => 'Orthopedics',
            'lastname' => "O\"\\s\\'\'\'\''''china\\\'dddddd",
            'address' => "Oschina net s'e'x"
        );

        $content = serialize($array);
        echo '<pre>';
        echo "原始数组:<br />";
        print_r($array);
        echo "原始序列化: {$content}<br/>";

        $db = $this->db('test');
        $result = $db->add(array('content' => $content));

        $select = $db->select();

        foreach ($select as $key => $value) {
            echo "入库后的序列化: {$value['content']}<br />";
            echo "还原序列化数组:<br />";
            print_r(unserialize($value['content']));
        }

        $result = $db->delete();
    }

效果截图如下:

无论数据有多恶劣,什么单引号,双引号啊,斜杠,反斜杠。。。PDO均轻易地解决!

文章末尾,用PDO是势在必行的!每一位PHPer,只要你觉得可以,请大胆向领导说,艹,公司架构应该换PDO了!程序员何苦为难程序员呢?有空大家多多看看乌云的漏洞,现在PHP和当年的asp安全形势已经相差不大了,这可是一个危险的警钟!如果你不想PHP成为下一代asp,请从现在开始,数据库都用上PDO吧!顺道吐槽一下:我发现公司的几个网站的代码已经有点变得不可控了。哈哈,太逗了。

© 著作权归作者所有

共有 人打赏支持
金拱门

金拱门

粉丝 371
博文 6
码字总数 3303
作品 7
广州
程序员
加载中

评论(9)

金拱门
金拱门

引用来自“mark35”的评论

lz所说的安全以及业务上的理由其实都和PDO没关系。用原生驱动照样可以实现同样效果的。PDO的优点是方便切换数据库,不过对于商用系统不可能让你随便更换数据库的。就和java宣传的一次编译各处运行一样其实意义不大
你这样理解也没错。但别忽略了一点,用mysql驱动形式编写的程序,很容易就产生注入的漏洞。因为新来的未必知道程序的安全机制。而选择了 预编译的 pdo或者mysqli,只需要开发人员知道预编译就杜绝了注入的产生。这才是最重要的。 拿一个典型的例子来说吧,当年用TP框架。他们本身就有安全机制。当时我也没怎么懂他们的文档是怎样说安全过滤的。于是我有自己写了一个安全过滤机制。 每次数据过滤都的去担心这会不会有注入。 这就是我认为为什么要用PDO的原因之一了。
mark35
mark35
lz所说的安全以及业务上的理由其实都和PDO没关系。用原生驱动照样可以实现同样效果的。PDO的优点是方便切换数据库,不过对于商用系统不可能让你随便更换数据库的。就和java宣传的一次编译各处运行一样其实意义不大
SimonYe
SimonYe

引用来自“都市网达”的评论

PDO的优点还有可以迁移数据库,我认为最大的优点还是自带的异常捕获。
还有事务处理
乌龟壳
乌龟壳
我没用过mysql的驱动,postgres有pg_prepare,pg_query_params,oracle有oci_parse,oci_bind_*,入库的时候根本不用操心怎么转义。出库的时候加上html_special_char防注入就行了。为什么原生的驱动不死,就是因为PDO没办法抽象一些数据库不共有的功能,这些功能放弃了就白花很多冤枉钱在数据库上了。
都市网达
都市网达
PDO的优点还有可以迁移数据库,我认为最大的优点还是自带的异常捕获。
金拱门
金拱门

引用来自“张敏峰”的评论

// 试试这个函数 mb_unserialize 还有 mysqli_real_escape_string() 函数
function mb_unserialize($serial_str) { // 修正unserialize在处理某些字串编码时返回 Error at offset 问题
$out = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $serial_str );
return unserialize($out);
}
谢指点了。 入库前用addslashes 肯定不周全的,还是过滤HTML标签。不考虑数据库特殊的编码环境的话,老式的过滤手法都是这样,外加 对 数据进行 关键词检测的。
BossKiller
BossKiller
入MySQL数据库前的转义用 addslashes 是不周全的
BossKiller
BossKiller
// 试试这个函数 mb_unserialize 还有 mysqli_real_escape_string() 函数
function mb_unserialize($serial_str) { // 修正unserialize在处理某些字串编码时返回 Error at offset 问题
$out = preg_replace('!s:(\d+):"(.*?)";!se', "'s:'.strlen('$2').':\"$2\";'", $serial_str );
return unserialize($out);
}
AzusaK
AzusaK
1年前已经使用pdo,安全与方便是没得说...
PHP中使用PDO连接SQL Server

注意,本文告诉你如何更好的用pdo连接sql server 2005 而不是 2000。(MSSQL2000可以直接应用PHP内置函数或直接调用PDO,另外如果应用PDO连接MSSQL 2000,需要将PHP 文件目录下的ntwdblib.dl...

Junn
2014/03/03
0
0
linux环境php调用sqlServer2000存储过程遇到的问题

  在linux环境中用php查询sql server并不是很常见的需求.一般来说如果一定要用sql server,编程语言我会先c#;如果一定要用php,数据库我就选mysql.   这几天的开发中,需要从一个非开源的e...

吕明明
2013/03/14
0
0
PDO防注入原理分析以及使用PDO的注意事项

我们都知道,只要合理正确使用PDO,可以基本上防止SQL注入的产生,本文主要回答以下两个问题: 为什么要使用PDO而不是mysql_connect? 为何PDO能防注入? 使用PDO防注入的时候应该特别注意什么...

月影又无痕
2013/07/30
0
7
PHP PDO在SWOOLE模式下关闭数据库连接一些注意点

最近在swoole中使用php pdo扩展访问数据库的时候,发现了一个很有意思的事情。 我测试用的版本是 PHP 7.1.13 官方手册明确到告诉我们,使用PDO是这样关闭数据库连接的,只需要将PDO对象置为n...

anoty
02/11
2
0
php PDO数据库操作 方法应用 bindColumn bindParam bindValue

php PDO数据库操作 方法应用 bindColumn bindParam bindValue 问题1: 为什么要用PDO抽象层? 问题2:这三个方法之间有什么不同 为什么要做绑定操作 ? 问题3: PDO是不是重复性更好?...

鬼谷子灬
2015/07/05
446
2
PDO

PDO 一、什么是PDO PDO是PHP数据对象(PHP Data Object)的缩写 二、怎么查看php是否支持PDO 1. 使用phpinfo() 函数查看PDO是否支持 2. 如果没有开启PDO 请查看 wamp目录:(C:wampbinphpphp7.0....

方花
2017/11/21
0
0
PHP自动加载实用技巧

0.为什么需要单入口? 原因很简单,需要确保自动加载类的函数注册成功。单入口确保这点的一种简单实现。设置好重写URL;一个入口PHP文件(常见的是各大框架的index.php);自动加载使用splau...

大止刀口
2016/04/12
27
0
泷涯/SYFramework

English SYFramework 此框架是原为泷涯自用,现开源,框架基本遵循Module、Model、Controller、View的分层 目前最新稳定版本为,最新测试版本为 此项目基于Apache License 2.0开源 查看文档 ...

泷涯
2015/10/19
0
0
还是php框架pdo预处理类的问题

别人的框架使用多了,对基本语法和底层原理会有点生疏.一直更新的自己的一个小框架,不断的扩充和修正.想把数据操作类升级成pdo预处理的.有人推介medoo,挺小巧的,但是我看到源码中增删改查方法...

manbudezhu
2016/07/26
214
0
linux安装php程序magento提示pdo_mysql组件未安装,单安装之后仍无效,求解

我买了国外的linux服务器,安装php程序magento的时候,提示pdo_mysql组件未安装,如下错误提示: There has been an error processing your requestpdo_mysql extension is not installed Tr...

闫军
2012/02/06
2.5K
5

没有更多内容

加载失败,请刷新页面

加载更多

下一页

用axios.all处理并发请求

如果我们需用在两个接口同时完成后在执行一些逻辑,我们可以使用axios.all处理并发请求: function getUserAccount() { return axios.get('/user/12345');}function getUserPermissio...

JamesView
34分钟前
0
0
SpringCloud 微服务 (十六) 服务追踪 Zipkin

问题 在服务中,有一个接口,该A接口中又调用了其他服务的B、C、D接口,出现一个请求耗时大的问题,这时候并不知道该B、C、D接口中哪个接口造成的耗时量,然后比如确定C服务接口出现的耗时量大,但...

___大侠
45分钟前
0
0
Java面试基础篇——第八篇:抽象类与接口的区别

1.抽象类 抽象类:如果一个类中包含有抽象方法,或这个类使用abstract关键字修饰,则称这个类是抽象类。 抽象方法是什么呢?抽象方法就是指用abstract关键字修饰的方法。 需要注意的是:抽象...

developlee的潇洒人生
今天
2
0
jsoup 相关资料

1.jsoup 2.Jsoup概述 3.jsoup入门 4.jsoup Java HTML Parser 1.11.3 API

IT追寻者
今天
0
0
JPA @MappedSuperclass 注解说明

基于代码复用和模型分离的思想,在项目开发中使用JPA的@MappedSuperclass注解将实体类的多个属性分别封装到不同的非实体类中。 1.@MappedSuperclass注解只能标准在类上:@Target({java.lang....

海博1600
今天
0
0
【一】Scala Configuration 相关API

Play使用了 Typesafe config library,但是也提供了一个有着更多Scala高级特性的的 Configuration 封装。不熟悉Typesafe配置的开发者可以移步 configuration文件的语法和特性文档。 读取配置...

Landas
今天
3
0
使用cookie技术 记住账号

1. 效果 2. 实现过程 2.1 前端 将用户的选中传递给后台 这个参数的获取是 参考:https://my.oschina.net/springMVCAndspring/blog/1860498 // var rememberLogin = $("#rememberLoginId").i...

Lucky_Me
今天
1
0
《趣谈网络协议》02之网络分层的真实含义

一、提出问题 1.提出问题 当你听到什么二层设备、三层设备、四层 LB 和七层 LB 中层的时候,是否有点一头雾水,不知道这些所谓的层,对应的各种协议具体要做什么“工作”? 2.这四个问题你弄...

aibinxiao
今天
2
0
Python3学习日志二 Python中的集合set和字典dict

1.集合set 定义一个集合set 我们可以看到定义集合set有两种不同的形式,如果要定义一个空的集合set不能用{}而是要用set();另外,集合是无序的,而且set中的元素是不可重复的,如果你定义了一...

Mr_bullshit
今天
0
0
adb 操作指令详解

ADB,即 Android Debug Bridge,它是 Android 开发/测试人员不可替代的强大工具,也是 Android 设备玩家的好玩具。 注:有部分命令的支持情况可能与 Android 系统版本及定制 ROM 的实现有关。...

孟飞阳
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部