ThinkPHP框架安全实现分析(3)

protected function _parseOptions($options=array()) { //分析表达式 if(is_array($options)){ $options = array_merge($this->options,$options); } /*获取表名,此处省略*/ /*添加数据表别名,此处省略*/ $options['model'] = $this->name;// 记录操作的模型名称 /*对数组查询条件进行字段类型检查,如果在合理范围内,就进行过滤处理;否则抛出异常或者删除掉对应字段*/ if(isset($options['where']) && is_array($options['where']) && !empty($fields) && !isset($options['join'])){ foreach ($options['where'] as $key=>$val){ $key = trim($key); if(in_array($key,$fields,true)){ //如果$key在数据库字段内,过滤以及强制类型转换之 if(is_scalar($val)) { /*is_scalar 检测是否为标量。标量是指integer、float、string、boolean的变量,array则不是标量。*/ $this->_parseType($options['where'],$key); } }elseif(!is_numeric($key) && '_' != substr($key,0,1) && false === strpos($key,'.') && false === strpos($key,'(') && false === strpos($key,'|') && false === strpos($key,'&')){ // 如果$key不是数字且第一个字符不是_,不存在.(|&等特殊字符 if(!empty($this->options['strict'])){ //如果是strict模式,抛出异常 E(L('_ERROR_QUERY_EXPRESS_').':['.$key.'=>'.$val.']'); } unset($options['where'][$key]); //unset掉对应的值 } } } $this->options = array(); // 查询过后清空sql表达式组装 避免影响下次查询 $this->_options_filter($options); // 表达式过滤 return $options; }

本函数的结构大概是,先获取了表名,模型名,再对数据进行处理:如果该条数据不在数据库字段内,则做出异常处理或者删除掉该条数据。否则,进行_parseType处理。parseType此处不再跟进,功能为:数据类型检测,强制类型转换包括int,float,bool型的三种数据。

函数运行到此处,就该把处理好的数据传到db层的select函数里了。此时的查询条件$options中的int,float,bool类型的数据都已经进行了强制类型转换,where()函数中的字符串(非数组格式的查询)也进行了addslashes等处理。

继续追踪到select函数,就到了driver对象中了,还是先列举几个有用的成员变量:

// 数据库表达式 protected $exp = array('eq'=>'=','neq'=>'<>','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE','in'=>'IN','notin'=>'NOT IN','not in'=>'NOT IN','between'=>'BETWEEN','not between'=>'NOT BETWEEN','notbetween'=>'NOT BETWEEN'); // 查询表达式 protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%'; // 当前SQL指令 protected $queryStr = ''; // 参数绑定 protected $bind = array(); select函数: public function select($options=array()) { $this->model = $options['model']; $this->parseBind(!empty($options['bind'])?$options['bind']:array()); $sql = $this->buildSelectSql($options); $result = $this->query($sql,!empty($options['fetch_sql']) ? true : false); return $result; }

版本3.2.3经过改进之后,select精简了不少。parseBind函数是绑定参数,用于pdo查询,此处不表。

buildSelectSql()函数及其后续调用如下:

public function buildSelectSql($options=array()) { if(isset($options['page'])) { /*页码计算及处理,此处省略*/ } $sql = $this->parseSql($this->selectSql,$options); return $sql; } /* 替换SQL语句中表达式*/ public function parseSql($sql,$options=array()){ $sql = str_replace( array('%TABLE%','%DISTINCT%','%FIELD%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%','%UNION%','%LOCK%','%COMMENT%','%FORCE%'), array( $this->parseTable($options['table']), $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false), $this->parseField(!empty($options['field'])?$options['field']:'*'), $this->parseJoin(!empty($options['join'])?$options['join']:''), $this->parseWhere(!empty($options['where'])?$options['where']:''), $this->parseGroup(!empty($options['group'])?$options['group']:''), $this->parseHaving(!empty($options['having'])?$options['having']:''), $this->parseOrder(!empty($options['order'])?$options['order']:''), $this->parseLimit(!empty($options['limit'])?$options['limit']:''), $this->parseUnion(!empty($options['union'])?$options['union']:''), $this->parseLock(isset($options['lock'])?$options['lock']:false), $this->parseComment(!empty($options['comment'])?$options['comment']:''), $this->parseForce(!empty($options['force'])?$options['force']:'') ),$sql); return $sql; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/3d5b9b34bafaabb81a3c3006c253aa5c.html