• 技术文章 >后端开发 >php教程

    mysql - PHP PDO斜杠导致错误问题

    2016-06-06 20:22:59原创574
    使用PDO出现了一个问题,当字符的最后一个为\的时候插入数据库失败,很是费解,参数绑定怎么会出现如此的问题?

    error_reporting(E_ALL);
    header("content-type:text/html;charset=utf8");
    
    $params = array();
    
    $params[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES UTF8';
    
    $dsn = "mysql:host=localhost;dbname=test;port=3306;";
    $dbh = new PDO($dsn, 'root', '123456', $params);
    
    $sql = 'INSERT INTO `fav_ls_1` (`uid`,`fid`,`type`,`title_md5`,`title`,`url`,`order`,`addtime`) VALUES (:uid,:fid,:type,:title_md5,:title,:url,:order,:addtime)';
    $bind = array(
        ':uid' => 5919639,
        ':fid' => 0,
        ':type' => 1,
        ':title_md5' => "0886c9605d1424e656c85736b4730e7f",
        ':title' => '\\敌\\',
        ':url' => "http://www.2345.com/?ie",
        ':order' => 0,
        ':addtime' => 1449156098,
    );
    
    $sth = $dbh->prepare($sql);
    if(false===$sth->execute($bind))
    {
     print_r(  $sth->errorInfo () );
    }
    else
    {
        echo  $dbh->lastInsertId();
    }

    错误代码如下:

    Array ( [0] => 42000 [1] => 1064 [2] => You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'http://www.2345.com/?ie','0','1449156098')' at line 1 )

    补充一下:
    这个设置了$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);就可以运行了,但是在其他sql上也会出现莫名其妙的错误。

    回复内容:

    使用PDO出现了一个问题,当字符的最后一个为\的时候插入数据库失败,很是费解,参数绑定怎么会出现如此的问题?

    error_reporting(E_ALL);
    header("content-type:text/html;charset=utf8");
    
    $params = array();
    
    $params[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES UTF8';
    
    $dsn = "mysql:host=localhost;dbname=test;port=3306;";
    $dbh = new PDO($dsn, 'root', '123456', $params);
    
    $sql = 'INSERT INTO `fav_ls_1` (`uid`,`fid`,`type`,`title_md5`,`title`,`url`,`order`,`addtime`) VALUES (:uid,:fid,:type,:title_md5,:title,:url,:order,:addtime)';
    $bind = array(
        ':uid' => 5919639,
        ':fid' => 0,
        ':type' => 1,
        ':title_md5' => "0886c9605d1424e656c85736b4730e7f",
        ':title' => '\\敌\\',
        ':url' => "http://www.2345.com/?ie",
        ':order' => 0,
        ':addtime' => 1449156098,
    );
    
    $sth = $dbh->prepare($sql);
    if(false===$sth->execute($bind))
    {
     print_r(  $sth->errorInfo () );
    }
    else
    {
        echo  $dbh->lastInsertId();
    }

    错误代码如下:

    Array ( [0] => 42000 [1] => 1064 [2] => You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'http://www.2345.com/?ie','0','1449156098')' at line 1 )

    补充一下:
    这个设置了$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);就可以运行了,但是在其他sql上也会出现莫名其妙的错误。

    感谢king同学的答案:
    我的问题是PHP环境是大于5.3.6的,需要在dsn中设置charset=utf8,低于PHP5.3.6版本的使用SET NAMES UTF8
    修改代码如下解决:

    public function connect($config, $linkNum) 
    {
        if(empty($this->_link[$linkNum]))
        {
            if(empty($config)) $config = $this->config;
            
            $params = array();
            
            //  PHP<=5.3.6使用此方法设置编码
            if(!empty($config['db_charset']) && version_compare(PHP_VERSION,'5.3.6','<='))
                $params[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . $config['db_charset'];
            
            // 长链接
            if(isset($config['db_params']['pconnect']) && $config['db_params']['pconnect'] == true)
                $params[PDO::ATTR_PERSISTENT] = true;
            
            // @link http://zhangxugg-163-com.iteye.com/blog/1835721 5.3.6下有bug
            if(version_compare(PHP_VERSION,'5.3.6','<='))
                $params[PDO::ATTR_EMULATE_PREPARES]  =   false; // 禁用模拟预处理语句
            
            // php 5.3.6+在PDO的DSN中指定charset属性
            $dsn_charset = version_compare(PHP_VERSION, '5.3.6', '>') ? "charset={$config['db_charset']};" : '';
            
            $dsn = "{$config['db_type']}:dbname={$config['db_name']};host={$config['db_host']};port={$config['db_port']};" . $dsn_charset;
            $this->dbName = $config['db_name'];
            $this->dbType = $config['db_type'];
            
            try
            {
                $this->_link[$linkNum]  = new PDO($dsn, $config['db_user'], $config['db_pass'], $params);
                $this->_link[$linkNum]->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
                $this->_link[$linkNum]->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
            }
            catch(PDOException $e)
            {
                throw new CException($e->getMessage());
            }
        }
        
        $this->_linkId = $this->_link[$linkNum];
        return $this->_linkId;
    }

    注意,把ATTR_EMULATE_PREPARES设置为true并没有真正的用参数绑定功能,这只是模拟
    本来默认也是false,不明白为何你要开启它

    MySQL的参数绑定是通过prepare语句实现的,如果你的数据库版本支持(MySQL 4.1以上版本支持),不应该开启这个选项!

    你的问题很可能是因为这个模拟参数绑定,也就是本质上其实是通过转义实现的出现的错误(推测,未验证)

    请见
    http://php.net/manual/zh/pdo.setattribute.php

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:php mysql
    上一篇:php-fpm - OSX PHP56 nginx 服务器 权限问题,导致php链接500错误 下一篇:curl - PHP循环中发送邮件、网络请求问题
    千万级数据并发解决方案

    相关文章推荐

    • 用PHP实现自己的sha-256哈希算法!• PHP中的一些经验积累_PHP教程• 理解PHP中的MVC编程之控制器_PHP教程• PHP用代码实现文件下载_PHP教程• 成为优秀PHP开发人员做到的5件事_PHP教程
    1/1

    PHP中文网