From b03a59cc5c3e71c74c6d374e67bd45de6b270eea Mon Sep 17 00:00:00 2001 From: Jake Farrell Date: Tue, 29 Nov 2011 16:45:51 +0000 Subject: [PATCH] Thrift-1427: PHP library uses non-multibyte safe functions with mbstring function overloading Client: php Patch: Bryan Alves Fixes issue with php overloaded mbstring to be binary-safe for strlen and substr. git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1207960 13f79535-47bb-0310-9956-ffa450edef68 --- lib/php/src/TStringUtils.php | 81 ++++++++++++++++++++ lib/php/src/Thrift.php | 2 + lib/php/src/protocol/TBinaryProtocol.php | 2 +- lib/php/src/protocol/TCompactProtocol.php | 6 +- lib/php/src/transport/TBufferedTransport.php | 20 ++--- lib/php/src/transport/TFramedTransport.php | 20 ++--- lib/php/src/transport/THttpClient.php | 4 +- lib/php/src/transport/TMemoryBuffer.php | 10 +-- lib/php/src/transport/TPhpStream.php | 6 +- lib/php/src/transport/TSocket.php | 10 +-- lib/php/src/transport/TTransport.php | 2 +- 11 files changed, 123 insertions(+), 40 deletions(-) create mode 100644 lib/php/src/TStringUtils.php diff --git a/lib/php/src/TStringUtils.php b/lib/php/src/TStringUtils.php new file mode 100644 index 00000000..69672e86 --- /dev/null +++ b/lib/php/src/TStringUtils.php @@ -0,0 +1,81 @@ +strlen($str) - $start; + } + + return mb_substr($str, $start, $length, '8bit'); + } + + public function strlen($str) { + return mb_strlen($str, '8bit'); + } +} + +class TStringFuncFactory { + private static $_instance; + + /** + * Get the Singleton instance of TStringFunc implementation that is + * compatible with the current system's mbstring.func_overload settings. + * + * @return TStringFunc + */ + public static function create() { + if(!self::$_instance) { + self::_setInstance(); + } + + return self::$_instance; + } + + private static function _setInstance() { + /** + * Cannot use str* functions for byte counting because multibyte + * characters will be read a single bytes. + * + * See: http://us.php.net/manual/en/mbstring.overload.php + */ + if(ini_get('mbstring.func_overload') & 2) { + self::$_instance = new TStringFunc_Mbstring(); + } + /** + * mbstring is not installed or does not have function overloading + * of the str* functions enabled so use PHP core str* functions for + * byte counting. + */ + else { + self::$_instance = new TStringFunc_Core(); + } + } +} diff --git a/lib/php/src/Thrift.php b/lib/php/src/Thrift.php index d2a94414..c8453951 100644 --- a/lib/php/src/Thrift.php +++ b/lib/php/src/Thrift.php @@ -785,3 +785,5 @@ if (!isset($GLOBALS['THRIFT_ROOT'])) { } include_once $GLOBALS['THRIFT_ROOT'].'/protocol/TProtocol.php'; include_once $GLOBALS['THRIFT_ROOT'].'/transport/TTransport.php'; +include_once $GLOBALS['THRIFT_ROOT'].'/TStringUtils.php'; + diff --git a/lib/php/src/protocol/TBinaryProtocol.php b/lib/php/src/protocol/TBinaryProtocol.php index b5bc750f..40b9f9ba 100644 --- a/lib/php/src/protocol/TBinaryProtocol.php +++ b/lib/php/src/protocol/TBinaryProtocol.php @@ -180,7 +180,7 @@ class TBinaryProtocol extends TProtocol { } public function writeString($value) { - $len = strlen($value); + $len = TStringFuncFactory::create()->strlen($value); $result = $this->writeI32($len); if ($len) { $this->trans_->write($value, $len); diff --git a/lib/php/src/protocol/TCompactProtocol.php b/lib/php/src/protocol/TCompactProtocol.php index 6ecbd09f..9f0d4076 100644 --- a/lib/php/src/protocol/TCompactProtocol.php +++ b/lib/php/src/protocol/TCompactProtocol.php @@ -121,7 +121,7 @@ class TCompactProtocol extends TProtocol { public function writeVarint($data) { $out = $this->getVarint($data); - $result = strlen($out); + $result = TStringFuncFactory::create()->strlen($out); $this->trans_->write($out, $result); return $result; } @@ -308,7 +308,7 @@ class TCompactProtocol extends TProtocol { } public function writeString($value) { - $len = strlen($value); + $len = TStringFuncFactory::create()->strlen($value); $result = $this->writeVarint($len); if ($len) { $this->trans_->write($value, $len); @@ -653,7 +653,7 @@ class TCompactProtocol extends TProtocol { } } - $ret = strlen($out); + $ret = TStringFuncFactory::create()->strlen($out); $this->trans_->write($out, $ret); return $ret; diff --git a/lib/php/src/transport/TBufferedTransport.php b/lib/php/src/transport/TBufferedTransport.php index e841564d..9b27d023 100644 --- a/lib/php/src/transport/TBufferedTransport.php +++ b/lib/php/src/transport/TBufferedTransport.php @@ -87,7 +87,7 @@ class TBufferedTransport extends TTransport { } public function putBack($data) { - if (strlen($this->rBuf_) === 0) { + if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { $this->rBuf_ = $data; } else { $this->rBuf_ = ($data . $this->rBuf_); @@ -104,7 +104,7 @@ class TBufferedTransport extends TTransport { * the buffered readAll. */ public function readAll($len) { - $have = strlen($this->rBuf_); + $have = TStringFuncFactory::create()->strlen($this->rBuf_); if ($have == 0) { $data = $this->transport_->readAll($len); } else if ($have < $len) { @@ -115,31 +115,31 @@ class TBufferedTransport extends TTransport { $data = $this->rBuf_; $this->rBuf_ = ''; } else if ($have > $len) { - $data = substr($this->rBuf_, 0, $len); - $this->rBuf_ = substr($this->rBuf_, $len); + $data = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len); + $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len); } return $data; } public function read($len) { - if (strlen($this->rBuf_) === 0) { + if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { $this->rBuf_ = $this->transport_->read($this->rBufSize_); } - if (strlen($this->rBuf_) <= $len) { + if (TStringFuncFactory::create()->strlen($this->rBuf_) <= $len) { $ret = $this->rBuf_; $this->rBuf_ = ''; return $ret; } - $ret = substr($this->rBuf_, 0, $len); - $this->rBuf_ = substr($this->rBuf_, $len); + $ret = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len); + $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len); return $ret; } public function write($buf) { $this->wBuf_ .= $buf; - if (strlen($this->wBuf_) >= $this->wBufSize_) { + if (TStringFuncFactory::create()->strlen($this->wBuf_) >= $this->wBufSize_) { $out = $this->wBuf_; // Note that we clear the internal wBuf_ prior to the underlying write @@ -151,7 +151,7 @@ class TBufferedTransport extends TTransport { } public function flush() { - if (strlen($this->wBuf_) > 0) { + if (TStringFuncFactory::create()->strlen($this->wBuf_) > 0) { $this->transport_->write($this->wBuf_); $this->wBuf_ = ''; } diff --git a/lib/php/src/transport/TFramedTransport.php b/lib/php/src/transport/TFramedTransport.php index b1c0bb5c..bc759dea 100644 --- a/lib/php/src/transport/TFramedTransport.php +++ b/lib/php/src/transport/TFramedTransport.php @@ -98,20 +98,20 @@ class TFramedTransport extends TTransport { return $this->transport_->read($len); } - if (strlen($this->rBuf_) === 0) { + if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { $this->readFrame(); } // Just return full buff - if ($len >= strlen($this->rBuf_)) { + if ($len >= TStringFuncFactory::create()->strlen($this->rBuf_)) { $out = $this->rBuf_; $this->rBuf_ = null; return $out; } - // Return substr - $out = substr($this->rBuf_, 0, $len); - $this->rBuf_ = substr($this->rBuf_, $len); + // Return TStringFuncFactory::create()->substr + $out = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len); + $this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len); return $out; } @@ -121,7 +121,7 @@ class TFramedTransport extends TTransport { * @param string $data data to return */ public function putBack($data) { - if (strlen($this->rBuf_) === 0) { + if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) { $this->rBuf_ = $data; } else { $this->rBuf_ = ($data . $this->rBuf_); @@ -150,8 +150,8 @@ class TFramedTransport extends TTransport { return $this->transport_->write($buf, $len); } - if ($len !== null && $len < strlen($buf)) { - $buf = substr($buf, 0, $len); + if ($len !== null && $len < TStringFuncFactory::create()->strlen($buf)) { + $buf = TStringFuncFactory::create()->substr($buf, 0, $len); } $this->wBuf_ .= $buf; } @@ -161,11 +161,11 @@ class TFramedTransport extends TTransport { * followed by the actual data. */ public function flush() { - if (!$this->write_ || strlen($this->wBuf_) == 0) { + if (!$this->write_ || TStringFuncFactory::create()->strlen($this->wBuf_) == 0) { return $this->transport_->flush(); } - $out = pack('N', strlen($this->wBuf_)); + $out = pack('N', TStringFuncFactory::create()->strlen($this->wBuf_)); $out .= $this->wBuf_; // Note that we clear the internal wBuf_ prior to the underlying write diff --git a/lib/php/src/transport/THttpClient.php b/lib/php/src/transport/THttpClient.php index 880011a0..118f0d3e 100644 --- a/lib/php/src/transport/THttpClient.php +++ b/lib/php/src/transport/THttpClient.php @@ -85,7 +85,7 @@ class THttpClient extends TTransport { * @param string $uri */ public function __construct($host, $port=80, $uri='', $scheme = 'http') { - if ((strlen($uri) > 0) && ($uri{0} != '/')) { + if ((TStringFuncFactory::create()->strlen($uri) > 0) && ($uri{0} != '/')) { $uri = '/'.$uri; } $this->scheme_ = $scheme; @@ -175,7 +175,7 @@ class THttpClient extends TTransport { 'Accept: application/x-thrift', 'User-Agent: PHP/THttpClient', 'Content-Type: application/x-thrift', - 'Content-Length: '.strlen($this->buf_)); + 'Content-Length: '.TStringFuncFactory::create()->strlen($this->buf_)); $options = array('method' => 'POST', 'header' => implode("\r\n", $headers), diff --git a/lib/php/src/transport/TMemoryBuffer.php b/lib/php/src/transport/TMemoryBuffer.php index a0b1a546..13aa9e54 100644 --- a/lib/php/src/transport/TMemoryBuffer.php +++ b/lib/php/src/transport/TMemoryBuffer.php @@ -54,20 +54,20 @@ class TMemoryBuffer extends TTransport { } public function read($len) { - if (strlen($this->buf_) === 0) { + if (TStringFuncFactory::create()->strlen($this->buf_) === 0) { throw new TTransportException('TMemoryBuffer: Could not read ' . $len . ' bytes from buffer.', TTransportException::UNKNOWN); } - if (strlen($this->buf_) <= $len) { + if (TStringFuncFactory::create()->strlen($this->buf_) <= $len) { $ret = $this->buf_; $this->buf_ = ''; return $ret; } - $ret = substr($this->buf_, 0, $len); - $this->buf_ = substr($this->buf_, $len); + $ret = TStringFuncFactory::create()->substr($this->buf_, 0, $len); + $this->buf_ = TStringFuncFactory::create()->substr($this->buf_, $len); return $ret; } @@ -77,6 +77,6 @@ class TMemoryBuffer extends TTransport { } public function available() { - return strlen($this->buf_); + return TStringFuncFactory::create()->strlen($this->buf_); } } diff --git a/lib/php/src/transport/TPhpStream.php b/lib/php/src/transport/TPhpStream.php index 94b11a6e..e16b4726 100644 --- a/lib/php/src/transport/TPhpStream.php +++ b/lib/php/src/transport/TPhpStream.php @@ -86,12 +86,12 @@ class TPhpStream extends TTransport { } public function write($buf) { - while (strlen($buf) > 0) { + while (TStringFuncFactory::create()->strlen($buf) > 0) { $got = @fwrite($this->outStream_, $buf); if ($got === 0 || $got === FALSE) { - throw new TException('TPhpStream: Could not write '.strlen($buf).' bytes'); + throw new TException('TPhpStream: Could not write '.TStringFuncFactory::create()->strlen($buf).' bytes'); } - $buf = substr($buf, $got); + $buf = TStringFuncFactory::create()->substr($buf, $got); } } diff --git a/lib/php/src/transport/TSocket.php b/lib/php/src/transport/TSocket.php index daf90204..02033846 100644 --- a/lib/php/src/transport/TSocket.php +++ b/lib/php/src/transport/TSocket.php @@ -283,23 +283,23 @@ class TSocket extends TTransport { $write = array($this->handle_); // keep writing until all the data has been written - while (strlen($buf) > 0) { + while (TStringFuncFactory::create()->strlen($buf) > 0) { // wait for stream to become available for writing $writable = @stream_select($null, $write, $null, $this->sendTimeoutSec_, $this->sendTimeoutUsec_); if ($writable > 0) { // write buffer to stream $written = @stream_socket_sendto($this->handle_, $buf); if ($written === -1 || $written === false) { - throw new TTransportException('TSocket: Could not write '.strlen($buf).' bytes '. + throw new TTransportException('TSocket: Could not write '.TStringFuncFactory::create()->strlen($buf).' bytes '. $this->host_.':'.$this->port_); } // determine how much of the buffer is left to write - $buf = substr($buf, $written); + $buf = TStringFuncFactory::create()->substr($buf, $written); } else if ($writable === 0) { - throw new TTransportException('TSocket: timed out writing '.strlen($buf).' bytes from '. + throw new TTransportException('TSocket: timed out writing '.TStringFuncFactory::create()->strlen($buf).' bytes from '. $this->host_.':'.$this->port_); } else { - throw new TTransportException('TSocket: Could not write '.strlen($buf).' bytes '. + throw new TTransportException('TSocket: Could not write '.TStringFuncFactory::create()->strlen($buf).' bytes '. $this->host_.':'.$this->port_); } } diff --git a/lib/php/src/transport/TTransport.php b/lib/php/src/transport/TTransport.php index e0e336d2..f8c8d86d 100644 --- a/lib/php/src/transport/TTransport.php +++ b/lib/php/src/transport/TTransport.php @@ -83,7 +83,7 @@ abstract class TTransport { $data = ''; $got = 0; - while (($got = strlen($data)) < $len) { + while (($got = TStringFuncFactory::create()->strlen($data)) < $len) { $data .= $this->read($len - $got); } return $data; -- 2.17.1