• 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名将缓存文件存入  ApplicationRuntimeData 目录下,结果虽然模块不同,但还是造成了缓存文件冲突,当 A model 先缓存时,在 A model 缓存文件未过期之前,B model 检测字段时会从 A model 缓存文件取,当没有检测到 B model 用到的字段时,就把where条件给删了。

    解决办法:

    1.重名model重命名。

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

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

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

  • 相关阅读:
    Android开发之Toast的快去替换
    Android开发之Fragment的替换显示反复创建问题
    Android开发之多渠道打包
    Android开发之让其他软件调用自己播放器
    Android开发之的到屏幕的宽和高
    Android开发之视频播放调用setVideoPath()方法
    [luogu4931]情侣?给我烧了!
    CF449D Jzzhu and Numbers
    [PKUWC2018]猎人杀
    [BZOJ3028]食物
  • 原文地址:https://www.cnblogs.com/yuanshen/p/12067561.html
Copyright © 2020-2023  润新知