TP model where条件丢失

最近我修复了一个bug,这个bug是用户能看到所有用户的数据,经过排查发现是where条件丢失,导致查询语句直接查了所有数据。

但是代码并没有问题,然后查到了 ThinkPHP/Library/Think/Model.class.php 的 _parseOptions 方法:

    /**
     * 分析表达式
     * @access protected
     * @param array $options 表达式参数
     * @return array
     */
    protected function _parseOptions($options=array()) {
        if(is_array($options))
            $options =  array_merge($this->options,$options);

        if(!isset($options['table'])){
            // 自动获取表名
            $options['table']   =   $this->getTableName();
            $fields             =   $this->fields;
        }else{
            // 指定数据表 则重新获取字段列表 但不支持类型检测
            $fields             =   $this->getDbFields();
        }

        // 数据表别名
        if(!empty($options['alias'])) {
            $options['table']  .=   ' '.$options['alias'];
        }
        // 记录操作的模型名称
        $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)){
                    if(is_scalar($val)) {
                        $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,'&')){
                    if(!empty($this->options['strict'])){
                        E(L('_ERROR_QUERY_EXPRESS_').':['.$key.'=>'.$val.']');
                    } 
                    unset($options['where'][$key]);
                }
            }
        }
        // 查询过后清空sql表达式组装 避免影响下次查询
        $this->options  =   array();
        // 表达式过滤
        $this->_options_filter($options);
        return $options;
    }

这是tp3封装的方法,在调用这个方法时,如果where条件中的字段,在表中不存在的话,就会删除这个条件,接着往下走,为什么明明表里有这个字段,却被判断为没有?

因为开启了字段缓存(不了解的可以去搜一下tp3字段缓存)。

正常来说开启字段缓存并不会出现这种问题,问题是出问题的这个model,和另一个接口模块的model重名了,开启字段缓存后,tp框架会根据model名将缓存文件存入  Application\Runtime\Data 目录下,结果虽然模块不同,但还是造成了缓存文件冲突,当 A model 先缓存时,在 A model 缓存文件未过期之前,B model 检测字段时会从 A model 缓存文件取,当没有检测到 B model 用到的字段时,就把where条件给删了。

三种解决办法:

1.重名model重命名。

2.关闭字段缓存(一般不会为了这种问题就关掉字段缓存,基本不考虑)。

3.在model内定义好要用的字段,这样这个model就不会再执行字段缓存,也不会再从字段缓存文件取:

新发现,tp3中 M('A') 和 D('A') 也会共享缓存文件,因此请尽量注意model命名,最好用表全称。

posted @ 2019-12-19 14:24  一剑还  阅读(818)  评论(0编辑  收藏  举报