From 1d4cd8b123044f9760c44fae26575a86d1202f20 Mon Sep 17 00:00:00 2001
From: Jeremy Andrews <jeremy@tag1consulting.com>
Date: Sun, 21 Apr 2013 09:57:15 -0400
Subject: [PATCH] Issue 1613622 by Jeremy, markpavlitski, tzakrajs: properly
 hash keys >250 characters

---
 README.txt          | 11 +++++++++++
 dmemcache.inc       |  7 ++++---
 tests/memcache.test | 22 ++++++++++++++++++----
 3 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/README.txt b/README.txt
index 1d6555b..4f520ab 100644
--- a/README.txt
+++ b/README.txt
@@ -225,6 +225,17 @@ array of settings.php:
 
 $conf['memcache_key_prefix'] = 'something_unique';
 
+Note: if the length of your prefix + key + bin combine to be more than 250
+characters, they will be automatically hashed. Memcache only supports key
+lengths up to 250 bytes. You can optionally configure the hashing algorithm
+used, however sha1 was selected as the default because it performs quickly with
+minimal collisions.
+
+$conf['memcache_key_hash_algorithm'] = 'sha1';
+
+Visit http://www.php.net/manual/en/function.hash-algos.php to learn more about
+which hash algorithms are available.
+
 ## MULTIPLE SERVERS ##
 
 To use this module with multiple memcached servers, it is important that you set
diff --git a/dmemcache.inc b/dmemcache.inc
index be252ef..40e9db6 100644
--- a/dmemcache.inc
+++ b/dmemcache.inc
@@ -452,10 +452,11 @@ function dmemcache_key($key, $bin = 'cache') {
   $full_key = urlencode($prefix . $bin . '-' . $key);
 
   // Memcache only supports key lengths up to 250 bytes.  If we have generated
-  // a longer key, hash it with sha1 which will shrink the key down to 40 bytes
-  // while still keeping it unique.
+  // a longer key, we shrink it to an acceptible length with a configurable
+  // hashing algorithm. Sha1 was selected as the default as it performs
+  // quickly with minimal collisions.
   if (strlen($full_key) > 250) {
-    $full_key = $prefix . $bin . '-' . sha1($key);
+    $full_key = urlencode(hash(variable_get('memcache_key_hash_algorithm', 'sha1'), $prefix . $bin . '-' . $key));
   }
 
   return $full_key;
diff --git a/tests/memcache.test b/tests/memcache.test
index 6cce365..11f0e4c 100644
--- a/tests/memcache.test
+++ b/tests/memcache.test
@@ -158,13 +158,27 @@ class MemCacheSavingCase extends MemcacheTestCase {
     $this->assertTrue(isset($cache->data) && $cache->data == $test_object, t('Object is saved and restored properly.'));
   }
 
+  /**
+   * Test save and restoring a string with a long key.
+   */
+  function testStringLongKey() {
+    $this->checkVariable($this->randomName(100), 'ThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydogThequickbrownfoxjumpsoverthelazydog');
+  }
+
+  /**
+   * Test save and restoring a string using a key with special characters.
+   */
+  function testStringSpecialKey() {
+    $this->checkVariable($this->randomName(100), 'Qwerty!@#$%^&*()_+-=[]\;\',./<>?:"{}|£¢');
+  }
+
   /*
    * Check or a variable is stored and restored properly.
    **/
-  function checkVariable($var) {
-    cache_set('test_var', $var, 'cache');
-    $cache = cache_get('test_var', 'cache');
-    $this->assertTrue(isset($cache->data) && $cache->data === $var, t('@type is saved and restored properly.', array('@type' => ucfirst(gettype($var)))));
+  function checkVariable($var, $key = 'test_var') {
+    cache_set($key, $var, 'cache');
+    $cache = cache_get($key, 'cache');
+    $this->assertTrue(isset($cache->data) && $cache->data === $var, t('@type is saved and restored properly!key.', array('@type' => ucfirst(gettype($var)), '!key' => ($key != 'test_var') ? t(' with key @key', array('@key' => $key)) : '')));
   }
 }
 
-- 
GitLab