ZF3-Zend \ Db \ Sql \ Predicate \ Expression-在SQL DATE_FORMAT上错误转义

问题描述 投票:0回答:2

我正在尝试根据提交的会话开始时间过滤半径计费数据库。在MySQL数据库中,字段“ acctstartime”定义为DATETIME。

这是我要构建的有效SQL查询:

SELECT * FROM radacct WHERE DATE_FORMAT(acctstarttime, '%Y-%m-%d') = DATE_FORMAT('2019-08-10' , '%Y-%m-%d') ORDER BY "radacctid" DESC LIMIT 100

在我的ZF3-Controller中,我正在使用Zend \ Db抽象层基于提交的参数来构建SQL查询。但不幸的是,Db层转义了%-Signs并生成了一个不起作用的SQL字符串:

SELECT * FROM radacct WHERE DATE_FORMAT(acctstarttime, '%%Y-%%m-%%d') = DATE_FORMAT('2019-01-01' , '%%Y-%%m-%%d') AND "acctstarttime" = '2019-01-01' ORDER BY "radacctid" DESC LIMIT 100

在第136行的文件zend-db/src/Sql/Expression.php中:

$expression = str_replace('%', '%%', $this->expression);

有人知道如何生成上面的查询吗?或者也许是做同样事情的另一种方法?我没有找到使用DATE_TIME的此类表达式的任何解决方法。


控制器:

class AccountingController extends AbstractRestfulJsonController {
    protected $service;

    public function __construct(RadiusService $service) {
        $this->service = $service;
    }

    public function get($id) {
        return $this->getList();
    }

    public function getList() {
        $viewModel = new JsonModel();

        try {
            $filter = [];
            $paramsRoute = $this->params()->fromRoute();
            $paramsQuery = $this->params()->fromQuery();
            $params = (OBJECT) array_merge($paramsRoute, $paramsQuery);

            if(isset($params->id)) {
                $filter['radacctid'] = (int) $params->id;
            }

            // ...

            if(isset($params->sessionStartTime) && strlen($params->sessionStartTime) > 0) {
                $filter[] = new Expression("DATE_FORMAT(acctstarttime, '%Y-%m-%d') = DATE_FORMAT('" . $params->sessionStartTime . "' , '%Y-%m-%d')");
            }

            // ...

            $data = $this->service->getAccounting($filter);

            $viewModel->setVariable('state', 'ok');
            $viewModel->setVariable('count', $data['totalItems']);
            $viewModel->setVariable('data', $data['items']);
        } catch (\Exception $e) {
            $viewModel->setVariable('state', 'nok');
            $viewModel->setVariable('message', $e->getMessage());
        }

        return $viewModel;
    }
}
mysql zend-db zend-framework3
2个回答
0
投票

所以“ SUBSTRING(acctstarttime,1,10)='”。 substr($ params-> sessionStartTime,0,10)。 “'”?


0
投票

[另一种方法,也许是“更清洁”的方法,是编写自己的类并重写getExpressionData方法以不转义值。例如:

    use Zend\Db\Sql\Predicate\Expression;

    public class NonEscapedExpression
    {
        /**
         * @return array
         * @throws Exception\RuntimeException
        */
        public function getExpressionData()
        {
            $parameters = (is_scalar($this->parameters)) ? [$this->parameters] : $this->parameters;
            $parametersCount = count($parameters);

            if ($parametersCount == 0) {
                return [
                    str_ireplace(self::PLACEHOLDER, '', $expression)
                ];
            }
            // assign locally, escaping % signs
            $expression = str_replace(self::PLACEHOLDER, '%s', $expression, $count);
            // test number of replacements without considering same variable begin used many times first, which is
            // faster, if the test fails then resort to regex which are slow and used rarely
            if ($count !== $parametersCount && $parametersCount === preg_match_all('/\:[a-zA-Z0-9_]*/', $expression)) {
                throw new Exception\RuntimeException(
                    'The number of replacements in the expression does not match the number of parameters'
                );
            }
            foreach ($parameters as $parameter) {
                list($values[], $types[]) = $this->normalizeArgument($parameter, self::TYPE_VALUE);
            }
            return [[
                $expression,
                $values,
                $types
            ]];
        }
    }

但是您应该小心使用它。

© www.soinside.com 2019 - 2024. All rights reserved.