summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Machniak <alec@alec.pl>2013-06-02 14:33:11 +0200
committerAleksander Machniak <alec@alec.pl>2013-06-02 14:33:11 +0200
commita6b0ca60a431b8e56d7c23246de71978d6968a79 (patch)
tree65d06e18eb4fdbc72b275f4003b1f6d03c318016
parentd77e08729b812333bc22680c4072a6e41f4ba40e (diff)
Fix bug where serialized strings were truncated in PDO::quote() (#1489142)
-rw-r--r--CHANGELOG1
-rw-r--r--program/lib/Roundcube/rcube_cache.php33
-rw-r--r--program/lib/Roundcube/rcube_cache_shared.php32
-rw-r--r--program/lib/Roundcube/rcube_db.php23
-rw-r--r--program/lib/Roundcube/rcube_imap_cache.php12
5 files changed, 82 insertions, 19 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 0af5ff1b9..74d7d84cc 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail
===========================
+- Fix bug where serialized strings were truncated in PDO::quote() (#1489142)
- Improved handling of Reply-To/Bcc addresses of identity in compose form (#1489016)
- Fix displaying messages with invalid self-closing HTML tags (#1489137)
- Fix PHP warning when responding to a message with many Return-Path headers (#1489136)
diff --git a/program/lib/Roundcube/rcube_cache.php b/program/lib/Roundcube/rcube_cache.php
index 129f3242d..08c9fc8a9 100644
--- a/program/lib/Roundcube/rcube_cache.php
+++ b/program/lib/Roundcube/rcube_cache.php
@@ -145,7 +145,7 @@ class rcube_cache
*/
function write($key, $data)
{
- return $this->write_record($key, $this->packed ? serialize($data) : $data);
+ return $this->write_record($key, $this->serialize($data));
}
@@ -219,7 +219,7 @@ class rcube_cache
if ($this->cache_changes[$key]) {
// Make sure we're not going to write unchanged data
// by comparing current md5 sum with the sum calculated on DB read
- $data = $this->packed ? serialize($data) : $data;
+ $data = $this->serialize($data);
if (!$this->cache_sums[$key] || $this->cache_sums[$key] != md5($data)) {
$this->write_record($key, $data);
@@ -255,7 +255,7 @@ class rcube_cache
if ($data) {
$md5sum = md5($data);
- $data = $this->packed ? unserialize($data) : $data;
+ $data = $this->unserialize($data);
if ($nostore) {
return $data;
@@ -283,7 +283,7 @@ class rcube_cache
$key = substr($sql_arr['cache_key'], strlen($this->prefix)+1);
$md5sum = $sql_arr['data'] ? md5($sql_arr['data']) : null;
if ($sql_arr['data']) {
- $data = $this->packed ? unserialize($sql_arr['data']) : $sql_arr['data'];
+ $data = $this->unserialize($sql_arr['data']);
}
if ($nostore) {
@@ -364,7 +364,6 @@ class rcube_cache
* @param string $key Cache key name or pattern
* @param boolean $prefix_mode Enable it to clear all keys starting
* with prefix specified in $key
- *
*/
private function remove_record($key=null, $prefix_mode=false)
{
@@ -553,4 +552,28 @@ class rcube_cache
// This way each cache will have its own index
return sprintf('%d:%s%s', $this->userid, $this->prefix, 'INDEX');
}
+
+ /**
+ * Serializes data for storing
+ */
+ private function serialize($data)
+ {
+ if ($this->type == 'db') {
+ return $this->db->encode($data, $this->packed);
+ }
+
+ return $this->packed ? serialize($data) : $data;
+ }
+
+ /**
+ * Unserializes serialized data
+ */
+ private function unserialize($data)
+ {
+ if ($this->type == 'db') {
+ return $this->db->decode($data, $this->packed);
+ }
+
+ return $this->packed ? @unserialize($data) : $data;
+ }
}
diff --git a/program/lib/Roundcube/rcube_cache_shared.php b/program/lib/Roundcube/rcube_cache_shared.php
index 5983bd36b..2c4af2046 100644
--- a/program/lib/Roundcube/rcube_cache_shared.php
+++ b/program/lib/Roundcube/rcube_cache_shared.php
@@ -144,7 +144,7 @@ class rcube_cache_shared
*/
function write($key, $data)
{
- return $this->write_record($key, $this->packed ? serialize($data) : $data);
+ return $this->write_record($key, $this->serialize($data));
}
@@ -216,7 +216,7 @@ class rcube_cache_shared
if ($this->cache_changes[$key]) {
// Make sure we're not going to write unchanged data
// by comparing current md5 sum with the sum calculated on DB read
- $data = $this->packed ? serialize($data) : $data;
+ $data = $this->serialize($data);
if (!$this->cache_sums[$key] || $this->cache_sums[$key] != md5($data)) {
$this->write_record($key, $data);
@@ -252,7 +252,7 @@ class rcube_cache_shared
if ($data) {
$md5sum = md5($data);
- $data = $this->packed ? unserialize($data) : $data;
+ $data = $this->unserialize($data);
if ($nostore) {
return $data;
@@ -278,7 +278,7 @@ class rcube_cache_shared
if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
$md5sum = $sql_arr['data'] ? md5($sql_arr['data']) : null;
if ($sql_arr['data']) {
- $data = $this->packed ? unserialize($sql_arr['data']) : $sql_arr['data'];
+ $data = $this->unserialize($sql_arr['data']);
}
if ($nostore) {
@@ -541,4 +541,28 @@ class rcube_cache_shared
// This way each cache will have its own index
return $this->prefix . 'INDEX';
}
+
+ /**
+ * Serializes data for storing
+ */
+ private function serialize($data)
+ {
+ if ($this->type == 'db') {
+ return $this->db->encode($data, $this->packed);
+ }
+
+ return $this->packed ? serialize($data) : $data;
+ }
+
+ /**
+ * Unserializes serialized data
+ */
+ private function unserialize($data)
+ {
+ if ($this->type == 'db') {
+ return $this->db->decode($data, $this->packed);
+ }
+
+ return $this->packed ? @unserialize($data) : $data;
+ }
}
diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php
index 5da38c899..645b85adb 100644
--- a/program/lib/Roundcube/rcube_db.php
+++ b/program/lib/Roundcube/rcube_db.php
@@ -795,12 +795,19 @@ class rcube_db
/**
* Encodes non-UTF-8 characters in string/array/object (recursive)
*
- * @param mixed $input Data to fix
+ * @param mixed $input Data to fix
+ * @param bool $serialized Enable serialization
*
* @return mixed Properly UTF-8 encoded data
*/
- public static function encode($input)
+ public static function encode($input, $serialized = false)
{
+ // use Base64 encoding to workaround issues with invalid
+ // or null characters in serialized string (#1489142)
+ if ($serialized) {
+ return base64_encode(serialize($input));
+ }
+
if (is_object($input)) {
foreach (get_object_vars($input) as $idx => $value) {
$input->$idx = self::encode($value);
@@ -811,6 +818,7 @@ class rcube_db
foreach ($input as $idx => $value) {
$input[$idx] = self::encode($value);
}
+
return $input;
}
@@ -820,12 +828,19 @@ class rcube_db
/**
* Decodes encoded UTF-8 string/object/array (recursive)
*
- * @param mixed $input Input data
+ * @param mixed $input Input data
+ * @param bool $serialized Enable serialization
*
* @return mixed Decoded data
*/
- public static function decode($input)
+ public static function decode($input, $serialized = false)
{
+ if ($serialized) {
+ // use Base64 encoding to workaround issues with invalid
+ // or null characters in serialized string (#1489142)
+ return @unserialize(base64_decode($input));
+ }
+
if (is_object($input)) {
foreach (get_object_vars($input) as $idx => $value) {
$input->$idx = self::decode($value);
diff --git a/program/lib/Roundcube/rcube_imap_cache.php b/program/lib/Roundcube/rcube_imap_cache.php
index 089a52439..71545f1a8 100644
--- a/program/lib/Roundcube/rcube_imap_cache.php
+++ b/program/lib/Roundcube/rcube_imap_cache.php
@@ -419,7 +419,7 @@ class rcube_imap_cache
}
unset($msg->flags);
- $msg = serialize($this->db->encode($msg));
+ $msg = $this->db->encode($msg, true);
// update cache record (even if it exists, the update
// here will work as select, assume row exist if affected_rows=0)
@@ -641,7 +641,7 @@ class rcube_imap_cache
if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
$data = explode('@', $sql_arr['data']);
- $index = @unserialize($data[0]);
+ $index = $this->db->decode($data[0], true);
unset($data[0]);
if (empty($index)) {
@@ -678,7 +678,7 @@ class rcube_imap_cache
if ($sql_arr = $this->db->fetch_assoc($sql_result)) {
$data = explode('@', $sql_arr['data']);
- $thread = @unserialize($data[0]);
+ $thread = $this->db->decode($data[0], true);
unset($data[0]);
if (empty($thread)) {
@@ -704,7 +704,7 @@ class rcube_imap_cache
$data, $mbox_data = array(), $exists = false, $modseq = null)
{
$data = array(
- serialize($data),
+ $this->db->encode($data, true),
$sort_field,
(int) $this->skip_deleted,
(int) $mbox_data['UIDVALIDITY'],
@@ -737,7 +737,7 @@ class rcube_imap_cache
private function add_thread_row($mailbox, $data, $mbox_data = array(), $exists = false)
{
$data = array(
- serialize($data),
+ $this->db->encode($data, true),
(int) $this->skip_deleted,
(int) $mbox_data['UIDVALIDITY'],
(int) $mbox_data['UIDNEXT'],
@@ -1069,7 +1069,7 @@ class rcube_imap_cache
*/
private function build_message($sql_arr)
{
- $message = $this->db->decode(unserialize($sql_arr['data']));
+ $message = $this->db->decode($sql_arr['data'], true);
if ($message) {
$message->flags = array();