diff --git a/framework/yii/db/redis/Connection.php b/framework/yii/db/redis/Connection.php index 781701b..b99c52b 100644 --- a/framework/yii/db/redis/Connection.php +++ b/framework/yii/db/redis/Connection.php @@ -371,7 +371,7 @@ class Connection extends Component array_unshift($params, $name); $command = '*' . count($params) . "\r\n"; foreach($params as $arg) { - $command .= '$' . strlen($arg) . "\r\n" . $arg . "\r\n"; + $command .= '$' . mb_strlen($arg, '8bit') . "\r\n" . $arg . "\r\n"; } \Yii::trace("Executing Redis Command: {$name}", __CLASS__); @@ -382,11 +382,11 @@ class Connection extends Component private function parseResponse($command) { - if(($line = fgets($this->_socket))===false) { + if(($line = fgets($this->_socket)) === false) { throw new Exception("Failed to read from socket.\nRedis command was: " . $command); } $type = $line[0]; - $line = substr($line, 1, -2); + $line = mb_substr($line, 1, -2, '8bit'); switch($type) { case '+': // Status reply @@ -400,10 +400,16 @@ class Connection extends Component if ($line == '-1') { return null; } - if(($data = fread($this->_socket, $line + 2))===false) { - throw new Exception("Failed to read from socket.\nRedis command was: " . $command); + $length = $line + 2; + $data = ''; + while ($length > 0) { + if(($block = fread($this->_socket, $line + 2)) === false) { + throw new Exception("Failed to read from socket.\nRedis command was: " . $command); + } + $data .= $block; + $length -= mb_strlen($block, '8bit'); } - return substr($data, 0, -2); + return mb_substr($data, 0, -2, '8bit'); case '*': // Multi-bulk replies $count = (int) $line; $data = array(); diff --git a/tests/unit/framework/caching/RedisCacheTest.php b/tests/unit/framework/caching/RedisCacheTest.php index a92be09..0924d0f 100644 --- a/tests/unit/framework/caching/RedisCacheTest.php +++ b/tests/unit/framework/caching/RedisCacheTest.php @@ -7,7 +7,7 @@ use yiiunit\TestCase; /** * Class for testing redis cache backend */ -class RedisCacheTest extends CacheTest +class RedisCacheTest extends CacheTestCase { private $_cacheInstance = null; @@ -20,6 +20,7 @@ class RedisCacheTest extends CacheTest 'hostname' => 'localhost', 'port' => 6379, 'database' => 0, + 'dataTimeout' => 0.1, ); $dsn = $config['hostname'] . ':' .$config['port']; if(!@stream_socket_client($dsn, $errorNumber, $errorDescription, 0.5)) { @@ -42,4 +43,41 @@ class RedisCacheTest extends CacheTest usleep(300000); $this->assertFalse($cache->get('expire_test_ms')); } + + /** + * Store a value that is 2 times buffer size big + * https://github.com/yiisoft/yii2/issues/743 + */ + public function testLargeData() + { + $cache = $this->getCacheInstance(); + + $data=str_repeat('XX',8192); // http://www.php.net/manual/en/function.fread.php + $key='bigdata1'; + + $this->assertFalse($cache->get($key)); + $cache->set($key,$data); + $this->assertTrue($cache->get($key)===$data); + + // try with multibyte string + $data=str_repeat('ЖЫ',8192); // http://www.php.net/manual/en/function.fread.php + $key='bigdata2'; + + $this->assertFalse($cache->get($key)); + $cache->set($key,$data); + $this->assertTrue($cache->get($key)===$data); + } + + public function testMultiByteGetAndSet() + { + $cache = $this->getCacheInstance(); + + $data=array('abc'=>'ежик',2=>'def'); + $key='data1'; + + $this->assertFalse($cache->get($key)); + $cache->set($key,$data); + $this->assertTrue($cache->get($key)===$data); + } + } \ No newline at end of file