ZF3 - Zend\Db\Sql\Predicate\Expression - 在 SQL DATE_FORMAT 上转义错误
ZF3 - Zend\Db\Sql\Predicate\Expression - Wrong escaping on SQL DATE_FORMAT
我正在尝试根据提交的会话开始时间过滤 radius 记帐数据库。 "acctstartime" 字段在 MySQL 数据库中定义为 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-string:
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
在文件 zend-db/src/Sql/Expression.php
的第 136 行:
$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;
}
}
那么"SUBSTRING(acctstarttime, 1, 10) = '"呢? substr($params->sessionStartTime, 0, 10) 。 “'”?
另一种方式,也许 "cleaner" 正在编写您自己的 class 并覆盖 getExpressionData
方法以不对值进行转义。例如:
use Zend\Db\Sql\Predicate\Expression;
public class NonEscapedExpression extends Expression
{
/**
* @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
]];
}
}
但请谨慎使用。
我正在尝试根据提交的会话开始时间过滤 radius 记帐数据库。 "acctstartime" 字段在 MySQL 数据库中定义为 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-string:
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
在文件 zend-db/src/Sql/Expression.php
的第 136 行:
$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;
}
}
那么"SUBSTRING(acctstarttime, 1, 10) = '"呢? substr($params->sessionStartTime, 0, 10) 。 “'”?
另一种方式,也许 "cleaner" 正在编写您自己的 class 并覆盖 getExpressionData
方法以不对值进行转义。例如:
use Zend\Db\Sql\Predicate\Expression;
public class NonEscapedExpression extends Expression
{
/**
* @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
]];
}
}
但请谨慎使用。