Unverified Commit eabff8a8 authored by eileen's avatar eileen 🎱 Committed by GitHub

Merge pull request #12376 from totten/master-psr16-util

(#174) Add various utilities to support PSR-16
parents e427e3a4 a8d721eb
......@@ -214,4 +214,30 @@ class CRM_Utils_Cache {
throw new CRM_Core_Exception("Failed to instantiate cache. No supported cache type found. " . print_r($params, 1));
}
/**
* Assert that a key is well-formed.
*
* @param string $key
* @return string
* Same $key, if it's valid.
* @throws \CRM_Utils_Cache_InvalidArgumentException
*/
public static function assertValidKey($key) {
$strict = CRM_Utils_Constant::value('CIVICRM_PSR16_STRICT', FALSE) || defined('CIVICRM_TEST');
if (!is_string($key)) {
throw new CRM_Utils_Cache_InvalidArgumentException("Invalid cache key: Not a string");
}
if ($strict && !preg_match(';^[A-Za-z0-9_\-\. ]+$;', $key)) {
throw new CRM_Utils_Cache_InvalidArgumentException("Invalid cache key: Illegal characters");
}
if ($strict && strlen($key) > 255) {
throw new CRM_Utils_Cache_InvalidArgumentException("Invalid cache key: Too long");
}
return $key;
}
}
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 5 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2018 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* Class CRM_Utils_Cache_CacheException
*
* NOTE: PSR-16 specifies its exceptions using interfaces. For cache-consumers,
* it's better to catch based on the interface. For cache-drivers, we need
* a concrete class.
*/
class CRM_Utils_Cache_CacheException extends \CRM_Core_Exception implements \Psr\SimpleCache\CacheException {
}
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 5 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2018 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
* Class CRM_Utils_Cache_InvalidArgumentException
*
* NOTE: PSR-16 specifies its exceptions using interfaces. For cache-consumers,
* it's better to catch based on the interface. For cache-drivers, we need
* a concrete class.
*/
class CRM_Utils_Cache_InvalidArgumentException extends \CRM_Core_Exception implements \Psr\SimpleCache\InvalidArgumentException {
}
......@@ -51,6 +51,8 @@ trait CRM_Utils_Cache_NaiveMultipleTrait {
* or if any of the $keys are not a legal value.
*/
public function getMultiple($keys, $default = NULL) {
$this->assertIterable('getMultiple', $keys);
$result = [];
foreach ($keys as $key) {
$result[$key] = $this->get($key, $default);
......@@ -73,8 +75,13 @@ trait CRM_Utils_Cache_NaiveMultipleTrait {
* or if any of the $values are not a legal value.
*/
public function setMultiple($values, $ttl = NULL) {
$this->assertIterable('setMultiple', $values);
$result = TRUE;
foreach ($values as $key => $value) {
if (is_int($key)) {
$key = (string) $key;
}
$result = $this->set($key, $value, $ttl) || $result;
}
return $result;
......@@ -92,6 +99,8 @@ trait CRM_Utils_Cache_NaiveMultipleTrait {
* or if any of the $keys are not a legal value.
*/
public function deleteMultiple($keys) {
$this->assertIterable('deleteMultiple', $keys);
$result = TRUE;
foreach ($keys as $key) {
$result = $this->delete($key) || $result;
......@@ -99,4 +108,14 @@ trait CRM_Utils_Cache_NaiveMultipleTrait {
return $result;
}
/**
* @param $keys
* @throws \CRM_Utils_Cache_InvalidArgumentException
*/
private function assertIterable($func, $keys) {
if (!is_array($keys) && !($keys instanceof Traversable)) {
throw new CRM_Utils_Cache_InvalidArgumentException("$func expects iterable input");
}
}
}
......@@ -695,6 +695,58 @@ class CRM_Utils_Date {
return TRUE;
}
/**
* Translate a TTL to a concrete expiration time.
*
* @param NULL|int|DateInterval $ttl
* @param int $default
* The value to use if $ttl is not specified (NULL).
* @return int
* Timestamp (seconds since epoch).
* @throws \CRM_Utils_Cache_InvalidArgumentException
*/
public static function convertCacheTtlToExpires($ttl, $default) {
if ($ttl === NULL) {
$ttl = $default;
}
if (is_int($ttl)) {
return time() + $ttl;
}
elseif ($ttl instanceof DateInterval) {
return date_add(new DateTime(), $ttl)->getTimestamp();
}
else {
throw new CRM_Utils_Cache_InvalidArgumentException("Invalid cache TTL");
}
}
/**
* Normalize a TTL.
*
* @param NULL|int|DateInterval $ttl
* @param int $default
* The value to use if $ttl is not specified (NULL).
* @return int
* Seconds until expiration.
* @throws \CRM_Utils_Cache_InvalidArgumentException
*/
public static function convertCacheTtl($ttl, $default) {
if ($ttl === NULL) {
return $default;
}
elseif (is_int($ttl)) {
return $ttl;
}
elseif ($ttl instanceof DateInterval) {
return date_add(new DateTime(), $ttl)->getTimestamp() - time();
}
else {
throw new CRM_Utils_Cache_InvalidArgumentException("Invalid cache TTL");
}
}
/**
* @param null $timeStamp
*
......
......@@ -399,6 +399,14 @@ if (!defined('CIVICRM_DB_CACHE_PREFIX')) {
define('CIVICRM_DB_CACHE_PREFIX', '');
}
/**
* The cache system traditionally allowed a wide range of cache-keys, but some
* cache-keys are prohibited by PSR-16.
*/
if (!defined('CIVICRM_PSR16_STRICT')) {
define('CIVICRM_PSR16_STRICT', FALSE);
}
/**
* If you have multilingual site and you are using the "inherit CMS language"
* configuration option, but wish to, for example, use fr_CA instead of the
......
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 5 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2018 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License along with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
require_once 'Cache/IntegrationTests/LegacySimpleCacheTest.php';
/**
* Verify that a cache service complies with PSR-16.
*
* @group e2e
*/
abstract class E2E_Cache_CacheTestCase extends \Cache\IntegrationTests\LegacySimpleCacheTest implements \Civi\Test\EndToEndInterface {
const MAX_KEY = 255;
public static function setUpBeforeClass() {
CRM_Core_Config::singleton(1, 1);
CRM_Utils_System::loadBootStrap(array(
'name' => $GLOBALS['_CV']['ADMIN_USER'],
'pass' => $GLOBALS['_CV']['ADMIN_PASS'],
));
CRM_Utils_System::synchronizeUsers();
parent::setUpBeforeClass();
}
public function testBasicUsageWithLongKey() {
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
}
// Upstream test hardcodes 300, which is more permissive than PSR-16.
$key = str_repeat('a', self::MAX_KEY);
$this->assertFalse($this->cache->has($key));
$this->assertTrue($this->cache->set($key, 'value'));
$this->assertTrue($this->cache->has($key));
$this->assertSame('value', $this->cache->get($key));
$this->assertTrue($this->cache->delete($key));
$this->assertFalse($this->cache->has($key));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment