From d32d065dbcfd0cfe8c12386661631a227970178c Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Fri, 22 Apr 2016 15:12:49 -0700 Subject: [PATCH] CRM-18193 - CRM_Logging_Differ - Improve interval checking a. This validates the interval in the constructor. Previously, there were two different functions which consumed the interval, but only one of them validated. b. My brain does not understand what it means to addslashes for an interval expression. This validation is based on the docs from mysql.com. --- CRM/Logging/Differ.php | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/CRM/Logging/Differ.php b/CRM/Logging/Differ.php index f58ebc8373..2d46a9bf04 100644 --- a/CRM/Logging/Differ.php +++ b/CRM/Logging/Differ.php @@ -50,7 +50,7 @@ class CRM_Logging_Differ { $this->db = $dsn['database']; $this->log_conn_id = $log_conn_id; $this->log_date = $log_date; - $this->interval = $interval; + $this->interval = self::filterInterval($interval); } /** @@ -144,10 +144,6 @@ LEFT JOIN civicrm_activity_contact source ON source.activity_id = lt.id AND sour $logDateClause = ''; if ($this->log_date) { $params[2] = array($this->log_date, 'String'); - // The format of $this->interval should be something like 10 SECOND. It should not have any ' - // characters so we don't want to declare it as a string & have them added. But if someone - // adds a ' then we want to neuter it. - $this->interval = addslashes($this->interval); $logDateClause = " AND lt.log_date BETWEEN DATE_SUB(%2, INTERVAL {$this->interval}) AND DATE_ADD(%2, INTERVAL {$this->interval}) "; @@ -481,4 +477,34 @@ ORDER BY log_date } + /** + * Filter a MySQL interval expression. + * + * @param string $interval + * @return string + * Normalized version of $interval + * @throws \CRM_Core_Exception + * If the expression is invalid. + * @see https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-add + */ + private static function filterInterval($interval) { + if (empty($interval)) { + return $interval; + } + + $units = array('MICROSECOND', 'SECOND', 'MINUTE', 'HOUR', 'DAY', 'WEEK', 'MONTH', 'QUARTER', 'YEAR'); + $interval = strtoupper($interval); + if (preg_match('/^([0-9]+) ([A-Z]+)$/', $interval, $matches)) { + if (in_array($matches[2], $units)) { + return $interval; + } + } + if (preg_match('/^\'([0-9: \.\-]+)\' ([A-Z]+)_([A-Z]+)$/', $interval, $matches)) { + if (in_array($matches[2], $units) && in_array($matches[3], $units)) { + return $interval; + } + } + throw new CRM_Core_Exception("Malformed interval"); + } + } -- 2.25.1