您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息
免费发信息

PDO如何处理SQL语句中对字段名以及表名的转义

2024/4/26 12:02:38发布6次查看
比如在一个数据表中有一个字段叫order,是专门用来做排序的,我的语句可能要这么写
$sth = $pdo->prepare('select * from table_name order by order asc');$sth->execute();

但是因为order本身是一个关键字,那么在执行的时候就会报syntax错误,我知道在pdo里对字段可以用:column_name来动态绑定,它会自动处理引号等问题,也可以用$pdo->quote来转义字符串,但是对字段名和表名却没有方法来转义。
这种转义在不同的数据库系统里是一样的,比如在mysql里
select * from table_name order by `order` asc

而在sqlite里
select * from table_name order by order asc

有没有一种通用而又省事的办法来处理这个问题呢
更新 根据答案最后总结出一种通用的转义方法
$escapes = array( 'mysql' => array('`', '`'), 'mssql' => array('[', ']'));$driver = $db->getattributes(pdo::attr_driver_name);$escape = isset($escapes[$driver]) ? $escapes[$driver] : array('', '');$field = $escape[0] . $field . $escape[1];

回复内容: 比如在一个数据表中有一个字段叫order,是专门用来做排序的,我的语句可能要这么写
$sth = $pdo->prepare('select * from table_name order by order asc');$sth->execute();

但是因为order本身是一个关键字,那么在执行的时候就会报syntax错误,我知道在pdo里对字段可以用:column_name来动态绑定,它会自动处理引号等问题,也可以用$pdo->quote来转义字符串,但是对字段名和表名却没有方法来转义。
这种转义在不同的数据库系统里是一样的,比如在mysql里
select * from table_name order by `order` asc

而在sqlite里
select * from table_name order by order asc

有没有一种通用而又省事的办法来处理这个问题呢
更新 根据答案最后总结出一种通用的转义方法
$escapes = array( 'mysql' => array('`', '`'), 'mssql' => array('[', ']'));$driver = $db->getattributes(pdo::attr_driver_name);$escape = isset($escapes[$driver]) ? $escapes[$driver] : array('', '');$field = $escape[0] . $field . $escape[1];

就我的经验来说,还真没有,遇到这种问题,也许你只能使用判断driver的方法来达到目的。你可以专门为此写个函数或者方法:
function add_quote_identifier($field, $driver = 'mysql'){ switch ($driver) { case 'mysql': return sprintf('`%s`', $field); case 'sqlite': return sprintf('%s', $field); default: return $field; }}
然后再利用他来prepare statement:
$stmt = $dbh->prepare(sprintf('select * from table_name order by %s asc', add_quote_identifier('order')));
结合 @chris yue 的方案,可以从连接实例里直接获取是什么driver:
// ...$driver = $db->getattributes(pdo::attr_driver_name);echo $driver; //如mysql
但我觉得更有建设性意义的问题是:“如何避免使用保留字”,因为不应该给不合法标识的存在提供便利:
首先说个与技术无关的方面:某些时候,“居然用了保留字”会成为话柄,对吧?这类情形我见了不少。既然都知道不要用保留字了,何苦呢?dba或者其他习惯用命令行、写大量sql的人,时不时还要留心字段转义,很闹心。各人的工具集不会完全统一,总有这种那种的备份或者分析工具没有自动转义,可能会导致时间、精力的浪费。rmdbs的版本(sql标准还总改呢)谁也穷举不了,所以各大orm经过讨论后都决定不做表名和字段的自动转义避免保留字很简单:
表名加个前缀就完了,比如gfw_之类的,谁这么缺德会用这个作为保留字?字段名应该经过一个设计文档来确认,或者至少大家有一个共同的地方去标注,在码很多代码之前就发现问题,并且逐渐积累成规范
chris yue的答案是见招拆招,可以帮助你解决历史遗留问题modi的答案是良好的设计规则,可以帮你在新项目中规避此类问题,相比之下,我更赞同这个答案,历史项目中的这类字段和表名,最好能够通过重构消灭掉。pdo不支持的特性还有很多,例如select * from table_name where id in (:id_lists)就是不支持的,所以后来我在lotusphp中不使用pdo的预处理特性了,改用自己的php方法来把sql语句完全当做字串模板处理,这有违预处理语句的初衷,是个无奈的选择。你既然选择了php与pdo,就最好使用它最可靠的特性,像modi说的那样,设计阶段就避开这些麻烦。mysql prepared statements其实是支持table名用占位符的,就像这样:select * from @table;set @table='sf_questions';
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录