Upgrading dependency to Thrift 0.12.0

This commit is contained in:
Renan DelValle 2018-11-27 18:03:50 -08:00
parent 3e4590dcc0
commit 356978cb42
No known key found for this signature in database
GPG key ID: C240AD6D6F443EC9
1302 changed files with 101701 additions and 26784 deletions

View file

@ -37,103 +37,102 @@ distclean-local:
endif
phpdir = $(PHP_PREFIX)/Thrift
phpdir = $(PHP_PREFIX)/
php_DATA = \
lib/Thrift/TMultiplexedProcessor.php
lib/TMultiplexedProcessor.php
phpbasedir = $(phpdir)/Base
phpbase_DATA = \
lib/Thrift/Base/TBase.php
lib/Base/TBase.php
phpclassloaderdir = $(phpdir)/ClassLoader
phpclassloader_DATA = \
lib/Thrift/ClassLoader/ThriftClassLoader.php
lib/ClassLoader/ThriftClassLoader.php
phpexceptiondir = $(phpdir)/Exception
phpexception_DATA = \
lib/Thrift/Exception/TApplicationException.php \
lib/Thrift/Exception/TException.php \
lib/Thrift/Exception/TProtocolException.php \
lib/Thrift/Exception/TTransportException.php
lib/Exception/TApplicationException.php \
lib/Exception/TException.php \
lib/Exception/TProtocolException.php \
lib/Exception/TTransportException.php
phpfactorydir = $(phpdir)/Factory
phpfactory_DATA = \
lib/Thrift/Factory/TBinaryProtocolFactory.php \
lib/Thrift/Factory/TCompactProtocolFactory.php \
lib/Thrift/Factory/TJSONProtocolFactory.php \
lib/Thrift/Factory/TProtocolFactory.php \
lib/Thrift/Factory/TStringFuncFactory.php \
lib/Thrift/Factory/TTransportFactory.php
lib/Factory/TBinaryProtocolFactory.php \
lib/Factory/TCompactProtocolFactory.php \
lib/Factory/TJSONProtocolFactory.php \
lib/Factory/TProtocolFactory.php \
lib/Factory/TStringFuncFactory.php \
lib/Factory/TTransportFactory.php
phpprotocoldir = $(phpdir)/Protocol
phpprotocol_DATA = \
lib/Thrift/Protocol/TBinaryProtocolAccelerated.php \
lib/Thrift/Protocol/TBinaryProtocol.php \
lib/Thrift/Protocol/TCompactProtocol.php \
lib/Thrift/Protocol/TJSONProtocol.php \
lib/Thrift/Protocol/TMultiplexedProtocol.php \
lib/Thrift/Protocol/TProtocol.php \
lib/Thrift/Protocol/TProtocolDecorator.php \
lib/Thrift/Protocol/TSimpleJSONProtocol.php
lib/Protocol/TBinaryProtocolAccelerated.php \
lib/Protocol/TBinaryProtocol.php \
lib/Protocol/TCompactProtocol.php \
lib/Protocol/TJSONProtocol.php \
lib/Protocol/TMultiplexedProtocol.php \
lib/Protocol/TProtocol.php \
lib/Protocol/TProtocolDecorator.php \
lib/Protocol/TSimpleJSONProtocol.php
phpprotocoljsondir = $(phpprotocoldir)/JSON
phpprotocoljson_DATA = \
lib/Thrift/Protocol/JSON/BaseContext.php \
lib/Thrift/Protocol/JSON/ListContext.php \
lib/Thrift/Protocol/JSON/LookaheadReader.php \
lib/Thrift/Protocol/JSON/PairContext.php
lib/Protocol/JSON/BaseContext.php \
lib/Protocol/JSON/ListContext.php \
lib/Protocol/JSON/LookaheadReader.php \
lib/Protocol/JSON/PairContext.php
phpprotocolsimplejsondir = $(phpprotocoldir)/SimpleJSON
phpprotocolsimplejson_DATA = \
lib/Thrift/Protocol/SimpleJSON/CollectionMapKeyException.php \
lib/Thrift/Protocol/SimpleJSON/Context.php \
lib/Thrift/Protocol/SimpleJSON/ListContext.php \
lib/Thrift/Protocol/SimpleJSON/MapContext.php \
lib/Thrift/Protocol/SimpleJSON/StructContext.php
lib/Protocol/SimpleJSON/CollectionMapKeyException.php \
lib/Protocol/SimpleJSON/Context.php \
lib/Protocol/SimpleJSON/ListContext.php \
lib/Protocol/SimpleJSON/MapContext.php \
lib/Protocol/SimpleJSON/StructContext.php
phpserializerdir = $(phpdir)/Serializer
phpserializer_DATA = \
lib/Thrift/Serializer/TBinarySerializer.php
lib/Serializer/TBinarySerializer.php
phpserverdir = $(phpdir)/Server
phpserver_DATA = \
lib/Thrift/Server/TServerSocket.php \
lib/Thrift/Server/TForkingServer.php \
lib/Thrift/Server/TServer.php \
lib/Thrift/Server/TServerTransport.php \
lib/Thrift/Server/TSimpleServer.php
lib/Server/TServerSocket.php \
lib/Server/TForkingServer.php \
lib/Server/TServer.php \
lib/Server/TServerTransport.php \
lib/Server/TSimpleServer.php
phpstringfuncdir = $(phpdir)/StringFunc
phpstringfunc_DATA = \
lib/Thrift/StringFunc/Mbstring.php \
lib/Thrift/StringFunc/Core.php \
lib/Thrift/StringFunc/TStringFunc.php
lib/StringFunc/Mbstring.php \
lib/StringFunc/Core.php \
lib/StringFunc/TStringFunc.php
phptransportdir = $(phpdir)/Transport
phptransport_DATA = \
lib/Thrift/Transport/TBufferedTransport.php \
lib/Thrift/Transport/TCurlClient.php \
lib/Thrift/Transport/TFramedTransport.php \
lib/Thrift/Transport/THttpClient.php \
lib/Thrift/Transport/TMemoryBuffer.php \
lib/Thrift/Transport/TNullTransport.php \
lib/Thrift/Transport/TPhpStream.php \
lib/Thrift/Transport/TSocket.php \
lib/Thrift/Transport/TSocketPool.php \
lib/Thrift/Transport/TTransport.php
lib/Transport/TBufferedTransport.php \
lib/Transport/TCurlClient.php \
lib/Transport/TFramedTransport.php \
lib/Transport/THttpClient.php \
lib/Transport/TMemoryBuffer.php \
lib/Transport/TNullTransport.php \
lib/Transport/TPhpStream.php \
lib/Transport/TSocket.php \
lib/Transport/TSocketPool.php \
lib/Transport/TTransport.php
phptypedir = $(phpdir)/Type
phptype_DATA = \
lib/Thrift/Type/TMessageType.php \
lib/Thrift/Type/TType.php \
lib/Thrift/Type/TConstant.php
lib/Type/TMessageType.php \
lib/Type/TType.php \
lib/Type/TConstant.php
EXTRA_DIST = \
lib \
src/autoload.php \
src/ext/thrift_protocol/config.m4 \
src/ext/thrift_protocol/config.w32 \
src/ext/thrift_protocol/php_thrift_protocol7.cpp \
src/ext/thrift_protocol/php_thrift_protocol.cpp \
src/ext/thrift_protocol/php_thrift_protocol.h \
src/ext/thrift_protocol/run-tests.php \

View file

@ -1,7 +1,6 @@
Thrift PHP Software Library
License
=======
# License
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@ -20,8 +19,7 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
Using Thrift with PHP
=====================
# Using Thrift with PHP
Thrift requires PHP 5. Thrift makes as few assumptions about your PHP
environment as possible while trying to make some more advanced PHP
@ -29,25 +27,34 @@ features (i.e. APC cacheing using asbolute path URLs) as simple as possible.
To use Thrift in your PHP codebase, take the following steps:
#1) Copy all of thrift/lib/php/lib into your PHP codebase
#2) Configure Symfony Autoloader (or whatever you usually use)
1. Copy all of thrift/lib/php/lib into your PHP codebase
2. Configure Symfony Autoloader (or whatever you usually use)
After that, you have to manually include the Thrift package
created by the compiler:
```
require_once 'packages/Service/Service.php';
require_once 'packages/Service/Types.php';
```
Dependencies
============
# Dependencies
PHP_INT_SIZE
This built-in signals whether your architecture is 32 or 64 bit and is
used by the TBinaryProtocol to properly use pack() and unpack() to
serialize data.
This built-in signals whether your architecture is 32 or 64 bit and is
used by the TBinaryProtocol to properly use pack() and unpack() to
serialize data.
apc_fetch(), apc_store()
APC cache is used by the TSocketPool class. If you do not have APC installed,
Thrift will fill in null stub function definitions.
APC cache is used by the TSocketPool class. If you do not have APC installed,
Thrift will fill in null stub function definitions.
# Breaking Changes
## 0.12.0
1. [PSR-4](https://www.php-fig.org/psr/psr-4/) loader is now the default. If you want to use class maps instead, use `-gen php:classmap`.
2. If using PSR-4, use `$thriftClassLoader->registerNamespace('namespace', '<path>')` instead of `$thriftClassLoader->registerDefinition('namespace', '<path>')`.

View file

@ -1 +1,5 @@
Please follow [General Coding Standards](/doc/coding_standards.md)
## PHP Coding Standards
Please follow:
* [Thrift General Coding Standards](/doc/coding_standards.md)
* [PSR-2](http://www.php-fig.org/psr/psr-2/)

View file

@ -0,0 +1,382 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift
*/
namespace Thrift\Base;
use Thrift\Type\TType;
/**
* Base class from which other Thrift structs extend. This is so that we can
* cut back on the size of the generated code which is turning out to have a
* nontrivial cost just to load thanks to the wondrously abysmal implementation
* of PHP. Note that code is intentionally duplicated in here to avoid making
* function calls for every field or member of a container..
*/
abstract class TBase
{
static public $tmethod = array(
TType::BOOL => 'Bool',
TType::BYTE => 'Byte',
TType::I16 => 'I16',
TType::I32 => 'I32',
TType::I64 => 'I64',
TType::DOUBLE => 'Double',
TType::STRING => 'String'
);
abstract public function read($input);
abstract public function write($output);
public function __construct($spec = null, $vals = null)
{
if (is_array($spec) && is_array($vals)) {
foreach ($spec as $fid => $fspec) {
$var = $fspec['var'];
if (isset($vals[$var])) {
$this->$var = $vals[$var];
}
}
}
}
public function __wakeup()
{
$this->__construct(get_object_vars($this));
}
private function _readMap(&$var, $spec, $input)
{
$xfer = 0;
$ktype = $spec['ktype'];
$vtype = $spec['vtype'];
$kread = $vread = null;
if (isset(TBase::$tmethod[$ktype])) {
$kread = 'read' . TBase::$tmethod[$ktype];
} else {
$kspec = $spec['key'];
}
if (isset(TBase::$tmethod[$vtype])) {
$vread = 'read' . TBase::$tmethod[$vtype];
} else {
$vspec = $spec['val'];
}
$var = array();
$_ktype = $_vtype = $size = 0;
$xfer += $input->readMapBegin($_ktype, $_vtype, $size);
for ($i = 0; $i < $size; ++$i) {
$key = $val = null;
if ($kread !== null) {
$xfer += $input->$kread($key);
} else {
switch ($ktype) {
case TType::STRUCT:
$class = $kspec['class'];
$key = new $class();
$xfer += $key->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($key, $kspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($key, $kspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($key, $kspec, $input, true);
break;
}
}
if ($vread !== null) {
$xfer += $input->$vread($val);
} else {
switch ($vtype) {
case TType::STRUCT:
$class = $vspec['class'];
$val = new $class();
$xfer += $val->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($val, $vspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($val, $vspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($val, $vspec, $input, true);
break;
}
}
$var[$key] = $val;
}
$xfer += $input->readMapEnd();
return $xfer;
}
private function _readList(&$var, $spec, $input, $set = false)
{
$xfer = 0;
$etype = $spec['etype'];
$eread = $vread = null;
if (isset(TBase::$tmethod[$etype])) {
$eread = 'read' . TBase::$tmethod[$etype];
} else {
$espec = $spec['elem'];
}
$var = array();
$_etype = $size = 0;
if ($set) {
$xfer += $input->readSetBegin($_etype, $size);
} else {
$xfer += $input->readListBegin($_etype, $size);
}
for ($i = 0; $i < $size; ++$i) {
$elem = null;
if ($eread !== null) {
$xfer += $input->$eread($elem);
} else {
$espec = $spec['elem'];
switch ($etype) {
case TType::STRUCT:
$class = $espec['class'];
$elem = new $class();
$xfer += $elem->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($elem, $espec, $input);
break;
case TType::LST:
$xfer += $this->_readList($elem, $espec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($elem, $espec, $input, true);
break;
}
}
if ($set) {
$var[$elem] = true;
} else {
$var [] = $elem;
}
}
if ($set) {
$xfer += $input->readSetEnd();
} else {
$xfer += $input->readListEnd();
}
return $xfer;
}
protected function _read($class, $spec, $input)
{
$xfer = 0;
$fname = null;
$ftype = 0;
$fid = 0;
$xfer += $input->readStructBegin($fname);
while (true) {
$xfer += $input->readFieldBegin($fname, $ftype, $fid);
if ($ftype == TType::STOP) {
break;
}
if (isset($spec[$fid])) {
$fspec = $spec[$fid];
$var = $fspec['var'];
if ($ftype == $fspec['type']) {
$xfer = 0;
if (isset(TBase::$tmethod[$ftype])) {
$func = 'read' . TBase::$tmethod[$ftype];
$xfer += $input->$func($this->$var);
} else {
switch ($ftype) {
case TType::STRUCT:
$class = $fspec['class'];
$this->$var = new $class();
$xfer += $this->$var->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($this->$var, $fspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($this->$var, $fspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($this->$var, $fspec, $input, true);
break;
}
}
} else {
$xfer += $input->skip($ftype);
}
} else {
$xfer += $input->skip($ftype);
}
$xfer += $input->readFieldEnd();
}
$xfer += $input->readStructEnd();
return $xfer;
}
private function _writeMap($var, $spec, $output)
{
$xfer = 0;
$ktype = $spec['ktype'];
$vtype = $spec['vtype'];
$kwrite = $vwrite = null;
if (isset(TBase::$tmethod[$ktype])) {
$kwrite = 'write' . TBase::$tmethod[$ktype];
} else {
$kspec = $spec['key'];
}
if (isset(TBase::$tmethod[$vtype])) {
$vwrite = 'write' . TBase::$tmethod[$vtype];
} else {
$vspec = $spec['val'];
}
$xfer += $output->writeMapBegin($ktype, $vtype, count($var));
foreach ($var as $key => $val) {
if (isset($kwrite)) {
$xfer += $output->$kwrite($key);
} else {
switch ($ktype) {
case TType::STRUCT:
$xfer += $key->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($key, $kspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($key, $kspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($key, $kspec, $output, true);
break;
}
}
if (isset($vwrite)) {
$xfer += $output->$vwrite($val);
} else {
switch ($vtype) {
case TType::STRUCT:
$xfer += $val->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($val, $vspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($val, $vspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($val, $vspec, $output, true);
break;
}
}
}
$xfer += $output->writeMapEnd();
return $xfer;
}
private function _writeList($var, $spec, $output, $set = false)
{
$xfer = 0;
$etype = $spec['etype'];
$ewrite = null;
if (isset(TBase::$tmethod[$etype])) {
$ewrite = 'write' . TBase::$tmethod[$etype];
} else {
$espec = $spec['elem'];
}
if ($set) {
$xfer += $output->writeSetBegin($etype, count($var));
} else {
$xfer += $output->writeListBegin($etype, count($var));
}
foreach ($var as $key => $val) {
$elem = $set ? $key : $val;
if (isset($ewrite)) {
$xfer += $output->$ewrite($elem);
} else {
switch ($etype) {
case TType::STRUCT:
$xfer += $elem->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($elem, $espec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($elem, $espec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($elem, $espec, $output, true);
break;
}
}
}
if ($set) {
$xfer += $output->writeSetEnd();
} else {
$xfer += $output->writeListEnd();
}
return $xfer;
}
protected function _write($class, $spec, $output)
{
$xfer = 0;
$xfer += $output->writeStructBegin($class);
foreach ($spec as $fid => $fspec) {
$var = $fspec['var'];
if ($this->$var !== null) {
$ftype = $fspec['type'];
$xfer += $output->writeFieldBegin($var, $ftype, $fid);
if (isset(TBase::$tmethod[$ftype])) {
$func = 'write' . TBase::$tmethod[$ftype];
$xfer += $output->$func($this->$var);
} else {
switch ($ftype) {
case TType::STRUCT:
$xfer += $this->$var->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($this->$var, $fspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($this->$var, $fspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($this->$var, $fspec, $output, true);
break;
}
}
$xfer += $output->writeFieldEnd();
}
}
$xfer += $output->writeFieldStop();
$xfer += $output->writeStructEnd();
return $xfer;
}
}

View file

@ -54,7 +54,7 @@ class ThriftClassLoader
/**
* Set autoloader to use APC cache
* @param boolean $apc
* @param string $apc_prefix
* @param string $apc_prefix
*/
public function __construct($apc = false, $apc_prefix = null)
{
@ -65,23 +65,23 @@ class ThriftClassLoader
/**
* Registers a namespace.
*
* @param string $namespace The namespace
* @param array|string $paths The location(s) of the namespace
* @param string $namespace The namespace
* @param array|string $paths The location(s) of the namespace
*/
public function registerNamespace($namespace, $paths)
{
$this->namespaces[$namespace] = (array) $paths;
$this->namespaces[$namespace] = (array)$paths;
}
/**
* Registers a Thrift definition namespace.
*
* @param string $namespace The definition namespace
* @param array|string $paths The location(s) of the definition namespace
* @param string $namespace The definition namespace
* @param array|string $paths The location(s) of the definition namespace
*/
public function registerDefinition($namespace, $paths)
{
$this->definitions[$namespace] = (array) $paths;
$this->definitions[$namespace] = (array)$paths;
}
/**
@ -101,11 +101,9 @@ class ThriftClassLoader
*/
public function loadClass($class)
{
if (
(true === $this->apc && ($file = $this->findFileInApc($class))) or
if ((true === $this->apc && ($file = $this->findFileInApc($class))) or
($file = $this->findFile($class))
)
{
) {
require_once $file;
}
}
@ -117,8 +115,8 @@ class ThriftClassLoader
*/
protected function findFileInApc($class)
{
if (false === $file = apc_fetch($this->apc_prefix.$class)) {
apc_store($this->apc_prefix.$class, $file = $this->findFile($class));
if (false === $file = apc_fetch($this->apc_prefix . $class)) {
apc_store($this->apc_prefix . $class, $file = $this->findFile($class));
}
return $file;
@ -150,10 +148,10 @@ class ThriftClassLoader
foreach ($dirs as $dir) {
$className = substr($class, $pos + 1);
$file = $dir.DIRECTORY_SEPARATOR.
str_replace('\\', DIRECTORY_SEPARATOR, $namespace).
DIRECTORY_SEPARATOR.
$className.'.php';
$file = $dir . DIRECTORY_SEPARATOR .
str_replace('\\', DIRECTORY_SEPARATOR, $namespace) .
DIRECTORY_SEPARATOR .
$className . '.php';
if (file_exists($file)) {
return $file;
@ -185,20 +183,18 @@ class ThriftClassLoader
* Available in service: Interface, Client, Processor, Rest
* And every service methods (_.+)
*/
if(
0 === preg_match('#(.+)(if|client|processor|rest)$#i', $class, $n) and
if (0 === preg_match('#(.+)(if|client|processor|rest)$#i', $class, $n) and
0 === preg_match('#(.+)_[a-z0-9]+_(args|result)$#i', $class, $n)
)
{
) {
$className = 'Types';
} else {
$className = $n[1];
}
$file = $dir.DIRECTORY_SEPARATOR .
str_replace('\\', DIRECTORY_SEPARATOR, $namespace) .
DIRECTORY_SEPARATOR .
$className . '.php';
$file = $dir . DIRECTORY_SEPARATOR .
str_replace('\\', DIRECTORY_SEPARATOR, $namespace) .
DIRECTORY_SEPARATOR .
$className . '.php';
if (file_exists($file)) {
return $file;

View file

@ -0,0 +1,76 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift
*/
namespace Thrift\Exception;
use Thrift\Type\TType;
class TApplicationException extends TException
{
static public $_TSPEC =
array(1 => array('var' => 'message',
'type' => TType::STRING),
2 => array('var' => 'code',
'type' => TType::I32));
const UNKNOWN = 0;
const UNKNOWN_METHOD = 1;
const INVALID_MESSAGE_TYPE = 2;
const WRONG_METHOD_NAME = 3;
const BAD_SEQUENCE_ID = 4;
const MISSING_RESULT = 5;
const INTERNAL_ERROR = 6;
const PROTOCOL_ERROR = 7;
const INVALID_TRANSFORM = 8;
const INVALID_PROTOCOL = 9;
const UNSUPPORTED_CLIENT_TYPE = 10;
public function __construct($message = null, $code = 0)
{
parent::__construct($message, $code);
}
public function read($output)
{
return $this->_read('TApplicationException', self::$_TSPEC, $output);
}
public function write($output)
{
$xfer = 0;
$xfer += $output->writeStructBegin('TApplicationException');
if ($message = $this->getMessage()) {
$xfer += $output->writeFieldBegin('message', TType::STRING, 1);
$xfer += $output->writeString($message);
$xfer += $output->writeFieldEnd();
}
if ($code = $this->getCode()) {
$xfer += $output->writeFieldBegin('type', TType::I32, 2);
$xfer += $output->writeI32($code);
$xfer += $output->writeFieldEnd();
}
$xfer += $output->writeFieldStop();
$xfer += $output->writeStructEnd();
return $xfer;
}
}

View file

@ -0,0 +1,384 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift
*/
namespace Thrift\Exception;
use Thrift\Type\TType;
use Thrift\Base\TBase;
/**
* NOTE(mcslee): This currently contains a ton of duplicated code from TBase
* because we need to save CPU cycles and this is not yet in an extension.
* Ideally we'd multiply-inherit TException from both Exception and Base, but
* that's not possible in PHP and there are no modules either, so for now we
* apologetically take a trip to HackTown.
*
* Can be called with standard Exception constructor (message, code) or with
* Thrift Base object constructor (spec, vals).
*
* @param mixed $p1 Message (string) or type-spec (array)
* @param mixed $p2 Code (integer) or values (array)
*/
class TException extends \Exception
{
public function __construct($p1 = null, $p2 = 0)
{
if (is_array($p1) && is_array($p2)) {
$spec = $p1;
$vals = $p2;
foreach ($spec as $fid => $fspec) {
$var = $fspec['var'];
if (isset($vals[$var])) {
$this->$var = $vals[$var];
}
}
} else {
parent::__construct($p1, $p2);
}
}
static public $tmethod = array(
TType::BOOL => 'Bool',
TType::BYTE => 'Byte',
TType::I16 => 'I16',
TType::I32 => 'I32',
TType::I64 => 'I64',
TType::DOUBLE => 'Double',
TType::STRING => 'String'
);
private function _readMap(&$var, $spec, $input)
{
$xfer = 0;
$ktype = $spec['ktype'];
$vtype = $spec['vtype'];
$kread = $vread = null;
if (isset(TBase::$tmethod[$ktype])) {
$kread = 'read' . TBase::$tmethod[$ktype];
} else {
$kspec = $spec['key'];
}
if (isset(TBase::$tmethod[$vtype])) {
$vread = 'read' . TBase::$tmethod[$vtype];
} else {
$vspec = $spec['val'];
}
$var = array();
$_ktype = $_vtype = $size = 0;
$xfer += $input->readMapBegin($_ktype, $_vtype, $size);
for ($i = 0; $i < $size; ++$i) {
$key = $val = null;
if ($kread !== null) {
$xfer += $input->$kread($key);
} else {
switch ($ktype) {
case TType::STRUCT:
$class = $kspec['class'];
$key = new $class();
$xfer += $key->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($key, $kspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($key, $kspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($key, $kspec, $input, true);
break;
}
}
if ($vread !== null) {
$xfer += $input->$vread($val);
} else {
switch ($vtype) {
case TType::STRUCT:
$class = $vspec['class'];
$val = new $class();
$xfer += $val->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($val, $vspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($val, $vspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($val, $vspec, $input, true);
break;
}
}
$var[$key] = $val;
}
$xfer += $input->readMapEnd();
return $xfer;
}
private function _readList(&$var, $spec, $input, $set = false)
{
$xfer = 0;
$etype = $spec['etype'];
$eread = $vread = null;
if (isset(TBase::$tmethod[$etype])) {
$eread = 'read' . TBase::$tmethod[$etype];
} else {
$espec = $spec['elem'];
}
$var = array();
$_etype = $size = 0;
if ($set) {
$xfer += $input->readSetBegin($_etype, $size);
} else {
$xfer += $input->readListBegin($_etype, $size);
}
for ($i = 0; $i < $size; ++$i) {
$elem = null;
if ($eread !== null) {
$xfer += $input->$eread($elem);
} else {
$espec = $spec['elem'];
switch ($etype) {
case TType::STRUCT:
$class = $espec['class'];
$elem = new $class();
$xfer += $elem->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($elem, $espec, $input);
break;
case TType::LST:
$xfer += $this->_readList($elem, $espec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($elem, $espec, $input, true);
break;
}
}
if ($set) {
$var[$elem] = true;
} else {
$var [] = $elem;
}
}
if ($set) {
$xfer += $input->readSetEnd();
} else {
$xfer += $input->readListEnd();
}
return $xfer;
}
protected function _read($class, $spec, $input)
{
$xfer = 0;
$fname = null;
$ftype = 0;
$fid = 0;
$xfer += $input->readStructBegin($fname);
while (true) {
$xfer += $input->readFieldBegin($fname, $ftype, $fid);
if ($ftype == TType::STOP) {
break;
}
if (isset($spec[$fid])) {
$fspec = $spec[$fid];
$var = $fspec['var'];
if ($ftype == $fspec['type']) {
$xfer = 0;
if (isset(TBase::$tmethod[$ftype])) {
$func = 'read' . TBase::$tmethod[$ftype];
$xfer += $input->$func($this->$var);
} else {
switch ($ftype) {
case TType::STRUCT:
$class = $fspec['class'];
$this->$var = new $class();
$xfer += $this->$var->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($this->$var, $fspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($this->$var, $fspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($this->$var, $fspec, $input, true);
break;
}
}
} else {
$xfer += $input->skip($ftype);
}
} else {
$xfer += $input->skip($ftype);
}
$xfer += $input->readFieldEnd();
}
$xfer += $input->readStructEnd();
return $xfer;
}
private function _writeMap($var, $spec, $output)
{
$xfer = 0;
$ktype = $spec['ktype'];
$vtype = $spec['vtype'];
$kwrite = $vwrite = null;
if (isset(TBase::$tmethod[$ktype])) {
$kwrite = 'write' . TBase::$tmethod[$ktype];
} else {
$kspec = $spec['key'];
}
if (isset(TBase::$tmethod[$vtype])) {
$vwrite = 'write' . TBase::$tmethod[$vtype];
} else {
$vspec = $spec['val'];
}
$xfer += $output->writeMapBegin($ktype, $vtype, count($var));
foreach ($var as $key => $val) {
if (isset($kwrite)) {
$xfer += $output->$kwrite($key);
} else {
switch ($ktype) {
case TType::STRUCT:
$xfer += $key->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($key, $kspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($key, $kspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($key, $kspec, $output, true);
break;
}
}
if (isset($vwrite)) {
$xfer += $output->$vwrite($val);
} else {
switch ($vtype) {
case TType::STRUCT:
$xfer += $val->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($val, $vspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($val, $vspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($val, $vspec, $output, true);
break;
}
}
}
$xfer += $output->writeMapEnd();
return $xfer;
}
private function _writeList($var, $spec, $output, $set = false)
{
$xfer = 0;
$etype = $spec['etype'];
$ewrite = null;
if (isset(TBase::$tmethod[$etype])) {
$ewrite = 'write' . TBase::$tmethod[$etype];
} else {
$espec = $spec['elem'];
}
if ($set) {
$xfer += $output->writeSetBegin($etype, count($var));
} else {
$xfer += $output->writeListBegin($etype, count($var));
}
foreach ($var as $key => $val) {
$elem = $set ? $key : $val;
if (isset($ewrite)) {
$xfer += $output->$ewrite($elem);
} else {
switch ($etype) {
case TType::STRUCT:
$xfer += $elem->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($elem, $espec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($elem, $espec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($elem, $espec, $output, true);
break;
}
}
}
if ($set) {
$xfer += $output->writeSetEnd();
} else {
$xfer += $output->writeListEnd();
}
return $xfer;
}
protected function _write($class, $spec, $output)
{
$xfer = 0;
$xfer += $output->writeStructBegin($class);
foreach ($spec as $fid => $fspec) {
$var = $fspec['var'];
if ($this->$var !== null) {
$ftype = $fspec['type'];
$xfer += $output->writeFieldBegin($var, $ftype, $fid);
if (isset(TBase::$tmethod[$ftype])) {
$func = 'write' . TBase::$tmethod[$ftype];
$xfer += $output->$func($this->$var);
} else {
switch ($ftype) {
case TType::STRUCT:
$xfer += $this->$var->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($this->$var, $fspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($this->$var, $fspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($this->$var, $fspec, $output, true);
break;
}
}
$xfer += $output->writeFieldEnd();
}
}
$xfer += $output->writeFieldStop();
$xfer += $output->writeStructEnd();
return $xfer;
}
}

View file

@ -35,16 +35,16 @@ namespace Thrift\Exception;
*/
class TProtocolException extends TException
{
const UNKNOWN = 0;
const INVALID_DATA = 1;
const NEGATIVE_SIZE = 2;
const SIZE_LIMIT = 3;
const BAD_VERSION = 4;
const NOT_IMPLEMENTED = 5;
const DEPTH_LIMIT = 6;
const UNKNOWN = 0;
const INVALID_DATA = 1;
const NEGATIVE_SIZE = 2;
const SIZE_LIMIT = 3;
const BAD_VERSION = 4;
const NOT_IMPLEMENTED = 5;
const DEPTH_LIMIT = 6;
public function __construct($message=null, $code=0)
{
parent::__construct($message, $code);
}
public function __construct($message = null, $code = 0)
{
parent::__construct($message, $code);
}
}

View file

@ -27,14 +27,14 @@ namespace Thrift\Exception;
*/
class TTransportException extends TException
{
const UNKNOWN = 0;
const NOT_OPEN = 1;
const ALREADY_OPEN = 2;
const TIMED_OUT = 3;
const END_OF_FILE = 4;
const UNKNOWN = 0;
const NOT_OPEN = 1;
const ALREADY_OPEN = 2;
const TIMED_OUT = 3;
const END_OF_FILE = 4;
public function __construct($message=null, $code=0)
{
parent::__construct($message, $code);
}
public function __construct($message = null, $code = 0)
{
parent::__construct($message, $code);
}
}

View file

@ -29,17 +29,17 @@ use Thrift\Protocol\TBinaryProtocol;
*/
class TBinaryProtocolFactory implements TProtocolFactory
{
private $strictRead_ = false;
private $strictWrite_ = false;
private $strictRead_ = false;
private $strictWrite_ = false;
public function __construct($strictRead=false, $strictWrite=false)
{
$this->strictRead_ = $strictRead;
$this->strictWrite_ = $strictWrite;
}
public function __construct($strictRead = false, $strictWrite = false)
{
$this->strictRead_ = $strictRead;
$this->strictWrite_ = $strictWrite;
}
public function getProtocol($trans)
{
return new TBinaryProtocol($trans, $this->strictRead_, $this->strictWrite_);
}
public function getProtocol($trans)
{
return new TBinaryProtocol($trans, $this->strictRead_, $this->strictWrite_);
}
}

View file

@ -29,12 +29,12 @@ use Thrift\Protocol\TCompactProtocol;
*/
class TCompactProtocolFactory implements TProtocolFactory
{
public function __construct()
{
}
public function __construct()
{
}
public function getProtocol($trans)
{
return new TCompactProtocol($trans);
}
public function getProtocol($trans)
{
return new TCompactProtocol($trans);
}
}

View file

@ -27,10 +27,10 @@ namespace Thrift\Factory;
*/
interface TProtocolFactory
{
/**
* Build a protocol from the base transport
*
* @return Thrift\Protocol\TProtocol protocol
*/
public function getProtocol($trans);
/**
* Build a protocol from the base transport
*
* @return Thrift\Protocol\TProtocol protocol
*/
public function getProtocol($trans);
}

View file

@ -21,8 +21,9 @@
namespace Thrift\Factory;
use Thrift\StringFunc\Mbstring;
use Thrift\StringFunc\Core;
use Thrift\StringFunc\Mbstring;
use Thrift\StringFunc\TStringFunc;
class TStringFuncFactory
{
@ -49,17 +50,16 @@ class TStringFuncFactory
* 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
* See: http://php.net/manual/en/mbstring.overload.php
*/
if (ini_get('mbstring.func_overload') & 2) {
self::$_instance = new 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 {
} else {
/**
* mbstring is not installed or does not have function overloading
* of the str* functions enabled so use PHP core str* functions for
* byte counting.
*/
self::$_instance = new Core();
}
}

View file

@ -0,0 +1,18 @@
<?php
namespace Thrift\Factory;
use Thrift\Transport\TTransport;
class TTransportFactory
{
/**
* @static
* @param TTransport $transport
* @return TTransport
*/
public static function getTransport(TTransport $transport)
{
return $transport;
}
}

View file

@ -22,8 +22,6 @@
namespace Thrift\Protocol\SimpleJSON;
use Thrift\Protocol\TSimpleJSONProtocol;
class MapContext extends StructContext
{
protected $isKey = true;
@ -47,5 +45,3 @@ class MapContext extends StructContext
return $this->isKey;
}
}

View file

@ -43,11 +43,10 @@ class StructContext extends Context
} else {
$this->p_->getTransport()->write(
$this->colon_ ?
TSimpleJSONProtocol::COLON :
TSimpleJSONProtocol::COMMA
TSimpleJSONProtocol::COLON :
TSimpleJSONProtocol::COMMA
);
$this->colon_ = !$this->colon_;
}
}
}

View file

@ -0,0 +1,453 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.protocol
*/
namespace Thrift\Protocol;
use Thrift\Type\TType;
use Thrift\Exception\TProtocolException;
use Thrift\Factory\TStringFuncFactory;
/**
* Binary implementation of the Thrift protocol.
*
*/
class TBinaryProtocol extends TProtocol
{
const VERSION_MASK = 0xffff0000;
const VERSION_1 = 0x80010000;
protected $strictRead_ = false;
protected $strictWrite_ = true;
public function __construct($trans, $strictRead = false, $strictWrite = true)
{
parent::__construct($trans);
$this->strictRead_ = $strictRead;
$this->strictWrite_ = $strictWrite;
}
public function writeMessageBegin($name, $type, $seqid)
{
if ($this->strictWrite_) {
$version = self::VERSION_1 | $type;
return
$this->writeI32($version) +
$this->writeString($name) +
$this->writeI32($seqid);
} else {
return
$this->writeString($name) +
$this->writeByte($type) +
$this->writeI32($seqid);
}
}
public function writeMessageEnd()
{
return 0;
}
public function writeStructBegin($name)
{
return 0;
}
public function writeStructEnd()
{
return 0;
}
public function writeFieldBegin($fieldName, $fieldType, $fieldId)
{
return
$this->writeByte($fieldType) +
$this->writeI16($fieldId);
}
public function writeFieldEnd()
{
return 0;
}
public function writeFieldStop()
{
return
$this->writeByte(TType::STOP);
}
public function writeMapBegin($keyType, $valType, $size)
{
return
$this->writeByte($keyType) +
$this->writeByte($valType) +
$this->writeI32($size);
}
public function writeMapEnd()
{
return 0;
}
public function writeListBegin($elemType, $size)
{
return
$this->writeByte($elemType) +
$this->writeI32($size);
}
public function writeListEnd()
{
return 0;
}
public function writeSetBegin($elemType, $size)
{
return
$this->writeByte($elemType) +
$this->writeI32($size);
}
public function writeSetEnd()
{
return 0;
}
public function writeBool($value)
{
$data = pack('c', $value ? 1 : 0);
$this->trans_->write($data, 1);
return 1;
}
public function writeByte($value)
{
$data = pack('c', $value);
$this->trans_->write($data, 1);
return 1;
}
public function writeI16($value)
{
$data = pack('n', $value);
$this->trans_->write($data, 2);
return 2;
}
public function writeI32($value)
{
$data = pack('N', $value);
$this->trans_->write($data, 4);
return 4;
}
public function writeI64($value)
{
// If we are on a 32bit architecture we have to explicitly deal with
// 64-bit twos-complement arithmetic since PHP wants to treat all ints
// as signed and any int over 2^31 - 1 as a float
if (PHP_INT_SIZE == 4) {
$neg = $value < 0;
if ($neg) {
$value *= -1;
}
$hi = (int)($value / 4294967296);
$lo = (int)$value;
if ($neg) {
$hi = ~$hi;
$lo = ~$lo;
if (($lo & (int)0xffffffff) == (int)0xffffffff) {
$lo = 0;
$hi++;
} else {
$lo++;
}
}
$data = pack('N2', $hi, $lo);
} else {
$hi = $value >> 32;
$lo = $value & 0xFFFFFFFF;
$data = pack('N2', $hi, $lo);
}
$this->trans_->write($data, 8);
return 8;
}
public function writeDouble($value)
{
$data = pack('d', $value);
$this->trans_->write(strrev($data), 8);
return 8;
}
public function writeString($value)
{
$len = TStringFuncFactory::create()->strlen($value);
$result = $this->writeI32($len);
if ($len) {
$this->trans_->write($value, $len);
}
return $result + $len;
}
public function readMessageBegin(&$name, &$type, &$seqid)
{
$result = $this->readI32($sz);
if ($sz < 0) {
$version = (int)($sz & self::VERSION_MASK);
if ($version != (int)self::VERSION_1) {
throw new TProtocolException('Bad version identifier: ' . $sz, TProtocolException::BAD_VERSION);
}
$type = $sz & 0x000000ff;
$result +=
$this->readString($name) +
$this->readI32($seqid);
} else {
if ($this->strictRead_) {
throw new TProtocolException(
'No version identifier, old protocol client?',
TProtocolException::BAD_VERSION
);
} else {
// Handle pre-versioned input
$name = $this->trans_->readAll($sz);
$result +=
$sz +
$this->readByte($type) +
$this->readI32($seqid);
}
}
return $result;
}
public function readMessageEnd()
{
return 0;
}
public function readStructBegin(&$name)
{
$name = '';
return 0;
}
public function readStructEnd()
{
return 0;
}
public function readFieldBegin(&$name, &$fieldType, &$fieldId)
{
$result = $this->readByte($fieldType);
if ($fieldType == TType::STOP) {
$fieldId = 0;
return $result;
}
$result += $this->readI16($fieldId);
return $result;
}
public function readFieldEnd()
{
return 0;
}
public function readMapBegin(&$keyType, &$valType, &$size)
{
return
$this->readByte($keyType) +
$this->readByte($valType) +
$this->readI32($size);
}
public function readMapEnd()
{
return 0;
}
public function readListBegin(&$elemType, &$size)
{
return
$this->readByte($elemType) +
$this->readI32($size);
}
public function readListEnd()
{
return 0;
}
public function readSetBegin(&$elemType, &$size)
{
return
$this->readByte($elemType) +
$this->readI32($size);
}
public function readSetEnd()
{
return 0;
}
public function readBool(&$value)
{
$data = $this->trans_->readAll(1);
$arr = unpack('c', $data);
$value = $arr[1] == 1;
return 1;
}
public function readByte(&$value)
{
$data = $this->trans_->readAll(1);
$arr = unpack('c', $data);
$value = $arr[1];
return 1;
}
public function readI16(&$value)
{
$data = $this->trans_->readAll(2);
$arr = unpack('n', $data);
$value = $arr[1];
if ($value > 0x7fff) {
$value = 0 - (($value - 1) ^ 0xffff);
}
return 2;
}
public function readI32(&$value)
{
$data = $this->trans_->readAll(4);
$arr = unpack('N', $data);
$value = $arr[1];
if ($value > 0x7fffffff) {
$value = 0 - (($value - 1) ^ 0xffffffff);
}
return 4;
}
public function readI64(&$value)
{
$data = $this->trans_->readAll(8);
$arr = unpack('N2', $data);
// If we are on a 32bit architecture we have to explicitly deal with
// 64-bit twos-complement arithmetic since PHP wants to treat all ints
// as signed and any int over 2^31 - 1 as a float
if (PHP_INT_SIZE == 4) {
$hi = $arr[1];
$lo = $arr[2];
$isNeg = $hi < 0;
// Check for a negative
if ($isNeg) {
$hi = ~$hi & (int)0xffffffff;
$lo = ~$lo & (int)0xffffffff;
if ($lo == (int)0xffffffff) {
$hi++;
$lo = 0;
} else {
$lo++;
}
}
// Force 32bit words in excess of 2G to pe positive - we deal wigh sign
// explicitly below
if ($hi & (int)0x80000000) {
$hi &= (int)0x7fffffff;
$hi += 0x80000000;
}
if ($lo & (int)0x80000000) {
$lo &= (int)0x7fffffff;
$lo += 0x80000000;
}
$value = $hi * 4294967296 + $lo;
if ($isNeg) {
$value = 0 - $value;
}
} else {
// Upcast negatives in LSB bit
if ($arr[2] & 0x80000000) {
$arr[2] = $arr[2] & 0xffffffff;
}
// Check for a negative
if ($arr[1] & 0x80000000) {
$arr[1] = $arr[1] & 0xffffffff;
$arr[1] = $arr[1] ^ 0xffffffff;
$arr[2] = $arr[2] ^ 0xffffffff;
$value = 0 - $arr[1] * 4294967296 - $arr[2] - 1;
} else {
$value = $arr[1] * 4294967296 + $arr[2];
}
}
return 8;
}
public function readDouble(&$value)
{
$data = strrev($this->trans_->readAll(8));
$arr = unpack('d', $data);
$value = $arr[1];
return 8;
}
public function readString(&$value)
{
$result = $this->readI32($len);
if ($len) {
$value = $this->trans_->readAll($len);
} else {
$value = '';
}
return $result + $len;
}
}

View file

@ -0,0 +1,67 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.protocol
*/
namespace Thrift\Protocol;
use Thrift\Transport\TBufferedTransport;
/**
* Accelerated binary protocol: used in conjunction with the thrift_protocol
* extension for faster deserialization
*/
class TBinaryProtocolAccelerated extends TBinaryProtocol
{
public function __construct($trans, $strictRead = false, $strictWrite = true)
{
// If the transport doesn't implement putBack, wrap it in a
// TBufferedTransport (which does)
// NOTE (t.heintz): This is very evil to do, because the TBufferedTransport may swallow bytes, which
// are then never written to the underlying transport. This happens precisely when a number of bytes
// less than the max buffer size (512 by default) is written to the transport and then flush() is NOT
// called. In that case the data stays in the writeBuffer of the transport, from where it can never be
// accessed again (for example through read()).
//
// Since the caller of this method does not know about the wrapping transport, this creates bugs which
// are very difficult to find. Hence the wrapping of a transport in a buffer should be left to the
// calling code. An interface could used to mandate the presence of the putBack() method in the transport.
//
// I am leaving this code in nonetheless, because there may be applications depending on this behavior.
//
// @see THRIFT-1579
if (!method_exists($trans, 'putBack')) {
$trans = new TBufferedTransport($trans);
}
parent::__construct($trans, $strictRead, $strictWrite);
}
public function isStrictRead()
{
return $this->strictRead_;
}
public function isStrictWrite()
{
return $this->strictWrite_;
}
}

View file

@ -0,0 +1,739 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.protocol
*/
namespace Thrift\Protocol;
use Thrift\Type\TType;
use Thrift\Exception\TProtocolException;
use Thrift\Factory\TStringFuncFactory;
/**
* Compact implementation of the Thrift protocol.
*
*/
class TCompactProtocol extends TProtocol
{
const COMPACT_STOP = 0x00;
const COMPACT_TRUE = 0x01;
const COMPACT_FALSE = 0x02;
const COMPACT_BYTE = 0x03;
const COMPACT_I16 = 0x04;
const COMPACT_I32 = 0x05;
const COMPACT_I64 = 0x06;
const COMPACT_DOUBLE = 0x07;
const COMPACT_BINARY = 0x08;
const COMPACT_LIST = 0x09;
const COMPACT_SET = 0x0A;
const COMPACT_MAP = 0x0B;
const COMPACT_STRUCT = 0x0C;
const STATE_CLEAR = 0;
const STATE_FIELD_WRITE = 1;
const STATE_VALUE_WRITE = 2;
const STATE_CONTAINER_WRITE = 3;
const STATE_BOOL_WRITE = 4;
const STATE_FIELD_READ = 5;
const STATE_CONTAINER_READ = 6;
const STATE_VALUE_READ = 7;
const STATE_BOOL_READ = 8;
const VERSION_MASK = 0x1f;
const VERSION = 1;
const PROTOCOL_ID = 0x82;
const TYPE_MASK = 0xe0;
const TYPE_BITS = 0x07;
const TYPE_SHIFT_AMOUNT = 5;
protected static $ctypes = array(
TType::STOP => TCompactProtocol::COMPACT_STOP,
TType::BOOL => TCompactProtocol::COMPACT_TRUE, // used for collection
TType::BYTE => TCompactProtocol::COMPACT_BYTE,
TType::I16 => TCompactProtocol::COMPACT_I16,
TType::I32 => TCompactProtocol::COMPACT_I32,
TType::I64 => TCompactProtocol::COMPACT_I64,
TType::DOUBLE => TCompactProtocol::COMPACT_DOUBLE,
TType::STRING => TCompactProtocol::COMPACT_BINARY,
TType::STRUCT => TCompactProtocol::COMPACT_STRUCT,
TType::LST => TCompactProtocol::COMPACT_LIST,
TType::SET => TCompactProtocol::COMPACT_SET,
TType::MAP => TCompactProtocol::COMPACT_MAP,
);
protected static $ttypes = array(
TCompactProtocol::COMPACT_STOP => TType::STOP,
TCompactProtocol::COMPACT_TRUE => TType::BOOL, // used for collection
TCompactProtocol::COMPACT_FALSE => TType::BOOL,
TCompactProtocol::COMPACT_BYTE => TType::BYTE,
TCompactProtocol::COMPACT_I16 => TType::I16,
TCompactProtocol::COMPACT_I32 => TType::I32,
TCompactProtocol::COMPACT_I64 => TType::I64,
TCompactProtocol::COMPACT_DOUBLE => TType::DOUBLE,
TCompactProtocol::COMPACT_BINARY => TType::STRING,
TCompactProtocol::COMPACT_STRUCT => TType::STRUCT,
TCompactProtocol::COMPACT_LIST => TType::LST,
TCompactProtocol::COMPACT_SET => TType::SET,
TCompactProtocol::COMPACT_MAP => TType::MAP,
);
protected $state = TCompactProtocol::STATE_CLEAR;
protected $lastFid = 0;
protected $boolFid = null;
protected $boolValue = null;
protected $structs = array();
protected $containers = array();
// Some varint / zigzag helper methods
public function toZigZag($n, $bits)
{
return ($n << 1) ^ ($n >> ($bits - 1));
}
public function fromZigZag($n)
{
return ($n >> 1) ^ -($n & 1);
}
public function getVarint($data)
{
$out = "";
while (true) {
if (($data & ~0x7f) === 0) {
$out .= chr($data);
break;
} else {
$out .= chr(($data & 0xff) | 0x80);
$data = $data >> 7;
}
}
return $out;
}
public function writeVarint($data)
{
$out = $this->getVarint($data);
$result = TStringFuncFactory::create()->strlen($out);
$this->trans_->write($out, $result);
return $result;
}
public function readVarint(&$result)
{
$idx = 0;
$shift = 0;
$result = 0;
while (true) {
$x = $this->trans_->readAll(1);
$arr = unpack('C', $x);
$byte = $arr[1];
$idx += 1;
$result |= ($byte & 0x7f) << $shift;
if (($byte >> 7) === 0) {
return $idx;
}
$shift += 7;
}
return $idx;
}
public function __construct($trans)
{
parent::__construct($trans);
}
public function writeMessageBegin($name, $type, $seqid)
{
$written =
$this->writeUByte(TCompactProtocol::PROTOCOL_ID) +
$this->writeUByte(TCompactProtocol::VERSION |
($type << TCompactProtocol::TYPE_SHIFT_AMOUNT)) +
$this->writeVarint($seqid) +
$this->writeString($name);
$this->state = TCompactProtocol::STATE_VALUE_WRITE;
return $written;
}
public function writeMessageEnd()
{
$this->state = TCompactProtocol::STATE_CLEAR;
return 0;
}
public function writeStructBegin($name)
{
$this->structs[] = array($this->state, $this->lastFid);
$this->state = TCompactProtocol::STATE_FIELD_WRITE;
$this->lastFid = 0;
return 0;
}
public function writeStructEnd()
{
$old_values = array_pop($this->structs);
$this->state = $old_values[0];
$this->lastFid = $old_values[1];
return 0;
}
public function writeFieldStop()
{
return $this->writeByte(0);
}
public function writeFieldHeader($type, $fid)
{
$written = 0;
$delta = $fid - $this->lastFid;
if (0 < $delta && $delta <= 15) {
$written = $this->writeUByte(($delta << 4) | $type);
} else {
$written = $this->writeByte($type) +
$this->writeI16($fid);
}
$this->lastFid = $fid;
return $written;
}
public function writeFieldBegin($field_name, $field_type, $field_id)
{
if ($field_type == TTYPE::BOOL) {
$this->state = TCompactProtocol::STATE_BOOL_WRITE;
$this->boolFid = $field_id;
return 0;
} else {
$this->state = TCompactProtocol::STATE_VALUE_WRITE;
return $this->writeFieldHeader(self::$ctypes[$field_type], $field_id);
}
}
public function writeFieldEnd()
{
$this->state = TCompactProtocol::STATE_FIELD_WRITE;
return 0;
}
public function writeCollectionBegin($etype, $size)
{
$written = 0;
if ($size <= 14) {
$written = $this->writeUByte($size << 4 |
self::$ctypes[$etype]);
} else {
$written = $this->writeUByte(0xf0 |
self::$ctypes[$etype]) +
$this->writeVarint($size);
}
$this->containers[] = $this->state;
$this->state = TCompactProtocol::STATE_CONTAINER_WRITE;
return $written;
}
public function writeMapBegin($key_type, $val_type, $size)
{
$written = 0;
if ($size == 0) {
$written = $this->writeByte(0);
} else {
$written = $this->writeVarint($size) +
$this->writeUByte(self::$ctypes[$key_type] << 4 |
self::$ctypes[$val_type]);
}
$this->containers[] = $this->state;
return $written;
}
public function writeCollectionEnd()
{
$this->state = array_pop($this->containers);
return 0;
}
public function writeMapEnd()
{
return $this->writeCollectionEnd();
}
public function writeListBegin($elem_type, $size)
{
return $this->writeCollectionBegin($elem_type, $size);
}
public function writeListEnd()
{
return $this->writeCollectionEnd();
}
public function writeSetBegin($elem_type, $size)
{
return $this->writeCollectionBegin($elem_type, $size);
}
public function writeSetEnd()
{
return $this->writeCollectionEnd();
}
public function writeBool($value)
{
if ($this->state == TCompactProtocol::STATE_BOOL_WRITE) {
$ctype = TCompactProtocol::COMPACT_FALSE;
if ($value) {
$ctype = TCompactProtocol::COMPACT_TRUE;
}
return $this->writeFieldHeader($ctype, $this->boolFid);
} elseif ($this->state == TCompactProtocol::STATE_CONTAINER_WRITE) {
return $this->writeByte($value ? 1 : 0);
} else {
throw new TProtocolException('Invalid state in compact protocol');
}
}
public function writeByte($value)
{
$data = pack('c', $value);
$this->trans_->write($data, 1);
return 1;
}
public function writeUByte($byte)
{
$this->trans_->write(pack('C', $byte), 1);
return 1;
}
public function writeI16($value)
{
$thing = $this->toZigZag($value, 16);
return $this->writeVarint($thing);
}
public function writeI32($value)
{
$thing = $this->toZigZag($value, 32);
return $this->writeVarint($thing);
}
public function writeDouble($value)
{
$data = pack('d', $value);
$this->trans_->write($data, 8);
return 8;
}
public function writeString($value)
{
$len = TStringFuncFactory::create()->strlen($value);
$result = $this->writeVarint($len);
if ($len) {
$this->trans_->write($value, $len);
}
return $result + $len;
}
public function readFieldBegin(&$name, &$field_type, &$field_id)
{
$result = $this->readUByte($compact_type_and_delta);
$compact_type = $compact_type_and_delta & 0x0f;
if ($compact_type == TType::STOP) {
$field_type = $compact_type;
$field_id = 0;
return $result;
}
$delta = $compact_type_and_delta >> 4;
if ($delta == 0) {
$result += $this->readI16($field_id);
} else {
$field_id = $this->lastFid + $delta;
}
$this->lastFid = $field_id;
$field_type = $this->getTType($compact_type);
if ($compact_type == TCompactProtocol::COMPACT_TRUE) {
$this->state = TCompactProtocol::STATE_BOOL_READ;
$this->boolValue = true;
} elseif ($compact_type == TCompactProtocol::COMPACT_FALSE) {
$this->state = TCompactProtocol::STATE_BOOL_READ;
$this->boolValue = false;
} else {
$this->state = TCompactProtocol::STATE_VALUE_READ;
}
return $result;
}
public function readFieldEnd()
{
$this->state = TCompactProtocol::STATE_FIELD_READ;
return 0;
}
public function readUByte(&$value)
{
$data = $this->trans_->readAll(1);
$arr = unpack('C', $data);
$value = $arr[1];
return 1;
}
public function readByte(&$value)
{
$data = $this->trans_->readAll(1);
$arr = unpack('c', $data);
$value = $arr[1];
return 1;
}
public function readZigZag(&$value)
{
$result = $this->readVarint($value);
$value = $this->fromZigZag($value);
return $result;
}
public function readMessageBegin(&$name, &$type, &$seqid)
{
$protoId = 0;
$result = $this->readUByte($protoId);
if ($protoId != TCompactProtocol::PROTOCOL_ID) {
throw new TProtocolException('Bad protocol id in TCompact message');
}
$verType = 0;
$result += $this->readUByte($verType);
$type = ($verType >> TCompactProtocol::TYPE_SHIFT_AMOUNT) & TCompactProtocol::TYPE_BITS;
$version = $verType & TCompactProtocol::VERSION_MASK;
if ($version != TCompactProtocol::VERSION) {
throw new TProtocolException('Bad version in TCompact message');
}
$result += $this->readVarint($seqid);
$result += $this->readString($name);
return $result;
}
public function readMessageEnd()
{
return 0;
}
public function readStructBegin(&$name)
{
$name = ''; // unused
$this->structs[] = array($this->state, $this->lastFid);
$this->state = TCompactProtocol::STATE_FIELD_READ;
$this->lastFid = 0;
return 0;
}
public function readStructEnd()
{
$last = array_pop($this->structs);
$this->state = $last[0];
$this->lastFid = $last[1];
return 0;
}
public function readCollectionBegin(&$type, &$size)
{
$sizeType = 0;
$result = $this->readUByte($sizeType);
$size = $sizeType >> 4;
$type = $this->getTType($sizeType);
if ($size == 15) {
$result += $this->readVarint($size);
}
$this->containers[] = $this->state;
$this->state = TCompactProtocol::STATE_CONTAINER_READ;
return $result;
}
public function readMapBegin(&$key_type, &$val_type, &$size)
{
$result = $this->readVarint($size);
$types = 0;
if ($size > 0) {
$result += $this->readUByte($types);
}
$val_type = $this->getTType($types);
$key_type = $this->getTType($types >> 4);
$this->containers[] = $this->state;
$this->state = TCompactProtocol::STATE_CONTAINER_READ;
return $result;
}
public function readCollectionEnd()
{
$this->state = array_pop($this->containers);
return 0;
}
public function readMapEnd()
{
return $this->readCollectionEnd();
}
public function readListBegin(&$elem_type, &$size)
{
return $this->readCollectionBegin($elem_type, $size);
}
public function readListEnd()
{
return $this->readCollectionEnd();
}
public function readSetBegin(&$elem_type, &$size)
{
return $this->readCollectionBegin($elem_type, $size);
}
public function readSetEnd()
{
return $this->readCollectionEnd();
}
public function readBool(&$value)
{
if ($this->state == TCompactProtocol::STATE_BOOL_READ) {
$value = $this->boolValue;
return 0;
} elseif ($this->state == TCompactProtocol::STATE_CONTAINER_READ) {
return $this->readByte($value);
} else {
throw new TProtocolException('Invalid state in compact protocol');
}
}
public function readI16(&$value)
{
return $this->readZigZag($value);
}
public function readI32(&$value)
{
return $this->readZigZag($value);
}
public function readDouble(&$value)
{
$data = $this->trans_->readAll(8);
$arr = unpack('d', $data);
$value = $arr[1];
return 8;
}
public function readString(&$value)
{
$result = $this->readVarint($len);
if ($len) {
$value = $this->trans_->readAll($len);
} else {
$value = '';
}
return $result + $len;
}
public function getTType($byte)
{
return self::$ttypes[$byte & 0x0f];
}
// If we are on a 32bit architecture we have to explicitly deal with
// 64-bit twos-complement arithmetic since PHP wants to treat all ints
// as signed and any int over 2^31 - 1 as a float
// Read and write I64 as two 32 bit numbers $hi and $lo
public function readI64(&$value)
{
// Read varint from wire
$hi = 0;
$lo = 0;
$idx = 0;
$shift = 0;
while (true) {
$x = $this->trans_->readAll(1);
$arr = unpack('C', $x);
$byte = $arr[1];
$idx += 1;
// Shift hi and lo together.
if ($shift < 28) {
$lo |= (($byte & 0x7f) << $shift);
} elseif ($shift == 28) {
$lo |= (($byte & 0x0f) << 28);
$hi |= (($byte & 0x70) >> 4);
} else {
$hi |= (($byte & 0x7f) << ($shift - 32));
}
if (($byte >> 7) === 0) {
break;
}
$shift += 7;
}
// Now, unzig it.
$xorer = 0;
if ($lo & 1) {
$xorer = 0xffffffff;
}
$lo = ($lo >> 1) & 0x7fffffff;
$lo = $lo | (($hi & 1) << 31);
$hi = ($hi >> 1) ^ $xorer;
$lo = $lo ^ $xorer;
// Now put $hi and $lo back together
$isNeg = $hi < 0 || $hi & 0x80000000;
// Check for a negative
if ($isNeg) {
$hi = ~$hi & (int)0xffffffff;
$lo = ~$lo & (int)0xffffffff;
if ($lo == (int)0xffffffff) {
$hi++;
$lo = 0;
} else {
$lo++;
}
}
// Force 32bit words in excess of 2G to be positive - we deal with sign
// explicitly below
if ($hi & (int)0x80000000) {
$hi &= (int)0x7fffffff;
$hi += 0x80000000;
}
if ($lo & (int)0x80000000) {
$lo &= (int)0x7fffffff;
$lo += 0x80000000;
}
// Create as negative value first, since we can store -2^63 but not 2^63
$value = -$hi * 4294967296 - $lo;
if (!$isNeg) {
$value = -$value;
}
return $idx;
}
public function writeI64($value)
{
// If we are in an I32 range, use the easy method below.
if (($value > 4294967296) || ($value < -4294967296)) {
// Convert $value to $hi and $lo
$neg = $value < 0;
if ($neg) {
$value *= -1;
}
$hi = (int)$value >> 32;
$lo = (int)$value & 0xffffffff;
if ($neg) {
$hi = ~$hi;
$lo = ~$lo;
if (($lo & (int)0xffffffff) == (int)0xffffffff) {
$lo = 0;
$hi++;
} else {
$lo++;
}
}
// Now do the zigging and zagging.
$xorer = 0;
if ($neg) {
$xorer = 0xffffffff;
}
$lowbit = ($lo >> 31) & 1;
$hi = ($hi << 1) | $lowbit;
$lo = ($lo << 1);
$lo = ($lo ^ $xorer) & 0xffffffff;
$hi = ($hi ^ $xorer) & 0xffffffff;
// now write out the varint, ensuring we shift both hi and lo
$out = "";
while (true) {
if (($lo & ~0x7f) === 0 &&
$hi === 0) {
$out .= chr($lo);
break;
} else {
$out .= chr(($lo & 0xff) | 0x80);
$lo = $lo >> 7;
$lo = $lo | ($hi << 25);
$hi = $hi >> 7;
// Right shift carries sign, but we don't want it to.
$hi = $hi & (127 << 25);
}
}
$ret = TStringFuncFactory::create()->strlen($out);
$this->trans_->write($out, $ret);
return $ret;
} else {
return $this->writeVarint($this->toZigZag($value, 64));
}
}
}

View file

@ -217,9 +217,9 @@ class TJSONProtocol extends TProtocol
private function hasJSONUnescapedUnicode()
{
if (PHP_MAJOR_VERSION > 5
|| (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4))
if (PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4)) {
return true;
}
return false;
}
@ -237,18 +237,24 @@ class TJSONProtocol extends TProtocol
* High surrogate: 0xD800 - 0xDBFF
* Low surrogate: 0xDC00 - 0xDFFF
*/
$json = preg_replace_callback('/\\\\u(d[89ab][0-9a-f]{2})\\\\u(d[cdef][0-9a-f]{2})/i',
$json = preg_replace_callback(
'/\\\\u(d[89ab][0-9a-f]{2})\\\\u(d[cdef][0-9a-f]{2})/i',
function ($matches) {
return mb_convert_encoding(pack('H*', $matches[1].$matches[2]), 'UTF-8', 'UTF-16BE');
}, $json);
return mb_convert_encoding(pack('H*', $matches[1] . $matches[2]), 'UTF-8', 'UTF-16BE');
},
$json
);
/*
* Unescaped characters within the Basic Multilingual Plane
*/
$json = preg_replace_callback('/\\\\u([0-9a-f]{4})/i',
$json = preg_replace_callback(
'/\\\\u([0-9a-f]{4})/i',
function ($matches) {
return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UTF-16BE');
}, $json);
},
$json
);
return $json;
}
@ -308,54 +314,54 @@ class TJSONProtocol extends TProtocol
private function writeJSONObjectStart()
{
$this->context_->write();
$this->trans_->write(self::LBRACE);
$this->pushContext(new PairContext($this));
$this->context_->write();
$this->trans_->write(self::LBRACE);
$this->pushContext(new PairContext($this));
}
private function writeJSONObjectEnd()
{
$this->popContext();
$this->trans_->write(self::RBRACE);
$this->popContext();
$this->trans_->write(self::RBRACE);
}
private function writeJSONArrayStart()
{
$this->context_->write();
$this->trans_->write(self::LBRACKET);
$this->pushContext(new ListContext($this));
$this->context_->write();
$this->trans_->write(self::LBRACKET);
$this->pushContext(new ListContext($this));
}
private function writeJSONArrayEnd()
{
$this->popContext();
$this->trans_->write(self::RBRACKET);
$this->popContext();
$this->trans_->write(self::RBRACKET);
}
private function readJSONString($skipContext)
{
if (!$skipContext) {
$this->context_->read();
}
$jsonString = '';
$lastChar = null;
while (true) {
$ch = $this->reader_->read();
$jsonString .= $ch;
if ($ch == self::QUOTE &&
$lastChar !== NULL &&
$lastChar !== self::ESCSEQ) {
break;
if (!$skipContext) {
$this->context_->read();
}
if ($ch == self::ESCSEQ && $lastChar == self::ESCSEQ) {
$lastChar = self::DOUBLEESC;
} else {
$lastChar = $ch;
}
}
return json_decode($jsonString);
$jsonString = '';
$lastChar = null;
while (true) {
$ch = $this->reader_->read();
$jsonString .= $ch;
if ($ch == self::QUOTE &&
$lastChar !== null &&
$lastChar !== self::ESCSEQ) {
break;
}
if ($ch == self::ESCSEQ && $lastChar == self::ESCSEQ) {
$lastChar = self::DOUBLEESC;
} else {
$lastChar = $ch;
}
}
return json_decode($jsonString);
}
private function isJSONNumeric($b)
@ -376,8 +382,8 @@ class TJSONProtocol extends TProtocol
case '9':
case 'E':
case 'e':
return true;
}
return true;
}
return false;
}
@ -459,8 +465,10 @@ class TJSONProtocol extends TProtocol
} elseif ($arr == "Infinity") {
return INF;
} elseif (!$this->context_->escapeNum()) {
throw new TProtocolException("Numeric data unexpectedly quoted " . $arr,
TProtocolException::INVALID_DATA);
throw new TProtocolException(
"Numeric data unexpectedly quoted " . $arr,
TProtocolException::INVALID_DATA
);
}
return floatval($arr);
@ -514,9 +522,9 @@ class TJSONProtocol extends TProtocol
/**
* Writes the message header
*
* @param string $name Function name
* @param int $type message type TMessageType::CALL or TMessageType::REPLY
* @param int $seqid The sequence id of this message
* @param string $name Function name
* @param int $type message type TMessageType::CALL or TMessageType::REPLY
* @param int $seqid The sequence id of this message
*/
public function writeMessageBegin($name, $type, $seqid)
{
@ -538,7 +546,7 @@ class TJSONProtocol extends TProtocol
/**
* Writes a struct header.
*
* @param string $name Struct name
* @param string $name Struct name
* @throws TException on write error
* @return int How many bytes written
*/
@ -652,7 +660,7 @@ class TJSONProtocol extends TProtocol
* Reads the message header
*
* @param string $name Function name
* @param int $type message type TMessageType::CALL or TMessageType::REPLY
* @param int $type message type TMessageType::CALL or TMessageType::REPLY
* @parem int $seqid The sequence id of this message
*/
public function readMessageBegin(&$name, &$type, &$seqid)

View file

@ -0,0 +1,350 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.protocol
*/
namespace Thrift\Protocol;
use Thrift\Type\TType;
use Thrift\Exception\TProtocolException;
/**
* Protocol base class module.
*/
abstract class TProtocol
{
/**
* Underlying transport
*
* @var TTransport
*/
protected $trans_;
/**
* Constructor
*/
protected function __construct($trans)
{
$this->trans_ = $trans;
}
/**
* Accessor for transport
*
* @return TTransport
*/
public function getTransport()
{
return $this->trans_;
}
/**
* Writes the message header
*
* @param string $name Function name
* @param int $type message type TMessageType::CALL or TMessageType::REPLY
* @param int $seqid The sequence id of this message
*/
abstract public function writeMessageBegin($name, $type, $seqid);
/**
* Close the message
*/
abstract public function writeMessageEnd();
/**
* Writes a struct header.
*
* @param string $name Struct name
* @throws TException on write error
* @return int How many bytes written
*/
abstract public function writeStructBegin($name);
/**
* Close a struct.
*
* @throws TException on write error
* @return int How many bytes written
*/
abstract public function writeStructEnd();
/*
* Starts a field.
*
* @param string $name Field name
* @param int $type Field type
* @param int $fid Field id
* @throws TException on write error
* @return int How many bytes written
*/
abstract public function writeFieldBegin($fieldName, $fieldType, $fieldId);
abstract public function writeFieldEnd();
abstract public function writeFieldStop();
abstract public function writeMapBegin($keyType, $valType, $size);
abstract public function writeMapEnd();
abstract public function writeListBegin($elemType, $size);
abstract public function writeListEnd();
abstract public function writeSetBegin($elemType, $size);
abstract public function writeSetEnd();
abstract public function writeBool($bool);
abstract public function writeByte($byte);
abstract public function writeI16($i16);
abstract public function writeI32($i32);
abstract public function writeI64($i64);
abstract public function writeDouble($dub);
abstract public function writeString($str);
/**
* Reads the message header
*
* @param string $name Function name
* @param int $type message type TMessageType::CALL or TMessageType::REPLY
* @parem int $seqid The sequence id of this message
*/
abstract public function readMessageBegin(&$name, &$type, &$seqid);
/**
* Read the close of message
*/
abstract public function readMessageEnd();
abstract public function readStructBegin(&$name);
abstract public function readStructEnd();
abstract public function readFieldBegin(&$name, &$fieldType, &$fieldId);
abstract public function readFieldEnd();
abstract public function readMapBegin(&$keyType, &$valType, &$size);
abstract public function readMapEnd();
abstract public function readListBegin(&$elemType, &$size);
abstract public function readListEnd();
abstract public function readSetBegin(&$elemType, &$size);
abstract public function readSetEnd();
abstract public function readBool(&$bool);
abstract public function readByte(&$byte);
abstract public function readI16(&$i16);
abstract public function readI32(&$i32);
abstract public function readI64(&$i64);
abstract public function readDouble(&$dub);
abstract public function readString(&$str);
/**
* The skip function is a utility to parse over unrecognized date without
* causing corruption.
*
* @param TType $type What type is it
*/
public function skip($type)
{
switch ($type) {
case TType::BOOL:
return $this->readBool($bool);
case TType::BYTE:
return $this->readByte($byte);
case TType::I16:
return $this->readI16($i16);
case TType::I32:
return $this->readI32($i32);
case TType::I64:
return $this->readI64($i64);
case TType::DOUBLE:
return $this->readDouble($dub);
case TType::STRING:
return $this->readString($str);
case TType::STRUCT:
$result = $this->readStructBegin($name);
while (true) {
$result += $this->readFieldBegin($name, $ftype, $fid);
if ($ftype == TType::STOP) {
break;
}
$result += $this->skip($ftype);
$result += $this->readFieldEnd();
}
$result += $this->readStructEnd();
return $result;
case TType::MAP:
$result = $this->readMapBegin($keyType, $valType, $size);
for ($i = 0; $i < $size; $i++) {
$result += $this->skip($keyType);
$result += $this->skip($valType);
}
$result += $this->readMapEnd();
return $result;
case TType::SET:
$result = $this->readSetBegin($elemType, $size);
for ($i = 0; $i < $size; $i++) {
$result += $this->skip($elemType);
}
$result += $this->readSetEnd();
return $result;
case TType::LST:
$result = $this->readListBegin($elemType, $size);
for ($i = 0; $i < $size; $i++) {
$result += $this->skip($elemType);
}
$result += $this->readListEnd();
return $result;
default:
throw new TProtocolException(
'Unknown field type: ' . $type,
TProtocolException::INVALID_DATA
);
}
}
/**
* Utility for skipping binary data
*
* @param TTransport $itrans TTransport object
* @param int $type Field type
*/
public static function skipBinary($itrans, $type)
{
switch ($type) {
case TType::BOOL:
return $itrans->readAll(1);
case TType::BYTE:
return $itrans->readAll(1);
case TType::I16:
return $itrans->readAll(2);
case TType::I32:
return $itrans->readAll(4);
case TType::I64:
return $itrans->readAll(8);
case TType::DOUBLE:
return $itrans->readAll(8);
case TType::STRING:
$len = unpack('N', $itrans->readAll(4));
$len = $len[1];
if ($len > 0x7fffffff) {
$len = 0 - (($len - 1) ^ 0xffffffff);
}
return 4 + $itrans->readAll($len);
case TType::STRUCT:
$result = 0;
while (true) {
$ftype = 0;
$fid = 0;
$data = $itrans->readAll(1);
$arr = unpack('c', $data);
$ftype = $arr[1];
if ($ftype == TType::STOP) {
break;
}
// I16 field id
$result += $itrans->readAll(2);
$result += self::skipBinary($itrans, $ftype);
}
return $result;
case TType::MAP:
// Ktype
$data = $itrans->readAll(1);
$arr = unpack('c', $data);
$ktype = $arr[1];
// Vtype
$data = $itrans->readAll(1);
$arr = unpack('c', $data);
$vtype = $arr[1];
// Size
$data = $itrans->readAll(4);
$arr = unpack('N', $data);
$size = $arr[1];
if ($size > 0x7fffffff) {
$size = 0 - (($size - 1) ^ 0xffffffff);
}
$result = 6;
for ($i = 0; $i < $size; $i++) {
$result += self::skipBinary($itrans, $ktype);
$result += self::skipBinary($itrans, $vtype);
}
return $result;
case TType::SET:
case TType::LST:
// Vtype
$data = $itrans->readAll(1);
$arr = unpack('c', $data);
$vtype = $arr[1];
// Size
$data = $itrans->readAll(4);
$arr = unpack('N', $data);
$size = $arr[1];
if ($size > 0x7fffffff) {
$size = 0 - (($size - 1) ^ 0xffffffff);
}
$result = 5;
for ($i = 0; $i < $size; $i++) {
$result += self::skipBinary($itrans, $vtype);
}
return $result;
default:
throw new TProtocolException(
'Unknown field type: ' . $type,
TProtocolException::INVALID_DATA
);
}
}
}

View file

@ -21,6 +21,7 @@
*/
namespace Thrift\Protocol;
use Thrift\Exception\TException;
/**

View file

@ -54,7 +54,8 @@ class TSimpleJSONProtocol extends TProtocol
/**
* Push a new write context onto the stack.
*/
protected function pushWriteContext(Context $c) {
protected function pushWriteContext(Context $c)
{
$this->writeContextStack_[] = $this->writeContext_;
$this->writeContext_ = $c;
}
@ -62,14 +63,16 @@ class TSimpleJSONProtocol extends TProtocol
/**
* Pop the last write context off the stack
*/
protected function popWriteContext() {
protected function popWriteContext()
{
$this->writeContext_ = array_pop($this->writeContextStack_);
}
/**
* Used to make sure that we are not encountering a map whose keys are containers
*/
protected function assertContextIsNotMapKey($invalidKeyType) {
protected function assertContextIsNotMapKey($invalidKeyType)
{
if ($this->writeContext_->isMapKey()) {
throw new CollectionMapKeyException(
"Cannot serialize a map with keys that are of type " .

View file

@ -0,0 +1,87 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.protocol
* @author: rmarin (marin.radu@facebook.com)
*/
namespace Thrift\Serializer;
use Thrift\Transport\TMemoryBuffer;
use Thrift\Protocol\TBinaryProtocolAccelerated;
use Thrift\Type\TMessageType;
/**
* Utility class for serializing and deserializing
* a thrift object using TBinaryProtocolAccelerated.
*/
class TBinarySerializer
{
// NOTE(rmarin): Because thrift_protocol_write_binary
// adds a begin message prefix, you cannot specify
// a transport in which to serialize an object. It has to
// be a string. Otherwise we will break the compatibility with
// normal deserialization.
public static function serialize($object)
{
$transport = new TMemoryBuffer();
$protocol = new TBinaryProtocolAccelerated($transport);
if (function_exists('thrift_protocol_write_binary')) {
thrift_protocol_write_binary(
$protocol,
$object->getName(),
TMessageType::REPLY,
$object,
0,
$protocol->isStrictWrite()
);
$protocol->readMessageBegin($unused_name, $unused_type, $unused_seqid);
} else {
$object->write($protocol);
}
$protocol->getTransport()->flush();
return $transport->getBuffer();
}
public static function deserialize($string_object, $class_name, $buffer_size = 8192)
{
$transport = new TMemoryBuffer();
$protocol = new TBinaryProtocolAccelerated($transport);
if (function_exists('thrift_protocol_read_binary')) {
// NOTE (t.heintz) TBinaryProtocolAccelerated internally wraps our TMemoryBuffer in a
// TBufferedTransport, so we have to retrieve it again or risk losing data when writing
// less than 512 bytes to the transport (see the comment there as well).
// @see THRIFT-1579
$protocol->writeMessageBegin('', TMessageType::REPLY, 0);
$protocolTransport = $protocol->getTransport();
$protocolTransport->write($string_object);
$protocolTransport->flush();
return thrift_protocol_read_binary($protocol, $class_name, $protocol->isStrictRead(), $buffer_size);
} else {
$transport->write($string_object);
$object = new $class_name();
$object->read($protocol);
return $object;
}
}
}

View file

@ -0,0 +1,125 @@
<?php
namespace Thrift\Server;
use Thrift\Transport\TTransport;
use Thrift\Exception\TException;
use Thrift\Exception\TTransportException;
/**
* A forking implementation of a Thrift server.
*
* @package thrift.server
*/
class TForkingServer extends TServer
{
/**
* Flag for the main serving loop
*
* @var bool
*/
private $stop_ = false;
/**
* List of children.
*
* @var array
*/
protected $children_ = array();
/**
* Listens for new client using the supplied
* transport. We fork when a new connection
* arrives.
*
* @return void
*/
public function serve()
{
$this->transport_->listen();
while (!$this->stop_) {
try {
$transport = $this->transport_->accept();
if ($transport != null) {
$pid = pcntl_fork();
if ($pid > 0) {
$this->handleParent($transport, $pid);
} elseif ($pid === 0) {
$this->handleChild($transport);
} else {
throw new TException('Failed to fork');
}
}
} catch (TTransportException $e) {
}
$this->collectChildren();
}
}
/**
* Code run by the parent
*
* @param TTransport $transport
* @param int $pid
* @return void
*/
private function handleParent(TTransport $transport, $pid)
{
$this->children_[$pid] = $transport;
}
/**
* Code run by the child.
*
* @param TTransport $transport
* @return void
*/
private function handleChild(TTransport $transport)
{
try {
$inputTransport = $this->inputTransportFactory_->getTransport($transport);
$outputTransport = $this->outputTransportFactory_->getTransport($transport);
$inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport);
$outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport);
while ($this->processor_->process($inputProtocol, $outputProtocol)) {
}
@$transport->close();
} catch (TTransportException $e) {
}
exit(0);
}
/**
* Collects any children we may have
*
* @return void
*/
private function collectChildren()
{
foreach ($this->children_ as $pid => $transport) {
if (pcntl_waitpid($pid, $status, WNOHANG) > 0) {
unset($this->children_[$pid]);
if ($transport) {
@$transport->close();
}
}
}
}
/**
* Stops the server running. Kills the transport
* and then stops the main serving loop
*
* @return void
*/
public function stop()
{
$this->transport_->close();
$this->stop_ = true;
}
}

View file

@ -0,0 +1,97 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
namespace Thrift\Server;
use Thrift\Transport\TSSLSocket;
/**
* Socket implementation of a server agent.
*
* @package thrift.transport
*/
class TSSLServerSocket extends TServerSocket
{
/**
* Remote port
*
* @var resource
*/
protected $context_ = null;
/**
* ServerSocket constructor
*
* @param string $host Host to listen on
* @param int $port Port to listen on
* @param resource $context Stream context
* @return void
*/
public function __construct($host = 'localhost', $port = 9090, $context = null)
{
$ssl_host = $this->getSSLHost($host);
parent::__construct($ssl_host, $port);
$this->context_ = $context;
}
public function getSSLHost($host)
{
$transport_protocol_loc = strpos($host, "://");
if ($transport_protocol_loc === false) {
$host = 'ssl://' . $host;
}
return $host;
}
/**
* Opens a new socket server handle
*
* @return void
*/
public function listen()
{
$this->listener_ = @stream_socket_server(
$this->host_ . ':' . $this->port_,
$errno,
$errstr,
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN,
$this->context_
);
}
/**
* Implementation of accept. If not client is accepted in the given time
*
* @return TSocket
*/
protected function acceptImpl()
{
$handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0);
if (!$handle) {
return null;
}
$socket = new TSSLSocket();
$socket->setHandle($handle);
return $socket;
}
}

View file

@ -0,0 +1,102 @@
<?php
namespace Thrift\Server;
use Thrift\Factory\TTransportFactory;
use Thrift\Factory\TProtocolFactory;
/**
* Generic class for a Thrift server.
*
* @package thrift.server
*/
abstract class TServer
{
/**
* Processor to handle new clients
*
* @var TProcessor
*/
protected $processor_;
/**
* Server transport to be used for listening
* and accepting new clients
*
* @var TServerTransport
*/
protected $transport_;
/**
* Input transport factory
*
* @var TTransportFactory
*/
protected $inputTransportFactory_;
/**
* Output transport factory
*
* @var TTransportFactory
*/
protected $outputTransportFactory_;
/**
* Input protocol factory
*
* @var TProtocolFactory
*/
protected $inputProtocolFactory_;
/**
* Output protocol factory
*
* @var TProtocolFactory
*/
protected $outputProtocolFactory_;
/**
* Sets up all the factories, etc
*
* @param object $processor
* @param TServerTransport $transport
* @param TTransportFactory $inputTransportFactory
* @param TTransportFactory $outputTransportFactory
* @param TProtocolFactory $inputProtocolFactory
* @param TProtocolFactory $outputProtocolFactory
* @return void
*/
public function __construct(
$processor,
TServerTransport $transport,
TTransportFactory $inputTransportFactory,
TTransportFactory $outputTransportFactory,
TProtocolFactory $inputProtocolFactory,
TProtocolFactory $outputProtocolFactory
) {
$this->processor_ = $processor;
$this->transport_ = $transport;
$this->inputTransportFactory_ = $inputTransportFactory;
$this->outputTransportFactory_ = $outputTransportFactory;
$this->inputProtocolFactory_ = $inputProtocolFactory;
$this->outputProtocolFactory_ = $outputProtocolFactory;
}
/**
* Serves the server. This should never return
* unless a problem permits it to do so or it
* is interrupted intentionally
*
* @abstract
* @return void
*/
abstract public function serve();
/**
* Stops the server serving
*
* @abstract
* @return void
*/
abstract public function stop();
}

View file

@ -0,0 +1,124 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Server;
use Thrift\Transport\TSocket;
/**
* Socket implementation of a server agent.
*
* @package thrift.transport
*/
class TServerSocket extends TServerTransport
{
/**
* Handle for the listener socket
*
* @var resource
*/
protected $listener_;
/**
* Port for the listener to listen on
*
* @var int
*/
protected $port_;
/**
* Timeout when listening for a new client
*
* @var int
*/
protected $acceptTimeout_ = 30000;
/**
* Host to listen on
*
* @var string
*/
protected $host_;
/**
* ServerSocket constructor
*
* @param string $host Host to listen on
* @param int $port Port to listen on
* @return void
*/
public function __construct($host = 'localhost', $port = 9090)
{
$this->host_ = $host;
$this->port_ = $port;
}
/**
* Sets the accept timeout
*
* @param int $acceptTimeout
* @return void
*/
public function setAcceptTimeout($acceptTimeout)
{
$this->acceptTimeout_ = $acceptTimeout;
}
/**
* Opens a new socket server handle
*
* @return void
*/
public function listen()
{
$this->listener_ = stream_socket_server('tcp://' . $this->host_ . ':' . $this->port_);
}
/**
* Closes the socket server handle
*
* @return void
*/
public function close()
{
@fclose($this->listener_);
$this->listener_ = null;
}
/**
* Implementation of accept. If not client is accepted in the given time
*
* @return TSocket
*/
protected function acceptImpl()
{
$handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0);
if (!$handle) {
return null;
}
$socket = new TSocket();
$socket->setHandle($handle);
return $socket;
}
}

View file

@ -0,0 +1,56 @@
<?php
namespace Thrift\Server;
use Thrift\Exception\TTransportException;
/**
* Generic class for Server agent.
*
* @package thrift.transport
*/
abstract class TServerTransport
{
/**
* List for new clients
*
* @abstract
* @return void
*/
abstract public function listen();
/**
* Close the server
*
* @abstract
* @return void
*/
abstract public function close();
/**
* Subclasses should use this to implement
* accept.
*
* @abstract
* @return TTransport
*/
abstract protected function acceptImpl();
/**
* Uses the accept implemtation. If null is returned, an
* exception is thrown.
*
* @throws TTransportException
* @return TTransport
*/
public function accept()
{
$transport = $this->acceptImpl();
if ($transport == null) {
throw new TTransportException("accept() may not return NULL");
}
return $transport;
}
}

View file

@ -0,0 +1,60 @@
<?php
namespace Thrift\Server;
use Thrift\Exception\TTransportException;
/**
* Simple implemtation of a Thrift server.
*
* @package thrift.server
*/
class TSimpleServer extends TServer
{
/**
* Flag for the main serving loop
*
* @var bool
*/
private $stop_ = false;
/**
* Listens for new client using the supplied
* transport. It handles TTransportExceptions
* to avoid timeouts etc killing it
*
* @return void
*/
public function serve()
{
$this->transport_->listen();
while (!$this->stop_) {
try {
$transport = $this->transport_->accept();
if ($transport != null) {
$inputTransport = $this->inputTransportFactory_->getTransport($transport);
$outputTransport = $this->outputTransportFactory_->getTransport($transport);
$inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport);
$outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport);
while ($this->processor_->process($inputProtocol, $outputProtocol)) {
}
}
} catch (TTransportException $e) {
}
}
}
/**
* Stops the server running. Kills the transport
* and then stops the main serving loop
*
* @return void
*/
public function stop()
{
$this->transport_->close();
$this->stop_ = true;
}
}

View file

@ -0,0 +1,53 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.processor
*/
namespace Thrift;
use Thrift\Protocol\TProtocol;
use Thrift\Protocol\TProtocolDecorator;
/**
* Our goal was to work with any protocol. In order to do that, we needed
* to allow them to call readMessageBegin() and get the Message in exactly
* the standard format, without the service name prepended to the Message name.
*/
class StoredMessageProtocol extends TProtocolDecorator
{
private $fname_;
private $mtype_;
private $rseqid_;
public function __construct(TProtocol $protocol, $fname, $mtype, $rseqid)
{
parent::__construct($protocol);
$this->fname_ = $fname;
$this->mtype_ = $mtype;
$this->rseqid_ = $rseqid;
}
public function readMessageBegin(&$name, &$type, &$seqid)
{
$name = $this->fname_;
$type = $this->mtype_;
$seqid = $this->rseqid_;
}
}

View file

@ -25,7 +25,6 @@ namespace Thrift;
use Thrift\Exception\TException;
use Thrift\Protocol\TProtocol;
use Thrift\Protocol\TMultiplexedProtocol;
use Thrift\Protocol\TProtocolDecorator;
use Thrift\Type\TMessageType;
/**
@ -112,32 +111,8 @@ class TMultiplexedProcessor
$processor = $this->serviceProcessorMap_[$serviceName];
return $processor->process(
new StoredMessageProtocol($input, $messageName, $mtype, $rseqid), $output
new StoredMessageProtocol($input, $messageName, $mtype, $rseqid),
$output
);
}
}
/**
* Our goal was to work with any protocol. In order to do that, we needed
* to allow them to call readMessageBegin() and get the Message in exactly
* the standard format, without the service name prepended to the Message name.
*/
class StoredMessageProtocol extends TProtocolDecorator
{
private $fname_, $mtype_, $rseqid_;
public function __construct(TProtocol $protocol, $fname, $mtype, $rseqid)
{
parent::__construct($protocol);
$this->fname_ = $fname;
$this->mtype_ = $mtype;
$this->rseqid_ = $rseqid;
}
public function readMessageBegin(&$name, &$type, &$seqid)
{
$name = $this->fname_;
$type = $this->mtype_;
$seqid = $this->rseqid_;
}
}

View file

@ -1,380 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift
*/
namespace Thrift\Base;
use Thrift\Type\TType;
/**
* Base class from which other Thrift structs extend. This is so that we can
* cut back on the size of the generated code which is turning out to have a
* nontrivial cost just to load thanks to the wondrously abysmal implementation
* of PHP. Note that code is intentionally duplicated in here to avoid making
* function calls for every field or member of a container..
*/
abstract class TBase
{
static $tmethod = array(TType::BOOL => 'Bool',
TType::BYTE => 'Byte',
TType::I16 => 'I16',
TType::I32 => 'I32',
TType::I64 => 'I64',
TType::DOUBLE => 'Double',
TType::STRING => 'String');
abstract public function read($input);
abstract public function write($output);
public function __construct($spec=null, $vals=null)
{
if (is_array($spec) && is_array($vals)) {
foreach ($spec as $fid => $fspec) {
$var = $fspec['var'];
if (isset($vals[$var])) {
$this->$var = $vals[$var];
}
}
}
}
public function __wakeup()
{
$this->__construct(get_object_vars($this));
}
private function _readMap(&$var, $spec, $input)
{
$xfer = 0;
$ktype = $spec['ktype'];
$vtype = $spec['vtype'];
$kread = $vread = null;
if (isset(TBase::$tmethod[$ktype])) {
$kread = 'read'.TBase::$tmethod[$ktype];
} else {
$kspec = $spec['key'];
}
if (isset(TBase::$tmethod[$vtype])) {
$vread = 'read'.TBase::$tmethod[$vtype];
} else {
$vspec = $spec['val'];
}
$var = array();
$_ktype = $_vtype = $size = 0;
$xfer += $input->readMapBegin($_ktype, $_vtype, $size);
for ($i = 0; $i < $size; ++$i) {
$key = $val = null;
if ($kread !== null) {
$xfer += $input->$kread($key);
} else {
switch ($ktype) {
case TType::STRUCT:
$class = $kspec['class'];
$key = new $class();
$xfer += $key->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($key, $kspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($key, $kspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($key, $kspec, $input, true);
break;
}
}
if ($vread !== null) {
$xfer += $input->$vread($val);
} else {
switch ($vtype) {
case TType::STRUCT:
$class = $vspec['class'];
$val = new $class();
$xfer += $val->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($val, $vspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($val, $vspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($val, $vspec, $input, true);
break;
}
}
$var[$key] = $val;
}
$xfer += $input->readMapEnd();
return $xfer;
}
private function _readList(&$var, $spec, $input, $set=false)
{
$xfer = 0;
$etype = $spec['etype'];
$eread = $vread = null;
if (isset(TBase::$tmethod[$etype])) {
$eread = 'read'.TBase::$tmethod[$etype];
} else {
$espec = $spec['elem'];
}
$var = array();
$_etype = $size = 0;
if ($set) {
$xfer += $input->readSetBegin($_etype, $size);
} else {
$xfer += $input->readListBegin($_etype, $size);
}
for ($i = 0; $i < $size; ++$i) {
$elem = null;
if ($eread !== null) {
$xfer += $input->$eread($elem);
} else {
$espec = $spec['elem'];
switch ($etype) {
case TType::STRUCT:
$class = $espec['class'];
$elem = new $class();
$xfer += $elem->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($elem, $espec, $input);
break;
case TType::LST:
$xfer += $this->_readList($elem, $espec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($elem, $espec, $input, true);
break;
}
}
if ($set) {
$var[$elem] = true;
} else {
$var []= $elem;
}
}
if ($set) {
$xfer += $input->readSetEnd();
} else {
$xfer += $input->readListEnd();
}
return $xfer;
}
protected function _read($class, $spec, $input)
{
$xfer = 0;
$fname = null;
$ftype = 0;
$fid = 0;
$xfer += $input->readStructBegin($fname);
while (true) {
$xfer += $input->readFieldBegin($fname, $ftype, $fid);
if ($ftype == TType::STOP) {
break;
}
if (isset($spec[$fid])) {
$fspec = $spec[$fid];
$var = $fspec['var'];
if ($ftype == $fspec['type']) {
$xfer = 0;
if (isset(TBase::$tmethod[$ftype])) {
$func = 'read'.TBase::$tmethod[$ftype];
$xfer += $input->$func($this->$var);
} else {
switch ($ftype) {
case TType::STRUCT:
$class = $fspec['class'];
$this->$var = new $class();
$xfer += $this->$var->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($this->$var, $fspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($this->$var, $fspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($this->$var, $fspec, $input, true);
break;
}
}
} else {
$xfer += $input->skip($ftype);
}
} else {
$xfer += $input->skip($ftype);
}
$xfer += $input->readFieldEnd();
}
$xfer += $input->readStructEnd();
return $xfer;
}
private function _writeMap($var, $spec, $output)
{
$xfer = 0;
$ktype = $spec['ktype'];
$vtype = $spec['vtype'];
$kwrite = $vwrite = null;
if (isset(TBase::$tmethod[$ktype])) {
$kwrite = 'write'.TBase::$tmethod[$ktype];
} else {
$kspec = $spec['key'];
}
if (isset(TBase::$tmethod[$vtype])) {
$vwrite = 'write'.TBase::$tmethod[$vtype];
} else {
$vspec = $spec['val'];
}
$xfer += $output->writeMapBegin($ktype, $vtype, count($var));
foreach ($var as $key => $val) {
if (isset($kwrite)) {
$xfer += $output->$kwrite($key);
} else {
switch ($ktype) {
case TType::STRUCT:
$xfer += $key->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($key, $kspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($key, $kspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($key, $kspec, $output, true);
break;
}
}
if (isset($vwrite)) {
$xfer += $output->$vwrite($val);
} else {
switch ($vtype) {
case TType::STRUCT:
$xfer += $val->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($val, $vspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($val, $vspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($val, $vspec, $output, true);
break;
}
}
}
$xfer += $output->writeMapEnd();
return $xfer;
}
private function _writeList($var, $spec, $output, $set=false)
{
$xfer = 0;
$etype = $spec['etype'];
$ewrite = null;
if (isset(TBase::$tmethod[$etype])) {
$ewrite = 'write'.TBase::$tmethod[$etype];
} else {
$espec = $spec['elem'];
}
if ($set) {
$xfer += $output->writeSetBegin($etype, count($var));
} else {
$xfer += $output->writeListBegin($etype, count($var));
}
foreach ($var as $key => $val) {
$elem = $set ? $key : $val;
if (isset($ewrite)) {
$xfer += $output->$ewrite($elem);
} else {
switch ($etype) {
case TType::STRUCT:
$xfer += $elem->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($elem, $espec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($elem, $espec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($elem, $espec, $output, true);
break;
}
}
}
if ($set) {
$xfer += $output->writeSetEnd();
} else {
$xfer += $output->writeListEnd();
}
return $xfer;
}
protected function _write($class, $spec, $output)
{
$xfer = 0;
$xfer += $output->writeStructBegin($class);
foreach ($spec as $fid => $fspec) {
$var = $fspec['var'];
if ($this->$var !== null) {
$ftype = $fspec['type'];
$xfer += $output->writeFieldBegin($var, $ftype, $fid);
if (isset(TBase::$tmethod[$ftype])) {
$func = 'write'.TBase::$tmethod[$ftype];
$xfer += $output->$func($this->$var);
} else {
switch ($ftype) {
case TType::STRUCT:
$xfer += $this->$var->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($this->$var, $fspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($this->$var, $fspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($this->$var, $fspec, $output, true);
break;
}
}
$xfer += $output->writeFieldEnd();
}
}
$xfer += $output->writeFieldStop();
$xfer += $output->writeStructEnd();
return $xfer;
}
}

View file

@ -1,76 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift
*/
namespace Thrift\Exception;
use Thrift\Type\TType;
class TApplicationException extends TException
{
static $_TSPEC =
array(1 => array('var' => 'message',
'type' => TType::STRING),
2 => array('var' => 'code',
'type' => TType::I32));
const UNKNOWN = 0;
const UNKNOWN_METHOD = 1;
const INVALID_MESSAGE_TYPE = 2;
const WRONG_METHOD_NAME = 3;
const BAD_SEQUENCE_ID = 4;
const MISSING_RESULT = 5;
const INTERNAL_ERROR = 6;
const PROTOCOL_ERROR = 7;
const INVALID_TRANSFORM = 8;
const INVALID_PROTOCOL = 9;
const UNSUPPORTED_CLIENT_TYPE = 10;
public function __construct($message=null, $code=0)
{
parent::__construct($message, $code);
}
public function read($output)
{
return $this->_read('TApplicationException', self::$_TSPEC, $output);
}
public function write($output)
{
$xfer = 0;
$xfer += $output->writeStructBegin('TApplicationException');
if ($message = $this->getMessage()) {
$xfer += $output->writeFieldBegin('message', TType::STRING, 1);
$xfer += $output->writeString($message);
$xfer += $output->writeFieldEnd();
}
if ($code = $this->getCode()) {
$xfer += $output->writeFieldBegin('type', TType::I32, 2);
$xfer += $output->writeI32($code);
$xfer += $output->writeFieldEnd();
}
$xfer += $output->writeFieldStop();
$xfer += $output->writeStructEnd();
return $xfer;
}
}

View file

@ -1,383 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift
*/
namespace Thrift\Exception;
use Thrift\Type\TType;
use Thrift\Base\TBase;
/**
* NOTE(mcslee): This currently contains a ton of duplicated code from TBase
* because we need to save CPU cycles and this is not yet in an extension.
* Ideally we'd multiply-inherit TException from both Exception and Base, but
* that's not possible in PHP and there are no modules either, so for now we
* apologetically take a trip to HackTown.
*
* Can be called with standard Exception constructor (message, code) or with
* Thrift Base object constructor (spec, vals).
*
* @param mixed $p1 Message (string) or type-spec (array)
* @param mixed $p2 Code (integer) or values (array)
*/
class TException extends \Exception
{
public function __construct($p1=null, $p2=0)
{
if (is_array($p1) && is_array($p2)) {
$spec = $p1;
$vals = $p2;
foreach ($spec as $fid => $fspec) {
$var = $fspec['var'];
if (isset($vals[$var])) {
$this->$var = $vals[$var];
}
}
} else {
parent::__construct($p1, $p2);
}
}
static $tmethod = array(TType::BOOL => 'Bool',
TType::BYTE => 'Byte',
TType::I16 => 'I16',
TType::I32 => 'I32',
TType::I64 => 'I64',
TType::DOUBLE => 'Double',
TType::STRING => 'String');
private function _readMap(&$var, $spec, $input)
{
$xfer = 0;
$ktype = $spec['ktype'];
$vtype = $spec['vtype'];
$kread = $vread = null;
if (isset(TBase::$tmethod[$ktype])) {
$kread = 'read'.TBase::$tmethod[$ktype];
} else {
$kspec = $spec['key'];
}
if (isset(TBase::$tmethod[$vtype])) {
$vread = 'read'.TBase::$tmethod[$vtype];
} else {
$vspec = $spec['val'];
}
$var = array();
$_ktype = $_vtype = $size = 0;
$xfer += $input->readMapBegin($_ktype, $_vtype, $size);
for ($i = 0; $i < $size; ++$i) {
$key = $val = null;
if ($kread !== null) {
$xfer += $input->$kread($key);
} else {
switch ($ktype) {
case TType::STRUCT:
$class = $kspec['class'];
$key = new $class();
$xfer += $key->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($key, $kspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($key, $kspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($key, $kspec, $input, true);
break;
}
}
if ($vread !== null) {
$xfer += $input->$vread($val);
} else {
switch ($vtype) {
case TType::STRUCT:
$class = $vspec['class'];
$val = new $class();
$xfer += $val->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($val, $vspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($val, $vspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($val, $vspec, $input, true);
break;
}
}
$var[$key] = $val;
}
$xfer += $input->readMapEnd();
return $xfer;
}
private function _readList(&$var, $spec, $input, $set=false)
{
$xfer = 0;
$etype = $spec['etype'];
$eread = $vread = null;
if (isset(TBase::$tmethod[$etype])) {
$eread = 'read'.TBase::$tmethod[$etype];
} else {
$espec = $spec['elem'];
}
$var = array();
$_etype = $size = 0;
if ($set) {
$xfer += $input->readSetBegin($_etype, $size);
} else {
$xfer += $input->readListBegin($_etype, $size);
}
for ($i = 0; $i < $size; ++$i) {
$elem = null;
if ($eread !== null) {
$xfer += $input->$eread($elem);
} else {
$espec = $spec['elem'];
switch ($etype) {
case TType::STRUCT:
$class = $espec['class'];
$elem = new $class();
$xfer += $elem->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($elem, $espec, $input);
break;
case TType::LST:
$xfer += $this->_readList($elem, $espec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($elem, $espec, $input, true);
break;
}
}
if ($set) {
$var[$elem] = true;
} else {
$var []= $elem;
}
}
if ($set) {
$xfer += $input->readSetEnd();
} else {
$xfer += $input->readListEnd();
}
return $xfer;
}
protected function _read($class, $spec, $input)
{
$xfer = 0;
$fname = null;
$ftype = 0;
$fid = 0;
$xfer += $input->readStructBegin($fname);
while (true) {
$xfer += $input->readFieldBegin($fname, $ftype, $fid);
if ($ftype == TType::STOP) {
break;
}
if (isset($spec[$fid])) {
$fspec = $spec[$fid];
$var = $fspec['var'];
if ($ftype == $fspec['type']) {
$xfer = 0;
if (isset(TBase::$tmethod[$ftype])) {
$func = 'read'.TBase::$tmethod[$ftype];
$xfer += $input->$func($this->$var);
} else {
switch ($ftype) {
case TType::STRUCT:
$class = $fspec['class'];
$this->$var = new $class();
$xfer += $this->$var->read($input);
break;
case TType::MAP:
$xfer += $this->_readMap($this->$var, $fspec, $input);
break;
case TType::LST:
$xfer += $this->_readList($this->$var, $fspec, $input, false);
break;
case TType::SET:
$xfer += $this->_readList($this->$var, $fspec, $input, true);
break;
}
}
} else {
$xfer += $input->skip($ftype);
}
} else {
$xfer += $input->skip($ftype);
}
$xfer += $input->readFieldEnd();
}
$xfer += $input->readStructEnd();
return $xfer;
}
private function _writeMap($var, $spec, $output)
{
$xfer = 0;
$ktype = $spec['ktype'];
$vtype = $spec['vtype'];
$kwrite = $vwrite = null;
if (isset(TBase::$tmethod[$ktype])) {
$kwrite = 'write'.TBase::$tmethod[$ktype];
} else {
$kspec = $spec['key'];
}
if (isset(TBase::$tmethod[$vtype])) {
$vwrite = 'write'.TBase::$tmethod[$vtype];
} else {
$vspec = $spec['val'];
}
$xfer += $output->writeMapBegin($ktype, $vtype, count($var));
foreach ($var as $key => $val) {
if (isset($kwrite)) {
$xfer += $output->$kwrite($key);
} else {
switch ($ktype) {
case TType::STRUCT:
$xfer += $key->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($key, $kspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($key, $kspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($key, $kspec, $output, true);
break;
}
}
if (isset($vwrite)) {
$xfer += $output->$vwrite($val);
} else {
switch ($vtype) {
case TType::STRUCT:
$xfer += $val->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($val, $vspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($val, $vspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($val, $vspec, $output, true);
break;
}
}
}
$xfer += $output->writeMapEnd();
return $xfer;
}
private function _writeList($var, $spec, $output, $set=false)
{
$xfer = 0;
$etype = $spec['etype'];
$ewrite = null;
if (isset(TBase::$tmethod[$etype])) {
$ewrite = 'write'.TBase::$tmethod[$etype];
} else {
$espec = $spec['elem'];
}
if ($set) {
$xfer += $output->writeSetBegin($etype, count($var));
} else {
$xfer += $output->writeListBegin($etype, count($var));
}
foreach ($var as $key => $val) {
$elem = $set ? $key : $val;
if (isset($ewrite)) {
$xfer += $output->$ewrite($elem);
} else {
switch ($etype) {
case TType::STRUCT:
$xfer += $elem->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($elem, $espec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($elem, $espec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($elem, $espec, $output, true);
break;
}
}
}
if ($set) {
$xfer += $output->writeSetEnd();
} else {
$xfer += $output->writeListEnd();
}
return $xfer;
}
protected function _write($class, $spec, $output)
{
$xfer = 0;
$xfer += $output->writeStructBegin($class);
foreach ($spec as $fid => $fspec) {
$var = $fspec['var'];
if ($this->$var !== null) {
$ftype = $fspec['type'];
$xfer += $output->writeFieldBegin($var, $ftype, $fid);
if (isset(TBase::$tmethod[$ftype])) {
$func = 'write'.TBase::$tmethod[$ftype];
$xfer += $output->$func($this->$var);
} else {
switch ($ftype) {
case TType::STRUCT:
$xfer += $this->$var->write($output);
break;
case TType::MAP:
$xfer += $this->_writeMap($this->$var, $fspec, $output);
break;
case TType::LST:
$xfer += $this->_writeList($this->$var, $fspec, $output, false);
break;
case TType::SET:
$xfer += $this->_writeList($this->$var, $fspec, $output, true);
break;
}
}
$xfer += $output->writeFieldEnd();
}
}
$xfer += $output->writeFieldStop();
$xfer += $output->writeStructEnd();
return $xfer;
}
}

View file

@ -1,18 +0,0 @@
<?php
namespace Thrift\Factory;
use Thrift\Transport\TTransport;
class TTransportFactory
{
/**
* @static
* @param TTransport $transport
* @return TTransport
*/
public static function getTransport(TTransport $transport)
{
return $transport;
}
}

View file

@ -1,453 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.protocol
*/
namespace Thrift\Protocol;
use Thrift\Type\TType;
use Thrift\Exception\TProtocolException;
use Thrift\Factory\TStringFuncFactory;
/**
* Binary implementation of the Thrift protocol.
*
*/
class TBinaryProtocol extends TProtocol
{
const VERSION_MASK = 0xffff0000;
const VERSION_1 = 0x80010000;
protected $strictRead_ = false;
protected $strictWrite_ = true;
public function __construct($trans, $strictRead=false, $strictWrite=true)
{
parent::__construct($trans);
$this->strictRead_ = $strictRead;
$this->strictWrite_ = $strictWrite;
}
public function writeMessageBegin($name, $type, $seqid)
{
if ($this->strictWrite_) {
$version = self::VERSION_1 | $type;
return
$this->writeI32($version) +
$this->writeString($name) +
$this->writeI32($seqid);
} else {
return
$this->writeString($name) +
$this->writeByte($type) +
$this->writeI32($seqid);
}
}
public function writeMessageEnd()
{
return 0;
}
public function writeStructBegin($name)
{
return 0;
}
public function writeStructEnd()
{
return 0;
}
public function writeFieldBegin($fieldName, $fieldType, $fieldId)
{
return
$this->writeByte($fieldType) +
$this->writeI16($fieldId);
}
public function writeFieldEnd()
{
return 0;
}
public function writeFieldStop()
{
return
$this->writeByte(TType::STOP);
}
public function writeMapBegin($keyType, $valType, $size)
{
return
$this->writeByte($keyType) +
$this->writeByte($valType) +
$this->writeI32($size);
}
public function writeMapEnd()
{
return 0;
}
public function writeListBegin($elemType, $size)
{
return
$this->writeByte($elemType) +
$this->writeI32($size);
}
public function writeListEnd()
{
return 0;
}
public function writeSetBegin($elemType, $size)
{
return
$this->writeByte($elemType) +
$this->writeI32($size);
}
public function writeSetEnd()
{
return 0;
}
public function writeBool($value)
{
$data = pack('c', $value ? 1 : 0);
$this->trans_->write($data, 1);
return 1;
}
public function writeByte($value)
{
$data = pack('c', $value);
$this->trans_->write($data, 1);
return 1;
}
public function writeI16($value)
{
$data = pack('n', $value);
$this->trans_->write($data, 2);
return 2;
}
public function writeI32($value)
{
$data = pack('N', $value);
$this->trans_->write($data, 4);
return 4;
}
public function writeI64($value)
{
// If we are on a 32bit architecture we have to explicitly deal with
// 64-bit twos-complement arithmetic since PHP wants to treat all ints
// as signed and any int over 2^31 - 1 as a float
if (PHP_INT_SIZE == 4) {
$neg = $value < 0;
if ($neg) {
$value *= -1;
}
$hi = (int) ($value / 4294967296);
$lo = (int) $value;
if ($neg) {
$hi = ~$hi;
$lo = ~$lo;
if (($lo & (int) 0xffffffff) == (int) 0xffffffff) {
$lo = 0;
$hi++;
} else {
$lo++;
}
}
$data = pack('N2', $hi, $lo);
} else {
$hi = $value >> 32;
$lo = $value & 0xFFFFFFFF;
$data = pack('N2', $hi, $lo);
}
$this->trans_->write($data, 8);
return 8;
}
public function writeDouble($value)
{
$data = pack('d', $value);
$this->trans_->write(strrev($data), 8);
return 8;
}
public function writeString($value)
{
$len = TStringFuncFactory::create()->strlen($value);
$result = $this->writeI32($len);
if ($len) {
$this->trans_->write($value, $len);
}
return $result + $len;
}
public function readMessageBegin(&$name, &$type, &$seqid)
{
$result = $this->readI32($sz);
if ($sz < 0) {
$version = (int) ($sz & self::VERSION_MASK);
if ($version != (int) self::VERSION_1) {
throw new TProtocolException('Bad version identifier: '.$sz, TProtocolException::BAD_VERSION);
}
$type = $sz & 0x000000ff;
$result +=
$this->readString($name) +
$this->readI32($seqid);
} else {
if ($this->strictRead_) {
throw new TProtocolException('No version identifier, old protocol client?', TProtocolException::BAD_VERSION);
} else {
// Handle pre-versioned input
$name = $this->trans_->readAll($sz);
$result +=
$sz +
$this->readByte($type) +
$this->readI32($seqid);
}
}
return $result;
}
public function readMessageEnd()
{
return 0;
}
public function readStructBegin(&$name)
{
$name = '';
return 0;
}
public function readStructEnd()
{
return 0;
}
public function readFieldBegin(&$name, &$fieldType, &$fieldId)
{
$result = $this->readByte($fieldType);
if ($fieldType == TType::STOP) {
$fieldId = 0;
return $result;
}
$result += $this->readI16($fieldId);
return $result;
}
public function readFieldEnd()
{
return 0;
}
public function readMapBegin(&$keyType, &$valType, &$size)
{
return
$this->readByte($keyType) +
$this->readByte($valType) +
$this->readI32($size);
}
public function readMapEnd()
{
return 0;
}
public function readListBegin(&$elemType, &$size)
{
return
$this->readByte($elemType) +
$this->readI32($size);
}
public function readListEnd()
{
return 0;
}
public function readSetBegin(&$elemType, &$size)
{
return
$this->readByte($elemType) +
$this->readI32($size);
}
public function readSetEnd()
{
return 0;
}
public function readBool(&$value)
{
$data = $this->trans_->readAll(1);
$arr = unpack('c', $data);
$value = $arr[1] == 1;
return 1;
}
public function readByte(&$value)
{
$data = $this->trans_->readAll(1);
$arr = unpack('c', $data);
$value = $arr[1];
return 1;
}
public function readI16(&$value)
{
$data = $this->trans_->readAll(2);
$arr = unpack('n', $data);
$value = $arr[1];
if ($value > 0x7fff) {
$value = 0 - (($value - 1) ^ 0xffff);
}
return 2;
}
public function readI32(&$value)
{
$data = $this->trans_->readAll(4);
$arr = unpack('N', $data);
$value = $arr[1];
if ($value > 0x7fffffff) {
$value = 0 - (($value - 1) ^ 0xffffffff);
}
return 4;
}
public function readI64(&$value)
{
$data = $this->trans_->readAll(8);
$arr = unpack('N2', $data);
// If we are on a 32bit architecture we have to explicitly deal with
// 64-bit twos-complement arithmetic since PHP wants to treat all ints
// as signed and any int over 2^31 - 1 as a float
if (PHP_INT_SIZE == 4) {
$hi = $arr[1];
$lo = $arr[2];
$isNeg = $hi < 0;
// Check for a negative
if ($isNeg) {
$hi = ~$hi & (int) 0xffffffff;
$lo = ~$lo & (int) 0xffffffff;
if ($lo == (int) 0xffffffff) {
$hi++;
$lo = 0;
} else {
$lo++;
}
}
// Force 32bit words in excess of 2G to pe positive - we deal wigh sign
// explicitly below
if ($hi & (int) 0x80000000) {
$hi &= (int) 0x7fffffff;
$hi += 0x80000000;
}
if ($lo & (int) 0x80000000) {
$lo &= (int) 0x7fffffff;
$lo += 0x80000000;
}
$value = $hi * 4294967296 + $lo;
if ($isNeg) {
$value = 0 - $value;
}
} else {
// Upcast negatives in LSB bit
if ($arr[2] & 0x80000000) {
$arr[2] = $arr[2] & 0xffffffff;
}
// Check for a negative
if ($arr[1] & 0x80000000) {
$arr[1] = $arr[1] & 0xffffffff;
$arr[1] = $arr[1] ^ 0xffffffff;
$arr[2] = $arr[2] ^ 0xffffffff;
$value = 0 - $arr[1]*4294967296 - $arr[2] - 1;
} else {
$value = $arr[1]*4294967296 + $arr[2];
}
}
return 8;
}
public function readDouble(&$value)
{
$data = strrev($this->trans_->readAll(8));
$arr = unpack('d', $data);
$value = $arr[1];
return 8;
}
public function readString(&$value)
{
$result = $this->readI32($len);
if ($len) {
$value = $this->trans_->readAll($len);
} else {
$value = '';
}
return $result + $len;
}
}

View file

@ -1,65 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.protocol
*/
namespace Thrift\Protocol;
use Thrift\Transport\TBufferedTransport;
/**
* Accelerated binary protocol: used in conjunction with the thrift_protocol
* extension for faster deserialization
*/
class TBinaryProtocolAccelerated extends TBinaryProtocol
{
public function __construct($trans, $strictRead=false, $strictWrite=true)
{
// If the transport doesn't implement putBack, wrap it in a
// TBufferedTransport (which does)
// NOTE (t.heintz): This is very evil to do, because the TBufferedTransport may swallow bytes, which
// are then never written to the underlying transport. This happens precisely when a number of bytes
// less than the max buffer size (512 by default) is written to the transport and then flush() is NOT
// called. In that case the data stays in the writeBuffer of the transport, from where it can never be
// accessed again (for example through read()).
//
// Since the caller of this method does not know about the wrapping transport, this creates bugs which
// are very difficult to find. Hence the wrapping of a transport in a buffer should be left to the
// calling code. An interface could used to mandate the presence of the putBack() method in the transport.
//
// I am leaving this code in nonetheless, because there may be applications depending on this behavior.
//
// @see THRIFT-1579
if (!method_exists($trans, 'putBack')) {
$trans = new TBufferedTransport($trans);
}
parent::__construct($trans, $strictRead, $strictWrite);
}
public function isStrictRead()
{
return $this->strictRead_;
}
public function isStrictWrite()
{
return $this->strictWrite_;
}
}

View file

@ -1,739 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.protocol
*/
namespace Thrift\Protocol;
use Thrift\Type\TType;
use Thrift\Exception\TProtocolException;
use Thrift\Factory\TStringFuncFactory;
/**
* Compact implementation of the Thrift protocol.
*
*/
class TCompactProtocol extends TProtocol
{
const COMPACT_STOP = 0x00;
const COMPACT_TRUE = 0x01;
const COMPACT_FALSE = 0x02;
const COMPACT_BYTE = 0x03;
const COMPACT_I16 = 0x04;
const COMPACT_I32 = 0x05;
const COMPACT_I64 = 0x06;
const COMPACT_DOUBLE = 0x07;
const COMPACT_BINARY = 0x08;
const COMPACT_LIST = 0x09;
const COMPACT_SET = 0x0A;
const COMPACT_MAP = 0x0B;
const COMPACT_STRUCT = 0x0C;
const STATE_CLEAR = 0;
const STATE_FIELD_WRITE = 1;
const STATE_VALUE_WRITE = 2;
const STATE_CONTAINER_WRITE = 3;
const STATE_BOOL_WRITE = 4;
const STATE_FIELD_READ = 5;
const STATE_CONTAINER_READ = 6;
const STATE_VALUE_READ = 7;
const STATE_BOOL_READ = 8;
const VERSION_MASK = 0x1f;
const VERSION = 1;
const PROTOCOL_ID = 0x82;
const TYPE_MASK = 0xe0;
const TYPE_BITS = 0x07;
const TYPE_SHIFT_AMOUNT = 5;
protected static $ctypes = array(
TType::STOP => TCompactProtocol::COMPACT_STOP,
TType::BOOL => TCompactProtocol::COMPACT_TRUE, // used for collection
TType::BYTE => TCompactProtocol::COMPACT_BYTE,
TType::I16 => TCompactProtocol::COMPACT_I16,
TType::I32 => TCompactProtocol::COMPACT_I32,
TType::I64 => TCompactProtocol::COMPACT_I64,
TType::DOUBLE => TCompactProtocol::COMPACT_DOUBLE,
TType::STRING => TCompactProtocol::COMPACT_BINARY,
TType::STRUCT => TCompactProtocol::COMPACT_STRUCT,
TType::LST => TCompactProtocol::COMPACT_LIST,
TType::SET => TCompactProtocol::COMPACT_SET,
TType::MAP => TCompactProtocol::COMPACT_MAP,
);
protected static $ttypes = array(
TCompactProtocol::COMPACT_STOP => TType::STOP ,
TCompactProtocol::COMPACT_TRUE => TType::BOOL, // used for collection
TCompactProtocol::COMPACT_FALSE => TType::BOOL,
TCompactProtocol::COMPACT_BYTE => TType::BYTE,
TCompactProtocol::COMPACT_I16 => TType::I16,
TCompactProtocol::COMPACT_I32 => TType::I32,
TCompactProtocol::COMPACT_I64 => TType::I64,
TCompactProtocol::COMPACT_DOUBLE => TType::DOUBLE,
TCompactProtocol::COMPACT_BINARY => TType::STRING,
TCompactProtocol::COMPACT_STRUCT => TType::STRUCT,
TCompactProtocol::COMPACT_LIST => TType::LST,
TCompactProtocol::COMPACT_SET => TType::SET,
TCompactProtocol::COMPACT_MAP => TType::MAP,
);
protected $state = TCompactProtocol::STATE_CLEAR;
protected $lastFid = 0;
protected $boolFid = null;
protected $boolValue = null;
protected $structs = array();
protected $containers = array();
// Some varint / zigzag helper methods
public function toZigZag($n, $bits)
{
return ($n << 1) ^ ($n >> ($bits - 1));
}
public function fromZigZag($n)
{
return ($n >> 1) ^ -($n & 1);
}
public function getVarint($data)
{
$out = "";
while (true) {
if (($data & ~0x7f) === 0) {
$out .= chr($data);
break;
} else {
$out .= chr(($data & 0xff) | 0x80);
$data = $data >> 7;
}
}
return $out;
}
public function writeVarint($data)
{
$out = $this->getVarint($data);
$result = TStringFuncFactory::create()->strlen($out);
$this->trans_->write($out, $result);
return $result;
}
public function readVarint(&$result)
{
$idx = 0;
$shift = 0;
$result = 0;
while (true) {
$x = $this->trans_->readAll(1);
$arr = unpack('C', $x);
$byte = $arr[1];
$idx += 1;
$result |= ($byte & 0x7f) << $shift;
if (($byte >> 7) === 0) {
return $idx;
}
$shift += 7;
}
return $idx;
}
public function __construct($trans)
{
parent::__construct($trans);
}
public function writeMessageBegin($name, $type, $seqid)
{
$written =
$this->writeUByte(TCompactProtocol::PROTOCOL_ID) +
$this->writeUByte(TCompactProtocol::VERSION |
($type << TCompactProtocol::TYPE_SHIFT_AMOUNT)) +
$this->writeVarint($seqid) +
$this->writeString($name);
$this->state = TCompactProtocol::STATE_VALUE_WRITE;
return $written;
}
public function writeMessageEnd()
{
$this->state = TCompactProtocol::STATE_CLEAR;
return 0;
}
public function writeStructBegin($name)
{
$this->structs[] = array($this->state, $this->lastFid);
$this->state = TCompactProtocol::STATE_FIELD_WRITE;
$this->lastFid = 0;
return 0;
}
public function writeStructEnd()
{
$old_values = array_pop($this->structs);
$this->state = $old_values[0];
$this->lastFid = $old_values[1];
return 0;
}
public function writeFieldStop()
{
return $this->writeByte(0);
}
public function writeFieldHeader($type, $fid)
{
$written = 0;
$delta = $fid - $this->lastFid;
if (0 < $delta && $delta <= 15) {
$written = $this->writeUByte(($delta << 4) | $type);
} else {
$written = $this->writeByte($type) +
$this->writeI16($fid);
}
$this->lastFid = $fid;
return $written;
}
public function writeFieldBegin($field_name, $field_type, $field_id)
{
if ($field_type == TTYPE::BOOL) {
$this->state = TCompactProtocol::STATE_BOOL_WRITE;
$this->boolFid = $field_id;
return 0;
} else {
$this->state = TCompactProtocol::STATE_VALUE_WRITE;
return $this->writeFieldHeader(self::$ctypes[$field_type], $field_id);
}
}
public function writeFieldEnd()
{
$this->state = TCompactProtocol::STATE_FIELD_WRITE;
return 0;
}
public function writeCollectionBegin($etype, $size)
{
$written = 0;
if ($size <= 14) {
$written = $this->writeUByte($size << 4 |
self::$ctypes[$etype]);
} else {
$written = $this->writeUByte(0xf0 |
self::$ctypes[$etype]) +
$this->writeVarint($size);
}
$this->containers[] = $this->state;
$this->state = TCompactProtocol::STATE_CONTAINER_WRITE;
return $written;
}
public function writeMapBegin($key_type, $val_type, $size)
{
$written = 0;
if ($size == 0) {
$written = $this->writeByte(0);
} else {
$written = $this->writeVarint($size) +
$this->writeUByte(self::$ctypes[$key_type] << 4 |
self::$ctypes[$val_type]);
}
$this->containers[] = $this->state;
return $written;
}
public function writeCollectionEnd()
{
$this->state = array_pop($this->containers);
return 0;
}
public function writeMapEnd()
{
return $this->writeCollectionEnd();
}
public function writeListBegin($elem_type, $size)
{
return $this->writeCollectionBegin($elem_type, $size);
}
public function writeListEnd()
{
return $this->writeCollectionEnd();
}
public function writeSetBegin($elem_type, $size)
{
return $this->writeCollectionBegin($elem_type, $size);
}
public function writeSetEnd()
{
return $this->writeCollectionEnd();
}
public function writeBool($value)
{
if ($this->state == TCompactProtocol::STATE_BOOL_WRITE) {
$ctype = TCompactProtocol::COMPACT_FALSE;
if ($value) {
$ctype = TCompactProtocol::COMPACT_TRUE;
}
return $this->writeFieldHeader($ctype, $this->boolFid);
} elseif ($this->state == TCompactProtocol::STATE_CONTAINER_WRITE) {
return $this->writeByte($value ? 1 : 0);
} else {
throw new TProtocolException('Invalid state in compact protocol');
}
}
public function writeByte($value)
{
$data = pack('c', $value);
$this->trans_->write($data, 1);
return 1;
}
public function writeUByte($byte)
{
$this->trans_->write(pack('C', $byte), 1);
return 1;
}
public function writeI16($value)
{
$thing = $this->toZigZag($value, 16);
return $this->writeVarint($thing);
}
public function writeI32($value)
{
$thing = $this->toZigZag($value, 32);
return $this->writeVarint($thing);
}
public function writeDouble($value)
{
$data = pack('d', $value);
$this->trans_->write($data, 8);
return 8;
}
public function writeString($value)
{
$len = TStringFuncFactory::create()->strlen($value);
$result = $this->writeVarint($len);
if ($len) {
$this->trans_->write($value, $len);
}
return $result + $len;
}
public function readFieldBegin(&$name, &$field_type, &$field_id)
{
$result = $this->readUByte($compact_type_and_delta);
$compact_type = $compact_type_and_delta & 0x0f;
if ($compact_type == TType::STOP) {
$field_type = $compact_type;
$field_id = 0;
return $result;
}
$delta = $compact_type_and_delta >> 4;
if ($delta == 0) {
$result += $this->readI16($field_id);
} else {
$field_id = $this->lastFid + $delta;
}
$this->lastFid = $field_id;
$field_type = $this->getTType($compact_type);
if ($compact_type == TCompactProtocol::COMPACT_TRUE) {
$this->state = TCompactProtocol::STATE_BOOL_READ;
$this->boolValue = true;
} elseif ($compact_type == TCompactProtocol::COMPACT_FALSE) {
$this->state = TCompactProtocol::STATE_BOOL_READ;
$this->boolValue = false;
} else {
$this->state = TCompactProtocol::STATE_VALUE_READ;
}
return $result;
}
public function readFieldEnd()
{
$this->state = TCompactProtocol::STATE_FIELD_READ;
return 0;
}
public function readUByte(&$value)
{
$data = $this->trans_->readAll(1);
$arr = unpack('C', $data);
$value = $arr[1];
return 1;
}
public function readByte(&$value)
{
$data = $this->trans_->readAll(1);
$arr = unpack('c', $data);
$value = $arr[1];
return 1;
}
public function readZigZag(&$value)
{
$result = $this->readVarint($value);
$value = $this->fromZigZag($value);
return $result;
}
public function readMessageBegin(&$name, &$type, &$seqid)
{
$protoId = 0;
$result = $this->readUByte($protoId);
if ($protoId != TCompactProtocol::PROTOCOL_ID) {
throw new TProtocolException('Bad protocol id in TCompact message');
}
$verType = 0;
$result += $this->readUByte($verType);
$type = ($verType >> TCompactProtocol::TYPE_SHIFT_AMOUNT) & TCompactProtocol::TYPE_BITS;
$version = $verType & TCompactProtocol::VERSION_MASK;
if ($version != TCompactProtocol::VERSION) {
throw new TProtocolException('Bad version in TCompact message');
}
$result += $this->readVarint($seqid);
$result += $this->readString($name);
return $result;
}
public function readMessageEnd()
{
return 0;
}
public function readStructBegin(&$name)
{
$name = ''; // unused
$this->structs[] = array($this->state, $this->lastFid);
$this->state = TCompactProtocol::STATE_FIELD_READ;
$this->lastFid = 0;
return 0;
}
public function readStructEnd()
{
$last = array_pop($this->structs);
$this->state = $last[0];
$this->lastFid = $last[1];
return 0;
}
public function readCollectionBegin(&$type, &$size)
{
$sizeType = 0;
$result = $this->readUByte($sizeType);
$size = $sizeType >> 4;
$type = $this->getTType($sizeType);
if ($size == 15) {
$result += $this->readVarint($size);
}
$this->containers[] = $this->state;
$this->state = TCompactProtocol::STATE_CONTAINER_READ;
return $result;
}
public function readMapBegin(&$key_type, &$val_type, &$size)
{
$result = $this->readVarint($size);
$types = 0;
if ($size > 0) {
$result += $this->readUByte($types);
}
$val_type = $this->getTType($types);
$key_type = $this->getTType($types >> 4);
$this->containers[] = $this->state;
$this->state = TCompactProtocol::STATE_CONTAINER_READ;
return $result;
}
public function readCollectionEnd()
{
$this->state = array_pop($this->containers);
return 0;
}
public function readMapEnd()
{
return $this->readCollectionEnd();
}
public function readListBegin(&$elem_type, &$size)
{
return $this->readCollectionBegin($elem_type, $size);
}
public function readListEnd()
{
return $this->readCollectionEnd();
}
public function readSetBegin(&$elem_type, &$size)
{
return $this->readCollectionBegin($elem_type, $size);
}
public function readSetEnd()
{
return $this->readCollectionEnd();
}
public function readBool(&$value)
{
if ($this->state == TCompactProtocol::STATE_BOOL_READ) {
$value = $this->boolValue;
return 0;
} elseif ($this->state == TCompactProtocol::STATE_CONTAINER_READ) {
return $this->readByte($value);
} else {
throw new TProtocolException('Invalid state in compact protocol');
}
}
public function readI16(&$value)
{
return $this->readZigZag($value);
}
public function readI32(&$value)
{
return $this->readZigZag($value);
}
public function readDouble(&$value)
{
$data = $this->trans_->readAll(8);
$arr = unpack('d', $data);
$value = $arr[1];
return 8;
}
public function readString(&$value)
{
$result = $this->readVarint($len);
if ($len) {
$value = $this->trans_->readAll($len);
} else {
$value = '';
}
return $result + $len;
}
public function getTType($byte)
{
return self::$ttypes[$byte & 0x0f];
}
// If we are on a 32bit architecture we have to explicitly deal with
// 64-bit twos-complement arithmetic since PHP wants to treat all ints
// as signed and any int over 2^31 - 1 as a float
// Read and write I64 as two 32 bit numbers $hi and $lo
public function readI64(&$value)
{
// Read varint from wire
$hi = 0;
$lo = 0;
$idx = 0;
$shift = 0;
while (true) {
$x = $this->trans_->readAll(1);
$arr = unpack('C', $x);
$byte = $arr[1];
$idx += 1;
// Shift hi and lo together.
if ($shift < 28) {
$lo |= (($byte & 0x7f) << $shift);
} elseif ($shift == 28) {
$lo |= (($byte & 0x0f) << 28);
$hi |= (($byte & 0x70) >> 4);
} else {
$hi |= (($byte & 0x7f) << ($shift - 32));
}
if (($byte >> 7) === 0) {
break;
}
$shift += 7;
}
// Now, unzig it.
$xorer = 0;
if ($lo & 1) {
$xorer = 0xffffffff;
}
$lo = ($lo >> 1) & 0x7fffffff;
$lo = $lo | (($hi & 1) << 31);
$hi = ($hi >> 1) ^ $xorer;
$lo = $lo ^ $xorer;
// Now put $hi and $lo back together
$isNeg = $hi < 0 || $hi & 0x80000000;
// Check for a negative
if ($isNeg) {
$hi = ~$hi & (int) 0xffffffff;
$lo = ~$lo & (int) 0xffffffff;
if ($lo == (int) 0xffffffff) {
$hi++;
$lo = 0;
} else {
$lo++;
}
}
// Force 32bit words in excess of 2G to be positive - we deal with sign
// explicitly below
if ($hi & (int) 0x80000000) {
$hi &= (int) 0x7fffffff;
$hi += 0x80000000;
}
if ($lo & (int) 0x80000000) {
$lo &= (int) 0x7fffffff;
$lo += 0x80000000;
}
// Create as negative value first, since we can store -2^63 but not 2^63
$value = -$hi * 4294967296 - $lo;
if (!$isNeg) {
$value = -$value;
}
return $idx;
}
public function writeI64($value)
{
// If we are in an I32 range, use the easy method below.
if (($value > 4294967296) || ($value < -4294967296)) {
// Convert $value to $hi and $lo
$neg = $value < 0;
if ($neg) {
$value *= -1;
}
$hi = (int) $value >> 32;
$lo = (int) $value & 0xffffffff;
if ($neg) {
$hi = ~$hi;
$lo = ~$lo;
if (($lo & (int) 0xffffffff) == (int) 0xffffffff) {
$lo = 0;
$hi++;
} else {
$lo++;
}
}
// Now do the zigging and zagging.
$xorer = 0;
if ($neg) {
$xorer = 0xffffffff;
}
$lowbit = ($lo >> 31) & 1;
$hi = ($hi << 1) | $lowbit;
$lo = ($lo << 1);
$lo = ($lo ^ $xorer) & 0xffffffff;
$hi = ($hi ^ $xorer) & 0xffffffff;
// now write out the varint, ensuring we shift both hi and lo
$out = "";
while (true) {
if (($lo & ~0x7f) === 0 &&
$hi === 0) {
$out .= chr($lo);
break;
} else {
$out .= chr(($lo & 0xff) | 0x80);
$lo = $lo >> 7;
$lo = $lo | ($hi << 25);
$hi = $hi >> 7;
// Right shift carries sign, but we don't want it to.
$hi = $hi & (127 << 25);
}
}
$ret = TStringFuncFactory::create()->strlen($out);
$this->trans_->write($out, $ret);
return $ret;
} else {
return $this->writeVarint($this->toZigZag($value, 64));
}
}
}

View file

@ -1,352 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.protocol
*/
namespace Thrift\Protocol;
use Thrift\Type\TType;
use Thrift\Exception\TProtocolException;
/**
* Protocol base class module.
*/
abstract class TProtocol
{
/**
* Underlying transport
*
* @var TTransport
*/
protected $trans_;
/**
* Constructor
*/
protected function __construct($trans)
{
$this->trans_ = $trans;
}
/**
* Accessor for transport
*
* @return TTransport
*/
public function getTransport()
{
return $this->trans_;
}
/**
* Writes the message header
*
* @param string $name Function name
* @param int $type message type TMessageType::CALL or TMessageType::REPLY
* @param int $seqid The sequence id of this message
*/
abstract public function writeMessageBegin($name, $type, $seqid);
/**
* Close the message
*/
abstract public function writeMessageEnd();
/**
* Writes a struct header.
*
* @param string $name Struct name
* @throws TException on write error
* @return int How many bytes written
*/
abstract public function writeStructBegin($name);
/**
* Close a struct.
*
* @throws TException on write error
* @return int How many bytes written
*/
abstract public function writeStructEnd();
/*
* Starts a field.
*
* @param string $name Field name
* @param int $type Field type
* @param int $fid Field id
* @throws TException on write error
* @return int How many bytes written
*/
abstract public function writeFieldBegin($fieldName, $fieldType, $fieldId);
abstract public function writeFieldEnd();
abstract public function writeFieldStop();
abstract public function writeMapBegin($keyType, $valType, $size);
abstract public function writeMapEnd();
abstract public function writeListBegin($elemType, $size);
abstract public function writeListEnd();
abstract public function writeSetBegin($elemType, $size);
abstract public function writeSetEnd();
abstract public function writeBool($bool);
abstract public function writeByte($byte);
abstract public function writeI16($i16);
abstract public function writeI32($i32);
abstract public function writeI64($i64);
abstract public function writeDouble($dub);
abstract public function writeString($str);
/**
* Reads the message header
*
* @param string $name Function name
* @param int $type message type TMessageType::CALL or TMessageType::REPLY
* @parem int $seqid The sequence id of this message
*/
abstract public function readMessageBegin(&$name, &$type, &$seqid);
/**
* Read the close of message
*/
abstract public function readMessageEnd();
abstract public function readStructBegin(&$name);
abstract public function readStructEnd();
abstract public function readFieldBegin(&$name, &$fieldType, &$fieldId);
abstract public function readFieldEnd();
abstract public function readMapBegin(&$keyType, &$valType, &$size);
abstract public function readMapEnd();
abstract public function readListBegin(&$elemType, &$size);
abstract public function readListEnd();
abstract public function readSetBegin(&$elemType, &$size);
abstract public function readSetEnd();
abstract public function readBool(&$bool);
abstract public function readByte(&$byte);
abstract public function readI16(&$i16);
abstract public function readI32(&$i32);
abstract public function readI64(&$i64);
abstract public function readDouble(&$dub);
abstract public function readString(&$str);
/**
* The skip function is a utility to parse over unrecognized date without
* causing corruption.
*
* @param TType $type What type is it
*/
public function skip($type)
{
switch ($type) {
case TType::BOOL:
return $this->readBool($bool);
case TType::BYTE:
return $this->readByte($byte);
case TType::I16:
return $this->readI16($i16);
case TType::I32:
return $this->readI32($i32);
case TType::I64:
return $this->readI64($i64);
case TType::DOUBLE:
return $this->readDouble($dub);
case TType::STRING:
return $this->readString($str);
case TType::STRUCT:
{
$result = $this->readStructBegin($name);
while (true) {
$result += $this->readFieldBegin($name, $ftype, $fid);
if ($ftype == TType::STOP) {
break;
}
$result += $this->skip($ftype);
$result += $this->readFieldEnd();
}
$result += $this->readStructEnd();
return $result;
}
case TType::MAP:
{
$result = $this->readMapBegin($keyType, $valType, $size);
for ($i = 0; $i < $size; $i++) {
$result += $this->skip($keyType);
$result += $this->skip($valType);
}
$result += $this->readMapEnd();
return $result;
}
case TType::SET:
{
$result = $this->readSetBegin($elemType, $size);
for ($i = 0; $i < $size; $i++) {
$result += $this->skip($elemType);
}
$result += $this->readSetEnd();
return $result;
}
case TType::LST:
{
$result = $this->readListBegin($elemType, $size);
for ($i = 0; $i < $size; $i++) {
$result += $this->skip($elemType);
}
$result += $this->readListEnd();
return $result;
}
default:
throw new TProtocolException('Unknown field type: '.$type,
TProtocolException::INVALID_DATA);
}
}
/**
* Utility for skipping binary data
*
* @param TTransport $itrans TTransport object
* @param int $type Field type
*/
public static function skipBinary($itrans, $type)
{
switch ($type) {
case TType::BOOL:
return $itrans->readAll(1);
case TType::BYTE:
return $itrans->readAll(1);
case TType::I16:
return $itrans->readAll(2);
case TType::I32:
return $itrans->readAll(4);
case TType::I64:
return $itrans->readAll(8);
case TType::DOUBLE:
return $itrans->readAll(8);
case TType::STRING:
$len = unpack('N', $itrans->readAll(4));
$len = $len[1];
if ($len > 0x7fffffff) {
$len = 0 - (($len - 1) ^ 0xffffffff);
}
return 4 + $itrans->readAll($len);
case TType::STRUCT:
{
$result = 0;
while (true) {
$ftype = 0;
$fid = 0;
$data = $itrans->readAll(1);
$arr = unpack('c', $data);
$ftype = $arr[1];
if ($ftype == TType::STOP) {
break;
}
// I16 field id
$result += $itrans->readAll(2);
$result += self::skipBinary($itrans, $ftype);
}
return $result;
}
case TType::MAP:
{
// Ktype
$data = $itrans->readAll(1);
$arr = unpack('c', $data);
$ktype = $arr[1];
// Vtype
$data = $itrans->readAll(1);
$arr = unpack('c', $data);
$vtype = $arr[1];
// Size
$data = $itrans->readAll(4);
$arr = unpack('N', $data);
$size = $arr[1];
if ($size > 0x7fffffff) {
$size = 0 - (($size - 1) ^ 0xffffffff);
}
$result = 6;
for ($i = 0; $i < $size; $i++) {
$result += self::skipBinary($itrans, $ktype);
$result += self::skipBinary($itrans, $vtype);
}
return $result;
}
case TType::SET:
case TType::LST:
{
// Vtype
$data = $itrans->readAll(1);
$arr = unpack('c', $data);
$vtype = $arr[1];
// Size
$data = $itrans->readAll(4);
$arr = unpack('N', $data);
$size = $arr[1];
if ($size > 0x7fffffff) {
$size = 0 - (($size - 1) ^ 0xffffffff);
}
$result = 5;
for ($i = 0; $i < $size; $i++) {
$result += self::skipBinary($itrans, $vtype);
}
return $result;
}
default:
throw new TProtocolException('Unknown field type: '.$type,
TProtocolException::INVALID_DATA);
}
}
}

View file

@ -1,85 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.protocol
* @author: rmarin (marin.radu@facebook.com)
*/
namespace Thrift\Serializer;
use Thrift\Transport\TMemoryBuffer;
use Thrift\Protocol\TBinaryProtocolAccelerated;
use Thrift\Type\TMessageType;
/**
* Utility class for serializing and deserializing
* a thrift object using TBinaryProtocolAccelerated.
*/
class TBinarySerializer
{
// NOTE(rmarin): Because thrift_protocol_write_binary
// adds a begin message prefix, you cannot specify
// a transport in which to serialize an object. It has to
// be a string. Otherwise we will break the compatibility with
// normal deserialization.
public static function serialize($object)
{
$transport = new TMemoryBuffer();
$protocol = new TBinaryProtocolAccelerated($transport);
if (function_exists('thrift_protocol_write_binary')) {
thrift_protocol_write_binary($protocol, $object->getName(),
TMessageType::REPLY, $object,
0, $protocol->isStrictWrite());
$protocol->readMessageBegin($unused_name, $unused_type,
$unused_seqid);
} else {
$object->write($protocol);
}
$protocol->getTransport()->flush();
return $transport->getBuffer();
}
public static function deserialize($string_object, $class_name, $buffer_size = 8192)
{
$transport = new TMemoryBuffer();
$protocol = new TBinaryProtocolAccelerated($transport);
if (function_exists('thrift_protocol_read_binary')) {
// NOTE (t.heintz) TBinaryProtocolAccelerated internally wraps our TMemoryBuffer in a
// TBufferedTransport, so we have to retrieve it again or risk losing data when writing
// less than 512 bytes to the transport (see the comment there as well).
// @see THRIFT-1579
$protocol->writeMessageBegin('', TMessageType::REPLY, 0);
$protocolTransport = $protocol->getTransport();
$protocolTransport->write($string_object);
$protocolTransport->flush();
return thrift_protocol_read_binary($protocol, $class_name,
$protocol->isStrictRead(),
$buffer_size);
} else {
$transport->write($string_object);
$object = new $class_name();
$object->read($protocol);
return $object;
}
}
}

View file

@ -1,120 +0,0 @@
<?php
namespace Thrift\Server;
use Thrift\Transport\TTransport;
use Thrift\Exception\TException;
use Thrift\Exception\TTransportException;
/**
* A forking implementation of a Thrift server.
*
* @package thrift.server
*/
class TForkingServer extends TServer
{
/**
* Flag for the main serving loop
*
* @var bool
*/
private $stop_ = false;
/**
* List of children.
*
* @var array
*/
protected $children_ = array();
/**
* Listens for new client using the supplied
* transport. We fork when a new connection
* arrives.
*
* @return void
*/
public function serve()
{
$this->transport_->listen();
while (!$this->stop_) {
try {
$transport = $this->transport_->accept();
if ($transport != null) {
$pid = pcntl_fork();
if ($pid > 0) {
$this->handleParent($transport, $pid);
} elseif ($pid === 0) {
$this->handleChild($transport);
} else {
throw new TException('Failed to fork');
}
}
} catch (TTransportException $e) { }
$this->collectChildren();
}
}
/**
* Code run by the parent
*
* @param TTransport $transport
* @param int $pid
* @return void
*/
private function handleParent(TTransport $transport, $pid)
{
$this->children_[$pid] = $transport;
}
/**
* Code run by the child.
*
* @param TTransport $transport
* @return void
*/
private function handleChild(TTransport $transport)
{
try {
$inputTransport = $this->inputTransportFactory_->getTransport($transport);
$outputTransport = $this->outputTransportFactory_->getTransport($transport);
$inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport);
$outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport);
while ($this->processor_->process($inputProtocol, $outputProtocol)) { }
@$transport->close();
} catch (TTransportException $e) { }
exit(0);
}
/**
* Collects any children we may have
*
* @return void
*/
private function collectChildren()
{
foreach ($this->children_ as $pid => $transport) {
if (pcntl_waitpid($pid, $status, WNOHANG) > 0) {
unset($this->children_[$pid]);
if ($transport) @$transport->close();
}
}
}
/**
* Stops the server running. Kills the transport
* and then stops the main serving loop
*
* @return void
*/
public function stop()
{
$this->transport_->close();
$this->stop_ = true;
}
}

View file

@ -1,94 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
namespace Thrift\Server;
use Thrift\Transport\TSSLSocket;
/**
* Socket implementation of a server agent.
*
* @package thrift.transport
*/
class TSSLServerSocket extends TServerSocket
{
/**
* Remote port
*
* @var resource
*/
protected $context_ = null;
/**
* ServerSocket constructor
*
* @param string $host Host to listen on
* @param int $port Port to listen on
* @param resource $context Stream context
* @return void
*/
public function __construct($host = 'localhost', $port = 9090, $context = null)
{
$ssl_host = $this->getSSLHost($host);
parent::__construct($ssl_host, $port);
$this->context_ = $context;
}
public function getSSLHost($host)
{
$transport_protocol_loc = strpos($host, "://");
if ($transport_protocol_loc === false) {
$host = 'ssl://'.$host;
}
return $host;
}
/**
* Opens a new socket server handle
*
* @return void
*/
public function listen()
{
$this->listener_ = @stream_socket_server(
$this->host_ . ':' . $this->port_,
$errno,
$errstr,
STREAM_SERVER_BIND|STREAM_SERVER_LISTEN,
$this->context_);
}
/**
* Implementation of accept. If not client is accepted in the given time
*
* @return TSocket
*/
protected function acceptImpl()
{
$handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0);
if(!$handle) return null;
$socket = new TSSLSocket();
$socket->setHandle($handle);
return $socket;
}
}

View file

@ -1,100 +0,0 @@
<?php
namespace Thrift\Server;
use Thrift\Factory\TTransportFactory;
use Thrift\Factory\TProtocolFactory;
/**
* Generic class for a Thrift server.
*
* @package thrift.server
*/
abstract class TServer
{
/**
* Processor to handle new clients
*
* @var TProcessor
*/
protected $processor_;
/**
* Server transport to be used for listening
* and accepting new clients
*
* @var TServerTransport
*/
protected $transport_;
/**
* Input transport factory
*
* @var TTransportFactory
*/
protected $inputTransportFactory_;
/**
* Output transport factory
*
* @var TTransportFactory
*/
protected $outputTransportFactory_;
/**
* Input protocol factory
*
* @var TProtocolFactory
*/
protected $inputProtocolFactory_;
/**
* Output protocol factory
*
* @var TProtocolFactory
*/
protected $outputProtocolFactory_;
/**
* Sets up all the factories, etc
*
* @param object $processor
* @param TServerTransport $transport
* @param TTransportFactory $inputTransportFactory
* @param TTransportFactory $outputTransportFactory
* @param TProtocolFactory $inputProtocolFactory
* @param TProtocolFactory $outputProtocolFactory
* @return void
*/
public function __construct($processor,
TServerTransport $transport,
TTransportFactory $inputTransportFactory,
TTransportFactory $outputTransportFactory,
TProtocolFactory $inputProtocolFactory,
TProtocolFactory $outputProtocolFactory) {
$this->processor_ = $processor;
$this->transport_ = $transport;
$this->inputTransportFactory_ = $inputTransportFactory;
$this->outputTransportFactory_ = $outputTransportFactory;
$this->inputProtocolFactory_ = $inputProtocolFactory;
$this->outputProtocolFactory_ = $outputProtocolFactory;
}
/**
* Serves the server. This should never return
* unless a problem permits it to do so or it
* is interrupted intentionally
*
* @abstract
* @return void
*/
abstract public function serve();
/**
* Stops the server serving
*
* @abstract
* @return void
*/
abstract public function stop();
}

View file

@ -1,122 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Server;
use Thrift\Transport\TSocket;
/**
* Socket implementation of a server agent.
*
* @package thrift.transport
*/
class TServerSocket extends TServerTransport
{
/**
* Handle for the listener socket
*
* @var resource
*/
protected $listener_;
/**
* Port for the listener to listen on
*
* @var int
*/
protected $port_;
/**
* Timeout when listening for a new client
*
* @var int
*/
protected $acceptTimeout_ = 30000;
/**
* Host to listen on
*
* @var string
*/
protected $host_;
/**
* ServerSocket constructor
*
* @param string $host Host to listen on
* @param int $port Port to listen on
* @return void
*/
public function __construct($host = 'localhost', $port = 9090)
{
$this->host_ = $host;
$this->port_ = $port;
}
/**
* Sets the accept timeout
*
* @param int $acceptTimeout
* @return void
*/
public function setAcceptTimeout($acceptTimeout)
{
$this->acceptTimeout_ = $acceptTimeout;
}
/**
* Opens a new socket server handle
*
* @return void
*/
public function listen()
{
$this->listener_ = stream_socket_server('tcp://' . $this->host_ . ':' . $this->port_);
}
/**
* Closes the socket server handle
*
* @return void
*/
public function close()
{
@fclose($this->listener_);
$this->listener_ = null;
}
/**
* Implementation of accept. If not client is accepted in the given time
*
* @return TSocket
*/
protected function acceptImpl()
{
$handle = @stream_socket_accept($this->listener_, $this->acceptTimeout_ / 1000.0);
if(!$handle) return null;
$socket = new TSocket();
$socket->setHandle($handle);
return $socket;
}
}

View file

@ -1,56 +0,0 @@
<?php
namespace Thrift\Server;
use Thrift\Exception\TTransportException;
/**
* Generic class for Server agent.
*
* @package thrift.transport
*/
abstract class TServerTransport
{
/**
* List for new clients
*
* @abstract
* @return void
*/
abstract public function listen();
/**
* Close the server
*
* @abstract
* @return void
*/
abstract public function close();
/**
* Subclasses should use this to implement
* accept.
*
* @abstract
* @return TTransport
*/
abstract protected function acceptImpl();
/**
* Uses the accept implemtation. If null is returned, an
* exception is thrown.
*
* @throws TTransportException
* @return TTransport
*/
public function accept()
{
$transport = $this->acceptImpl();
if ($transport == null) {
throw new TTransportException("accept() may not return NULL");
}
return $transport;
}
}

View file

@ -1,58 +0,0 @@
<?php
namespace Thrift\Server;
use Thrift\Exception\TTransportException;
/**
* Simple implemtation of a Thrift server.
*
* @package thrift.server
*/
class TSimpleServer extends TServer
{
/**
* Flag for the main serving loop
*
* @var bool
*/
private $stop_ = false;
/**
* Listens for new client using the supplied
* transport. It handles TTransportExceptions
* to avoid timeouts etc killing it
*
* @return void
*/
public function serve()
{
$this->transport_->listen();
while (!$this->stop_) {
try {
$transport = $this->transport_->accept();
if ($transport != null) {
$inputTransport = $this->inputTransportFactory_->getTransport($transport);
$outputTransport = $this->outputTransportFactory_->getTransport($transport);
$inputProtocol = $this->inputProtocolFactory_->getProtocol($inputTransport);
$outputProtocol = $this->outputProtocolFactory_->getProtocol($outputTransport);
while ($this->processor_->process($inputProtocol, $outputProtocol)) { }
}
} catch (TTransportException $e) { }
}
}
/**
* Stops the server running. Kills the transport
* and then stops the main serving loop
*
* @return void
*/
public function stop()
{
$this->transport_->close();
$this->stop_ = true;
}
}

View file

@ -1,181 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Factory\TStringFuncFactory;
/**
* Buffered transport. Stores data to an internal buffer that it doesn't
* actually write out until flush is called. For reading, we do a greedy
* read and then serve data out of the internal buffer.
*
* @package thrift.transport
*/
class TBufferedTransport extends TTransport
{
/**
* Constructor. Creates a buffered transport around an underlying transport
*/
public function __construct($transport=null, $rBufSize=512, $wBufSize=512)
{
$this->transport_ = $transport;
$this->rBufSize_ = $rBufSize;
$this->wBufSize_ = $wBufSize;
}
/**
* The underlying transport
*
* @var TTransport
*/
protected $transport_ = null;
/**
* The receive buffer size
*
* @var int
*/
protected $rBufSize_ = 512;
/**
* The write buffer size
*
* @var int
*/
protected $wBufSize_ = 512;
/**
* The write buffer.
*
* @var string
*/
protected $wBuf_ = '';
/**
* The read buffer.
*
* @var string
*/
protected $rBuf_ = '';
public function isOpen()
{
return $this->transport_->isOpen();
}
public function open()
{
$this->transport_->open();
}
public function close()
{
$this->transport_->close();
}
public function putBack($data)
{
if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
$this->rBuf_ = $data;
} else {
$this->rBuf_ = ($data . $this->rBuf_);
}
}
/**
* The reason that we customize readAll here is that the majority of PHP
* streams are already internally buffered by PHP. The socket stream, for
* example, buffers internally and blocks if you call read with $len greater
* than the amount of data available, unlike recv() in C.
*
* Therefore, use the readAll method of the wrapped transport inside
* the buffered readAll.
*/
public function readAll($len)
{
$have = TStringFuncFactory::create()->strlen($this->rBuf_);
if ($have == 0) {
$data = $this->transport_->readAll($len);
} elseif ($have < $len) {
$data = $this->rBuf_;
$this->rBuf_ = '';
$data .= $this->transport_->readAll($len - $have);
} elseif ($have == $len) {
$data = $this->rBuf_;
$this->rBuf_ = '';
} elseif ($have > $len) {
$data = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len);
$this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len);
}
return $data;
}
public function read($len)
{
if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
$this->rBuf_ = $this->transport_->read($this->rBufSize_);
}
if (TStringFuncFactory::create()->strlen($this->rBuf_) <= $len) {
$ret = $this->rBuf_;
$this->rBuf_ = '';
return $ret;
}
$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 (TStringFuncFactory::create()->strlen($this->wBuf_) >= $this->wBufSize_) {
$out = $this->wBuf_;
// Note that we clear the internal wBuf_ prior to the underlying write
// to ensure we're in a sane state (i.e. internal buffer cleaned)
// if the underlying write throws up an exception
$this->wBuf_ = '';
$this->transport_->write($out);
}
}
public function flush()
{
if (TStringFuncFactory::create()->strlen($this->wBuf_) > 0) {
$out = $this->wBuf_;
// Note that we clear the internal wBuf_ prior to the underlying write
// to ensure we're in a sane state (i.e. internal buffer cleaned)
// if the underlying write throws up an exception
$this->wBuf_ = '';
$this->transport_->write($out);
}
$this->transport_->flush();
}
}

View file

@ -1,231 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TTransportException;
use Thrift\Factory\TStringFuncFactory;
/**
* HTTP client for Thrift
*
* @package thrift.transport
*/
class TCurlClient extends TTransport
{
private static $curlHandle;
/**
* The host to connect to
*
* @var string
*/
protected $host_;
/**
* The port to connect on
*
* @var int
*/
protected $port_;
/**
* The URI to request
*
* @var string
*/
protected $uri_;
/**
* The scheme to use for the request, i.e. http, https
*
* @var string
*/
protected $scheme_;
/**
* Buffer for the HTTP request data
*
* @var string
*/
protected $request_;
/**
* Buffer for the HTTP response data.
*
* @var binary string
*/
protected $response_;
/**
* Read timeout
*
* @var float
*/
protected $timeout_;
/**
* Make a new HTTP client.
*
* @param string $host
* @param int $port
* @param string $uri
*/
public function __construct($host, $port=80, $uri='', $scheme = 'http')
{
if ((TStringFuncFactory::create()->strlen($uri) > 0) && ($uri{0} != '/')) {
$uri = '/'.$uri;
}
$this->scheme_ = $scheme;
$this->host_ = $host;
$this->port_ = $port;
$this->uri_ = $uri;
$this->request_ = '';
$this->response_ = null;
$this->timeout_ = null;
}
/**
* Set read timeout
*
* @param float $timeout
*/
public function setTimeoutSecs($timeout)
{
$this->timeout_ = $timeout;
}
/**
* Whether this transport is open.
*
* @return boolean true if open
*/
public function isOpen()
{
return true;
}
/**
* Open the transport for reading/writing
*
* @throws TTransportException if cannot open
*/
public function open()
{
}
/**
* Close the transport.
*/
public function close()
{
$this->request_ = '';
$this->response_ = null;
}
/**
* Read some data into the array.
*
* @param int $len How much to read
* @return string The data that has been read
* @throws TTransportException if cannot read any more data
*/
public function read($len)
{
if ($len >= strlen($this->response_)) {
return $this->response_;
} else {
$ret = substr($this->response_, 0, $len);
$this->response_ = substr($this->response_, $len);
return $ret;
}
}
/**
* Writes some data into the pending buffer
*
* @param string $buf The data to write
* @throws TTransportException if writing fails
*/
public function write($buf)
{
$this->request_ .= $buf;
}
/**
* Opens and sends the actual request over the HTTP connection
*
* @throws TTransportException if a writing error occurs
*/
public function flush()
{
if (!self::$curlHandle) {
register_shutdown_function(array('Thrift\\Transport\\TCurlClient', 'closeCurlHandle'));
self::$curlHandle = curl_init();
curl_setopt(self::$curlHandle, CURLOPT_RETURNTRANSFER, true);
curl_setopt(self::$curlHandle, CURLOPT_BINARYTRANSFER, true);
curl_setopt(self::$curlHandle, CURLOPT_USERAGENT, 'PHP/TCurlClient');
curl_setopt(self::$curlHandle, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt(self::$curlHandle, CURLOPT_FOLLOWLOCATION, true);
curl_setopt(self::$curlHandle, CURLOPT_MAXREDIRS, 1);
}
// God, PHP really has some esoteric ways of doing simple things.
$host = $this->host_.($this->port_ != 80 ? ':'.$this->port_ : '');
$fullUrl = $this->scheme_."://".$host.$this->uri_;
$headers = array('Accept: application/x-thrift',
'Content-Type: application/x-thrift',
'Content-Length: '.TStringFuncFactory::create()->strlen($this->request_));
curl_setopt(self::$curlHandle, CURLOPT_HTTPHEADER, $headers);
if ($this->timeout_ > 0) {
curl_setopt(self::$curlHandle, CURLOPT_TIMEOUT, $this->timeout_);
}
curl_setopt(self::$curlHandle, CURLOPT_POSTFIELDS, $this->request_);
$this->request_ = '';
curl_setopt(self::$curlHandle, CURLOPT_URL, $fullUrl);
$this->response_ = curl_exec(self::$curlHandle);
// Connect failed?
if (!$this->response_) {
curl_close(self::$curlHandle);
self::$curlHandle = null;
$error = 'TCurlClient: Could not connect to '.$fullUrl;
throw new TTransportException($error, TTransportException::NOT_OPEN);
}
}
public static function closeCurlHandle()
{
try {
if (self::$curlHandle) {
curl_close(self::$curlHandle);
self::$curlHandle = null;
}
} catch (\Exception $x) {
error_log('There was an error closing the curl handle: ' . $x->getMessage());
}
}
}

View file

@ -1,193 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Factory\TStringFuncFactory;
/**
* Framed transport. Writes and reads data in chunks that are stamped with
* their length.
*
* @package thrift.transport
*/
class TFramedTransport extends TTransport
{
/**
* Underlying transport object.
*
* @var TTransport
*/
private $transport_;
/**
* Buffer for read data.
*
* @var string
*/
private $rBuf_;
/**
* Buffer for queued output data
*
* @var string
*/
private $wBuf_;
/**
* Whether to frame reads
*
* @var bool
*/
private $read_;
/**
* Whether to frame writes
*
* @var bool
*/
private $write_;
/**
* Constructor.
*
* @param TTransport $transport Underlying transport
*/
public function __construct($transport=null, $read=true, $write=true)
{
$this->transport_ = $transport;
$this->read_ = $read;
$this->write_ = $write;
}
public function isOpen()
{
return $this->transport_->isOpen();
}
public function open()
{
$this->transport_->open();
}
public function close()
{
$this->transport_->close();
}
/**
* Reads from the buffer. When more data is required reads another entire
* chunk and serves future reads out of that.
*
* @param int $len How much data
*/
public function read($len)
{
if (!$this->read_) {
return $this->transport_->read($len);
}
if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
$this->readFrame();
}
// Just return full buff
if ($len >= TStringFuncFactory::create()->strlen($this->rBuf_)) {
$out = $this->rBuf_;
$this->rBuf_ = null;
return $out;
}
// Return TStringFuncFactory::create()->substr
$out = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len);
$this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len);
return $out;
}
/**
* Put previously read data back into the buffer
*
* @param string $data data to return
*/
public function putBack($data)
{
if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
$this->rBuf_ = $data;
} else {
$this->rBuf_ = ($data . $this->rBuf_);
}
}
/**
* Reads a chunk of data into the internal read buffer.
*/
private function readFrame()
{
$buf = $this->transport_->readAll(4);
$val = unpack('N', $buf);
$sz = $val[1];
$this->rBuf_ = $this->transport_->readAll($sz);
}
/**
* Writes some data to the pending output buffer.
*
* @param string $buf The data
* @param int $len Limit of bytes to write
*/
public function write($buf, $len=null)
{
if (!$this->write_) {
return $this->transport_->write($buf, $len);
}
if ($len !== null && $len < TStringFuncFactory::create()->strlen($buf)) {
$buf = TStringFuncFactory::create()->substr($buf, 0, $len);
}
$this->wBuf_ .= $buf;
}
/**
* Writes the output buffer to the stream in the format of a 4-byte length
* followed by the actual data.
*/
public function flush()
{
if (!$this->write_ || TStringFuncFactory::create()->strlen($this->wBuf_) == 0) {
return $this->transport_->flush();
}
$out = pack('N', TStringFuncFactory::create()->strlen($this->wBuf_));
$out .= $this->wBuf_;
// Note that we clear the internal wBuf_ prior to the underlying write
// to ensure we're in a sane state (i.e. internal buffer cleaned)
// if the underlying write throws up an exception
$this->wBuf_ = '';
$this->transport_->write($out);
$this->transport_->flush();
}
}

View file

@ -1,229 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TTransportException;
use Thrift\Factory\TStringFuncFactory;
/**
* HTTP client for Thrift
*
* @package thrift.transport
*/
class THttpClient extends TTransport
{
/**
* The host to connect to
*
* @var string
*/
protected $host_;
/**
* The port to connect on
*
* @var int
*/
protected $port_;
/**
* The URI to request
*
* @var string
*/
protected $uri_;
/**
* The scheme to use for the request, i.e. http, https
*
* @var string
*/
protected $scheme_;
/**
* Buffer for the HTTP request data
*
* @var string
*/
protected $buf_;
/**
* Input socket stream.
*
* @var resource
*/
protected $handle_;
/**
* Read timeout
*
* @var float
*/
protected $timeout_;
/**
* http headers
*
* @var array
*/
protected $headers_;
/**
* Make a new HTTP client.
*
* @param string $host
* @param int $port
* @param string $uri
*/
public function __construct($host, $port=80, $uri='', $scheme = 'http')
{
if ((TStringFuncFactory::create()->strlen($uri) > 0) && ($uri{0} != '/')) {
$uri = '/'.$uri;
}
$this->scheme_ = $scheme;
$this->host_ = $host;
$this->port_ = $port;
$this->uri_ = $uri;
$this->buf_ = '';
$this->handle_ = null;
$this->timeout_ = null;
$this->headers_ = array();
}
/**
* Set read timeout
*
* @param float $timeout
*/
public function setTimeoutSecs($timeout)
{
$this->timeout_ = $timeout;
}
/**
* Whether this transport is open.
*
* @return boolean true if open
*/
public function isOpen()
{
return true;
}
/**
* Open the transport for reading/writing
*
* @throws TTransportException if cannot open
*/
public function open() {}
/**
* Close the transport.
*/
public function close()
{
if ($this->handle_) {
@fclose($this->handle_);
$this->handle_ = null;
}
}
/**
* Read some data into the array.
*
* @param int $len How much to read
* @return string The data that has been read
* @throws TTransportException if cannot read any more data
*/
public function read($len)
{
$data = @fread($this->handle_, $len);
if ($data === FALSE || $data === '') {
$md = stream_get_meta_data($this->handle_);
if ($md['timed_out']) {
throw new TTransportException('THttpClient: timed out reading '.$len.' bytes from '.$this->host_.':'.$this->port_.$this->uri_, TTransportException::TIMED_OUT);
} else {
throw new TTransportException('THttpClient: Could not read '.$len.' bytes from '.$this->host_.':'.$this->port_.$this->uri_, TTransportException::UNKNOWN);
}
}
return $data;
}
/**
* Writes some data into the pending buffer
*
* @param string $buf The data to write
* @throws TTransportException if writing fails
*/
public function write($buf)
{
$this->buf_ .= $buf;
}
/**
* Opens and sends the actual request over the HTTP connection
*
* @throws TTransportException if a writing error occurs
*/
public function flush()
{
// God, PHP really has some esoteric ways of doing simple things.
$host = $this->host_.($this->port_ != 80 ? ':'.$this->port_ : '');
$headers = array();
$defaultHeaders = array('Host' => $host,
'Accept' => 'application/x-thrift',
'User-Agent' => 'PHP/THttpClient',
'Content-Type' => 'application/x-thrift',
'Content-Length' => TStringFuncFactory::create()->strlen($this->buf_));
foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) {
$headers[] = "$key: $value";
}
$options = array('method' => 'POST',
'header' => implode("\r\n", $headers),
'max_redirects' => 1,
'content' => $this->buf_);
if ($this->timeout_ > 0) {
$options['timeout'] = $this->timeout_;
}
$this->buf_ = '';
$contextid = stream_context_create(array('http' => $options));
$this->handle_ = @fopen($this->scheme_.'://'.$host.$this->uri_, 'r', false, $contextid);
// Connect failed?
if ($this->handle_ === FALSE) {
$this->handle_ = null;
$error = 'THttpClient: Could not connect to '.$host.$this->uri_;
throw new TTransportException($error, TTransportException::NOT_OPEN);
}
}
public function addHeaders($headers)
{
$this->headers_ = array_merge($this->headers_, $headers);
}
}

View file

@ -1,100 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TTransportException;
use Thrift\Factory\TStringFuncFactory;
/**
* A memory buffer is a tranpsort that simply reads from and writes to an
* in-memory string buffer. Anytime you call write on it, the data is simply
* placed into a buffer, and anytime you call read, data is read from that
* buffer.
*
* @package thrift.transport
*/
class TMemoryBuffer extends TTransport
{
/**
* Constructor. Optionally pass an initial value
* for the buffer.
*/
public function __construct($buf = '')
{
$this->buf_ = $buf;
}
protected $buf_ = '';
public function isOpen()
{
return true;
}
public function open() {}
public function close() {}
public function write($buf)
{
$this->buf_ .= $buf;
}
public function read($len)
{
$bufLength = TStringFuncFactory::create()->strlen($this->buf_);
if ($bufLength === 0) {
throw new TTransportException('TMemoryBuffer: Could not read ' .
$len . ' bytes from buffer.',
TTransportException::UNKNOWN);
}
if ($bufLength <= $len) {
$ret = $this->buf_;
$this->buf_ = '';
return $ret;
}
$ret = TStringFuncFactory::create()->substr($this->buf_, 0, $len);
$this->buf_ = TStringFuncFactory::create()->substr($this->buf_, $len);
return $ret;
}
public function getBuffer()
{
return $this->buf_;
}
public function available()
{
return TStringFuncFactory::create()->strlen($this->buf_);
}
public function putBack($data)
{
$this->buf_ = $data.$this->buf_;
}
}

View file

@ -1,123 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TException;
use Thrift\Factory\TStringFuncFactory;
/**
* Php stream transport. Reads to and writes from the php standard streams
* php://input and php://output
*
* @package thrift.transport
*/
class TPhpStream extends TTransport
{
const MODE_R = 1;
const MODE_W = 2;
private $inStream_ = null;
private $outStream_ = null;
private $read_ = false;
private $write_ = false;
public function __construct($mode)
{
$this->read_ = $mode & self::MODE_R;
$this->write_ = $mode & self::MODE_W;
}
public function open()
{
if ($this->read_) {
$this->inStream_ = @fopen(self::inStreamName(), 'r');
if (!is_resource($this->inStream_)) {
throw new TException('TPhpStream: Could not open php://input');
}
}
if ($this->write_) {
$this->outStream_ = @fopen('php://output', 'w');
if (!is_resource($this->outStream_)) {
throw new TException('TPhpStream: Could not open php://output');
}
}
}
public function close()
{
if ($this->read_) {
@fclose($this->inStream_);
$this->inStream_ = null;
}
if ($this->write_) {
@fclose($this->outStream_);
$this->outStream_ = null;
}
}
public function isOpen()
{
return
(!$this->read_ || is_resource($this->inStream_)) &&
(!$this->write_ || is_resource($this->outStream_));
}
public function read($len)
{
$data = @fread($this->inStream_, $len);
if ($data === FALSE || $data === '') {
throw new TException('TPhpStream: Could not read '.$len.' bytes');
}
return $data;
}
public function write($buf)
{
while (TStringFuncFactory::create()->strlen($buf) > 0) {
$got = @fwrite($this->outStream_, $buf);
if ($got === 0 || $got === FALSE) {
throw new TException('TPhpStream: Could not write '.TStringFuncFactory::create()->strlen($buf).' bytes');
}
$buf = TStringFuncFactory::create()->substr($buf, $got);
}
}
public function flush()
{
@fflush($this->outStream_);
}
private static function inStreamName()
{
if (php_sapi_name() == 'cli') {
return 'php://stdin';
}
return 'php://input';
}
}

View file

@ -1,112 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TException;
use Thrift\Exception\TTransportException;
use Thrift\Factory\TStringFuncFactory;
/**
* Sockets implementation of the TTransport interface.
*
* @package thrift.transport
*/
class TSSLSocket extends TSocket
{
/**
* Remote port
*
* @var resource
*/
protected $context_ = null;
/**
* Socket constructor
*
* @param string $host Remote hostname
* @param int $port Remote port
* @param resource $context Stream context
* @param bool $persist Whether to use a persistent socket
* @param string $debugHandler Function to call for error logging
*/
public function __construct($host='localhost',
$port=9090,
$context=null,
$debugHandler=null) {
$this->host_ = $this->getSSLHost($host);
$this->port_ = $port;
$this->context_ = $context;
$this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log';
}
/**
* Creates a host name with SSL transport protocol
* if no transport protocol already specified in
* the host name.
*
* @param string $host Host to listen on
* @return string $host Host name with transport protocol
*/
private function getSSLHost($host)
{
$transport_protocol_loc = strpos($host, "://");
if ($transport_protocol_loc === false) {
$host = 'ssl://'.$host;
}
return $host;
}
/**
* Connects the socket.
*/
public function open()
{
if ($this->isOpen()) {
throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN);
}
if (empty($this->host_)) {
throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN);
}
if ($this->port_ <= 0) {
throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN);
}
$this->handle_ = @stream_socket_client($this->host_.':'.$this->port_,
$errno,
$errstr,
$this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000),
STREAM_CLIENT_CONNECT,
$this->context_);
// Connect failed?
if ($this->handle_ === FALSE) {
$error = 'TSocket: Could not connect to '.$this->host_.':'.$this->port_.' ('.$errstr.' ['.$errno.'])';
if ($this->debug_) {
call_user_func($this->debugHandler_, $error);
}
throw new TException($error);
}
}
}

View file

@ -1,337 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TException;
use Thrift\Exception\TTransportException;
use Thrift\Factory\TStringFuncFactory;
/**
* Sockets implementation of the TTransport interface.
*
* @package thrift.transport
*/
class TSocket extends TTransport
{
/**
* Handle to PHP socket
*
* @var resource
*/
protected $handle_ = null;
/**
* Remote hostname
*
* @var string
*/
protected $host_ = 'localhost';
/**
* Remote port
*
* @var int
*/
protected $port_ = '9090';
/**
* Send timeout in seconds.
*
* Combined with sendTimeoutUsec this is used for send timeouts.
*
* @var int
*/
protected $sendTimeoutSec_ = 0;
/**
* Send timeout in microseconds.
*
* Combined with sendTimeoutSec this is used for send timeouts.
*
* @var int
*/
protected $sendTimeoutUsec_ = 100000;
/**
* Recv timeout in seconds
*
* Combined with recvTimeoutUsec this is used for recv timeouts.
*
* @var int
*/
protected $recvTimeoutSec_ = 0;
/**
* Recv timeout in microseconds
*
* Combined with recvTimeoutSec this is used for recv timeouts.
*
* @var int
*/
protected $recvTimeoutUsec_ = 750000;
/**
* Persistent socket or plain?
*
* @var bool
*/
protected $persist_ = false;
/**
* Debugging on?
*
* @var bool
*/
protected $debug_ = false;
/**
* Debug handler
*
* @var mixed
*/
protected $debugHandler_ = null;
/**
* Socket constructor
*
* @param string $host Remote hostname
* @param int $port Remote port
* @param bool $persist Whether to use a persistent socket
* @param string $debugHandler Function to call for error logging
*/
public function __construct($host='localhost',
$port=9090,
$persist=false,
$debugHandler=null) {
$this->host_ = $host;
$this->port_ = $port;
$this->persist_ = $persist;
$this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log';
}
/**
* @param resource $handle
* @return void
*/
public function setHandle($handle)
{
$this->handle_ = $handle;
}
/**
* Sets the send timeout.
*
* @param int $timeout Timeout in milliseconds.
*/
public function setSendTimeout($timeout)
{
$this->sendTimeoutSec_ = floor($timeout / 1000);
$this->sendTimeoutUsec_ =
($timeout - ($this->sendTimeoutSec_ * 1000)) * 1000;
}
/**
* Sets the receive timeout.
*
* @param int $timeout Timeout in milliseconds.
*/
public function setRecvTimeout($timeout)
{
$this->recvTimeoutSec_ = floor($timeout / 1000);
$this->recvTimeoutUsec_ =
($timeout - ($this->recvTimeoutSec_ * 1000)) * 1000;
}
/**
* Sets debugging output on or off
*
* @param bool $debug
*/
public function setDebug($debug)
{
$this->debug_ = $debug;
}
/**
* Get the host that this socket is connected to
*
* @return string host
*/
public function getHost()
{
return $this->host_;
}
/**
* Get the remote port that this socket is connected to
*
* @return int port
*/
public function getPort()
{
return $this->port_;
}
/**
* Tests whether this is open
*
* @return bool true if the socket is open
*/
public function isOpen()
{
return is_resource($this->handle_);
}
/**
* Connects the socket.
*/
public function open()
{
if ($this->isOpen()) {
throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN);
}
if (empty($this->host_)) {
throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN);
}
if ($this->port_ <= 0) {
throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN);
}
if ($this->persist_) {
$this->handle_ = @pfsockopen($this->host_,
$this->port_,
$errno,
$errstr,
$this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000));
} else {
$this->handle_ = @fsockopen($this->host_,
$this->port_,
$errno,
$errstr,
$this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000));
}
// Connect failed?
if ($this->handle_ === FALSE) {
$error = 'TSocket: Could not connect to '.$this->host_.':'.$this->port_.' ('.$errstr.' ['.$errno.'])';
if ($this->debug_) {
call_user_func($this->debugHandler_, $error);
}
throw new TException($error);
}
}
/**
* Closes the socket.
*/
public function close()
{
if (!$this->persist_) {
@fclose($this->handle_);
$this->handle_ = null;
}
}
/**
* Read from the socket at most $len bytes.
*
* This method will not wait for all the requested data, it will return as
* soon as any data is received.
*
* @param int $len Maximum number of bytes to read.
* @return string Binary data
*/
public function read($len)
{
$null = null;
$read = array($this->handle_);
$readable = @stream_select($read, $null, $null, $this->recvTimeoutSec_, $this->recvTimeoutUsec_);
if ($readable > 0) {
$data = fread($this->handle_, $len);
if ($data === false) {
throw new TTransportException('TSocket: Could not read '.$len.' bytes from '.
$this->host_.':'.$this->port_);
} elseif ($data == '' && feof($this->handle_)) {
throw new TTransportException('TSocket read 0 bytes');
}
return $data;
} elseif ($readable === 0) {
throw new TTransportException('TSocket: timed out reading '.$len.' bytes from '.
$this->host_.':'.$this->port_);
} else {
throw new TTransportException('TSocket: Could not read '.$len.' bytes from '.
$this->host_.':'.$this->port_);
}
}
/**
* Write to the socket.
*
* @param string $buf The data to write
*/
public function write($buf)
{
$null = null;
$write = array($this->handle_);
// keep writing until all the data has been written
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 = fwrite($this->handle_, $buf);
if ($written === -1 || $written === false) {
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 = TStringFuncFactory::create()->substr($buf, $written);
} elseif ($writable === 0) {
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 '.TStringFuncFactory::create()->strlen($buf).' bytes '.
$this->host_.':'.$this->port_);
}
}
}
/**
* Flush output to the socket.
*
* Since read(), readAll() and write() operate on the sockets directly,
* this is a no-op
*
* If you wish to have flushable buffering behaviour, wrap this TSocket
* in a TBufferedTransport.
*/
public function flush()
{
// no-op
}
}

View file

@ -1,300 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TException;
/**
* This library makes use of APC cache to make hosts as down in a web
* environment. If you are running from the CLI or on a system without APC
* installed, then these null functions will step in and act like cache
* misses.
*/
if (!function_exists('apc_fetch')) {
function apc_fetch($key) { return FALSE; }
function apc_store($key, $var, $ttl=0) { return FALSE; }
}
/**
* Sockets implementation of the TTransport interface that allows connection
* to a pool of servers.
*
* @package thrift.transport
*/
class TSocketPool extends TSocket
{
/**
* Remote servers. Array of associative arrays with 'host' and 'port' keys
*/
private $servers_ = array();
/**
* How many times to retry each host in connect
*
* @var int
*/
private $numRetries_ = 1;
/**
* Retry interval in seconds, how long to not try a host if it has been
* marked as down.
*
* @var int
*/
private $retryInterval_ = 60;
/**
* Max consecutive failures before marking a host down.
*
* @var int
*/
private $maxConsecutiveFailures_ = 1;
/**
* Try hosts in order? or Randomized?
*
* @var bool
*/
private $randomize_ = true;
/**
* Always try last host, even if marked down?
*
* @var bool
*/
private $alwaysTryLast_ = true;
/**
* Socket pool constructor
*
* @param array $hosts List of remote hostnames
* @param mixed $ports Array of remote ports, or a single common port
* @param bool $persist Whether to use a persistent socket
* @param mixed $debugHandler Function for error logging
*/
public function __construct($hosts=array('localhost'),
$ports=array(9090),
$persist=false,
$debugHandler=null) {
parent::__construct(null, 0, $persist, $debugHandler);
if (!is_array($ports)) {
$port = $ports;
$ports = array();
foreach ($hosts as $key => $val) {
$ports[$key] = $port;
}
}
foreach ($hosts as $key => $host) {
$this->servers_ []= array('host' => $host,
'port' => $ports[$key]);
}
}
/**
* Add a server to the pool
*
* This function does not prevent you from adding a duplicate server entry.
*
* @param string $host hostname or IP
* @param int $port port
*/
public function addServer($host, $port)
{
$this->servers_[] = array('host' => $host, 'port' => $port);
}
/**
* Sets how many time to keep retrying a host in the connect function.
*
* @param int $numRetries
*/
public function setNumRetries($numRetries)
{
$this->numRetries_ = $numRetries;
}
/**
* Sets how long to wait until retrying a host if it was marked down
*
* @param int $numRetries
*/
public function setRetryInterval($retryInterval)
{
$this->retryInterval_ = $retryInterval;
}
/**
* Sets how many time to keep retrying a host before marking it as down.
*
* @param int $numRetries
*/
public function setMaxConsecutiveFailures($maxConsecutiveFailures)
{
$this->maxConsecutiveFailures_ = $maxConsecutiveFailures;
}
/**
* Turns randomization in connect order on or off.
*
* @param bool $randomize
*/
public function setRandomize($randomize)
{
$this->randomize_ = $randomize;
}
/**
* Whether to always try the last server.
*
* @param bool $alwaysTryLast
*/
public function setAlwaysTryLast($alwaysTryLast)
{
$this->alwaysTryLast_ = $alwaysTryLast;
}
/**
* Connects the socket by iterating through all the servers in the pool
* and trying to find one that works.
*/
public function open()
{
// Check if we want order randomization
if ($this->randomize_) {
shuffle($this->servers_);
}
// Count servers to identify the "last" one
$numServers = count($this->servers_);
for ($i = 0; $i < $numServers; ++$i) {
// This extracts the $host and $port variables
extract($this->servers_[$i]);
// Check APC cache for a record of this server being down
$failtimeKey = 'thrift_failtime:'.$host.':'.$port.'~';
// Cache miss? Assume it's OK
$lastFailtime = apc_fetch($failtimeKey);
if ($lastFailtime === FALSE) {
$lastFailtime = 0;
}
$retryIntervalPassed = false;
// Cache hit...make sure enough the retry interval has elapsed
if ($lastFailtime > 0) {
$elapsed = time() - $lastFailtime;
if ($elapsed > $this->retryInterval_) {
$retryIntervalPassed = true;
if ($this->debug_) {
call_user_func($this->debugHandler_,
'TSocketPool: retryInterval '.
'('.$this->retryInterval_.') '.
'has passed for host '.$host.':'.$port);
}
}
}
// Only connect if not in the middle of a fail interval, OR if this
// is the LAST server we are trying, just hammer away on it
$isLastServer = false;
if ($this->alwaysTryLast_) {
$isLastServer = ($i == ($numServers - 1));
}
if (($lastFailtime === 0) ||
($isLastServer) ||
($lastFailtime > 0 && $retryIntervalPassed)) {
// Set underlying TSocket params to this one
$this->host_ = $host;
$this->port_ = $port;
// Try up to numRetries_ connections per server
for ($attempt = 0; $attempt < $this->numRetries_; $attempt++) {
try {
// Use the underlying TSocket open function
parent::open();
// Only clear the failure counts if required to do so
if ($lastFailtime > 0) {
apc_store($failtimeKey, 0);
}
// Successful connection, return now
return;
} catch (TException $tx) {
// Connection failed
}
}
// Mark failure of this host in the cache
$consecfailsKey = 'thrift_consecfails:'.$host.':'.$port.'~';
// Ignore cache misses
$consecfails = apc_fetch($consecfailsKey);
if ($consecfails === FALSE) {
$consecfails = 0;
}
// Increment by one
$consecfails++;
// Log and cache this failure
if ($consecfails >= $this->maxConsecutiveFailures_) {
if ($this->debug_) {
call_user_func($this->debugHandler_,
'TSocketPool: marking '.$host.':'.$port.
' as down for '.$this->retryInterval_.' secs '.
'after '.$consecfails.' failed attempts.');
}
// Store the failure time
apc_store($failtimeKey, time());
// Clear the count of consecutive failures
apc_store($consecfailsKey, 0);
} else {
apc_store($consecfailsKey, $consecfails);
}
}
}
// Oh no; we failed them all. The system is totally ill!
$error = 'TSocketPool: All hosts in pool are down. ';
$hosts = array();
foreach ($this->servers_ as $server) {
$hosts []= $server['host'].':'.$server['port'];
}
$hostlist = implode(',', $hosts);
$error .= '('.$hostlist.')';
if ($this->debug_) {
call_user_func($this->debugHandler_, $error);
}
throw new TException($error);
}
}

View file

@ -1,95 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Factory\TStringFuncFactory;
/**
* Base interface for a transport agent.
*
* @package thrift.transport
*/
abstract class TTransport
{
/**
* Whether this transport is open.
*
* @return boolean true if open
*/
abstract public function isOpen();
/**
* Open the transport for reading/writing
*
* @throws TTransportException if cannot open
*/
abstract public function open();
/**
* Close the transport.
*/
abstract public function close();
/**
* Read some data into the array.
*
* @param int $len How much to read
* @return string The data that has been read
* @throws TTransportException if cannot read any more data
*/
abstract public function read($len);
/**
* Guarantees that the full amount of data is read.
*
* @return string The data, of exact length
* @throws TTransportException if cannot read data
*/
public function readAll($len)
{
// return $this->read($len);
$data = '';
$got = 0;
while (($got = TStringFuncFactory::create()->strlen($data)) < $len) {
$data .= $this->read($len - $got);
}
return $data;
}
/**
* Writes the given data out.
*
* @param string $buf The data to write
* @throws TTransportException if writing fails
*/
abstract public function write($buf);
/**
* Flushes any pending data out of a buffer
*
* @throws TTransportException if a writing error occurs
*/
public function flush() {}
}

View file

@ -0,0 +1,206 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TTransportException;
use Thrift\Factory\TStringFuncFactory;
/**
* Buffered transport. Stores data to an internal buffer that it doesn't
* actually write out until flush is called. For reading, we do a greedy
* read and then serve data out of the internal buffer.
*
* @package thrift.transport
*/
class TBufferedTransport extends TTransport
{
/**
* The underlying transport
*
* @var TTransport
*/
protected $transport_;
/**
* The receive buffer size
*
* @var int
*/
protected $rBufSize_ = 512;
/**
* The write buffer size
*
* @var int
*/
protected $wBufSize_ = 512;
/**
* The write buffer.
*
* @var string
*/
protected $wBuf_ = '';
/**
* The read buffer.
*
* @var string
*/
protected $rBuf_ = '';
/**
* Constructor. Creates a buffered transport around an underlying transport
*/
public function __construct($transport, $rBufSize = 512, $wBufSize = 512)
{
$this->transport_ = $transport;
$this->rBufSize_ = $rBufSize;
$this->wBufSize_ = $wBufSize;
}
public function isOpen()
{
return $this->transport_->isOpen();
}
/**
* @inheritdoc
*
* @throws TTransportException
*/
public function open()
{
$this->transport_->open();
}
public function close()
{
$this->transport_->close();
}
public function putBack($data)
{
if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
$this->rBuf_ = $data;
} else {
$this->rBuf_ = ($data . $this->rBuf_);
}
}
/**
* The reason that we customize readAll here is that the majority of PHP
* streams are already internally buffered by PHP. The socket stream, for
* example, buffers internally and blocks if you call read with $len greater
* than the amount of data available, unlike recv() in C.
*
* Therefore, use the readAll method of the wrapped transport inside
* the buffered readAll.
*
* @throws TTransportException
*/
public function readAll($len)
{
$have = TStringFuncFactory::create()->strlen($this->rBuf_);
if ($have == 0) {
$data = $this->transport_->readAll($len);
} elseif ($have < $len) {
$data = $this->rBuf_;
$this->rBuf_ = '';
$data .= $this->transport_->readAll($len - $have);
} elseif ($have == $len) {
$data = $this->rBuf_;
$this->rBuf_ = '';
} elseif ($have > $len) {
$data = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len);
$this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len);
}
return $data;
}
/**
* @inheritdoc
*
* @param int $len
* @return string
* @throws TTransportException
*/
public function read($len)
{
if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
$this->rBuf_ = $this->transport_->read($this->rBufSize_);
}
if (TStringFuncFactory::create()->strlen($this->rBuf_) <= $len) {
$ret = $this->rBuf_;
$this->rBuf_ = '';
return $ret;
}
$ret = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len);
$this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len);
return $ret;
}
/**
* @inheritdoc
*
* @param string $buf
* @throws TTransportException
*/
public function write($buf)
{
$this->wBuf_ .= $buf;
if (TStringFuncFactory::create()->strlen($this->wBuf_) >= $this->wBufSize_) {
$out = $this->wBuf_;
// Note that we clear the internal wBuf_ prior to the underlying write
// to ensure we're in a sane state (i.e. internal buffer cleaned)
// if the underlying write throws up an exception
$this->wBuf_ = '';
$this->transport_->write($out);
}
}
/**
* @inheritdoc
*
* @throws TTransportException
*/
public function flush()
{
if (TStringFuncFactory::create()->strlen($this->wBuf_) > 0) {
$out = $this->wBuf_;
// Note that we clear the internal wBuf_ prior to the underlying write
// to ensure we're in a sane state (i.e. internal buffer cleaned)
// if the underlying write throws up an exception
$this->wBuf_ = '';
$this->transport_->write($out);
}
$this->transport_->flush();
}
}

View file

@ -0,0 +1,258 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TTransportException;
use Thrift\Factory\TStringFuncFactory;
/**
* HTTP client for Thrift
*
* @package thrift.transport
*/
class TCurlClient extends TTransport
{
private static $curlHandle;
/**
* The host to connect to
*
* @var string
*/
protected $host_;
/**
* The port to connect on
*
* @var int
*/
protected $port_;
/**
* The URI to request
*
* @var string
*/
protected $uri_;
/**
* The scheme to use for the request, i.e. http, https
*
* @var string
*/
protected $scheme_;
/**
* Buffer for the HTTP request data
*
* @var string
*/
protected $request_;
/**
* Buffer for the HTTP response data.
*
* @var binary string
*/
protected $response_;
/**
* Read timeout
*
* @var float
*/
protected $timeout_;
/**
* http headers
*
* @var array
*/
protected $headers_;
/**
* Make a new HTTP client.
*
* @param string $host
* @param int $port
* @param string $uri
*/
public function __construct($host, $port = 80, $uri = '', $scheme = 'http')
{
if ((TStringFuncFactory::create()->strlen($uri) > 0) && ($uri{0} != '/')) {
$uri = '/' . $uri;
}
$this->scheme_ = $scheme;
$this->host_ = $host;
$this->port_ = $port;
$this->uri_ = $uri;
$this->request_ = '';
$this->response_ = null;
$this->timeout_ = null;
$this->headers_ = array();
}
/**
* Set read timeout
*
* @param float $timeout
*/
public function setTimeoutSecs($timeout)
{
$this->timeout_ = $timeout;
}
/**
* Whether this transport is open.
*
* @return boolean true if open
*/
public function isOpen()
{
return true;
}
/**
* Open the transport for reading/writing
*
* @throws TTransportException if cannot open
*/
public function open()
{
}
/**
* Close the transport.
*/
public function close()
{
$this->request_ = '';
$this->response_ = null;
}
/**
* Read some data into the array.
*
* @param int $len How much to read
* @return string The data that has been read
* @throws TTransportException if cannot read any more data
*/
public function read($len)
{
if ($len >= strlen($this->response_)) {
return $this->response_;
} else {
$ret = substr($this->response_, 0, $len);
$this->response_ = substr($this->response_, $len);
return $ret;
}
}
/**
* Writes some data into the pending buffer
*
* @param string $buf The data to write
* @throws TTransportException if writing fails
*/
public function write($buf)
{
$this->request_ .= $buf;
}
/**
* Opens and sends the actual request over the HTTP connection
*
* @throws TTransportException if a writing error occurs
*/
public function flush()
{
if (!self::$curlHandle) {
register_shutdown_function(array('Thrift\\Transport\\TCurlClient', 'closeCurlHandle'));
self::$curlHandle = curl_init();
curl_setopt(self::$curlHandle, CURLOPT_RETURNTRANSFER, true);
curl_setopt(self::$curlHandle, CURLOPT_BINARYTRANSFER, true);
curl_setopt(self::$curlHandle, CURLOPT_USERAGENT, 'PHP/TCurlClient');
curl_setopt(self::$curlHandle, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt(self::$curlHandle, CURLOPT_FOLLOWLOCATION, true);
curl_setopt(self::$curlHandle, CURLOPT_MAXREDIRS, 1);
}
// God, PHP really has some esoteric ways of doing simple things.
$host = $this->host_ . ($this->port_ != 80 ? ':' . $this->port_ : '');
$fullUrl = $this->scheme_ . "://" . $host . $this->uri_;
$headers = array();
$defaultHeaders = array('Accept' => 'application/x-thrift',
'Content-Type' => 'application/x-thrift',
'Content-Length' => TStringFuncFactory::create()->strlen($this->request_));
foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) {
$headers[] = "$key: $value";
}
curl_setopt(self::$curlHandle, CURLOPT_HTTPHEADER, $headers);
if ($this->timeout_ > 0) {
curl_setopt(self::$curlHandle, CURLOPT_TIMEOUT, $this->timeout_);
}
curl_setopt(self::$curlHandle, CURLOPT_POSTFIELDS, $this->request_);
$this->request_ = '';
curl_setopt(self::$curlHandle, CURLOPT_URL, $fullUrl);
$this->response_ = curl_exec(self::$curlHandle);
$responseError = curl_error(self::$curlHandle);
$code = curl_getinfo(self::$curlHandle, CURLINFO_HTTP_CODE);
// Handle non 200 status code / connect failure
if ($this->response_ === false || $code !== 200) {
curl_close(self::$curlHandle);
self::$curlHandle = null;
$this->response_ = null;
$error = 'TCurlClient: Could not connect to ' . $fullUrl;
if ($responseError) {
$error .= ', ' . $responseError;
}
if ($code) {
$error .= ', HTTP status code: ' . $code;
}
throw new TTransportException($error, TTransportException::UNKNOWN);
}
}
public static function closeCurlHandle()
{
try {
if (self::$curlHandle) {
curl_close(self::$curlHandle);
self::$curlHandle = null;
}
} catch (\Exception $x) {
error_log('There was an error closing the curl handle: ' . $x->getMessage());
}
}
public function addHeaders($headers)
{
$this->headers_ = array_merge($this->headers_, $headers);
}
}

View file

@ -0,0 +1,192 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Factory\TStringFuncFactory;
/**
* Framed transport. Writes and reads data in chunks that are stamped with
* their length.
*
* @package thrift.transport
*/
class TFramedTransport extends TTransport
{
/**
* Underlying transport object.
*
* @var TTransport
*/
private $transport_;
/**
* Buffer for read data.
*
* @var string
*/
private $rBuf_;
/**
* Buffer for queued output data
*
* @var string
*/
private $wBuf_;
/**
* Whether to frame reads
*
* @var bool
*/
private $read_;
/**
* Whether to frame writes
*
* @var bool
*/
private $write_;
/**
* Constructor.
*
* @param TTransport $transport Underlying transport
*/
public function __construct($transport = null, $read = true, $write = true)
{
$this->transport_ = $transport;
$this->read_ = $read;
$this->write_ = $write;
}
public function isOpen()
{
return $this->transport_->isOpen();
}
public function open()
{
$this->transport_->open();
}
public function close()
{
$this->transport_->close();
}
/**
* Reads from the buffer. When more data is required reads another entire
* chunk and serves future reads out of that.
*
* @param int $len How much data
*/
public function read($len)
{
if (!$this->read_) {
return $this->transport_->read($len);
}
if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
$this->readFrame();
}
// Just return full buff
if ($len >= TStringFuncFactory::create()->strlen($this->rBuf_)) {
$out = $this->rBuf_;
$this->rBuf_ = null;
return $out;
}
// Return TStringFuncFactory::create()->substr
$out = TStringFuncFactory::create()->substr($this->rBuf_, 0, $len);
$this->rBuf_ = TStringFuncFactory::create()->substr($this->rBuf_, $len);
return $out;
}
/**
* Put previously read data back into the buffer
*
* @param string $data data to return
*/
public function putBack($data)
{
if (TStringFuncFactory::create()->strlen($this->rBuf_) === 0) {
$this->rBuf_ = $data;
} else {
$this->rBuf_ = ($data . $this->rBuf_);
}
}
/**
* Reads a chunk of data into the internal read buffer.
*/
private function readFrame()
{
$buf = $this->transport_->readAll(4);
$val = unpack('N', $buf);
$sz = $val[1];
$this->rBuf_ = $this->transport_->readAll($sz);
}
/**
* Writes some data to the pending output buffer.
*
* @param string $buf The data
* @param int $len Limit of bytes to write
*/
public function write($buf, $len = null)
{
if (!$this->write_) {
return $this->transport_->write($buf, $len);
}
if ($len !== null && $len < TStringFuncFactory::create()->strlen($buf)) {
$buf = TStringFuncFactory::create()->substr($buf, 0, $len);
}
$this->wBuf_ .= $buf;
}
/**
* Writes the output buffer to the stream in the format of a 4-byte length
* followed by the actual data.
*/
public function flush()
{
if (!$this->write_ || TStringFuncFactory::create()->strlen($this->wBuf_) == 0) {
return $this->transport_->flush();
}
$out = pack('N', TStringFuncFactory::create()->strlen($this->wBuf_));
$out .= $this->wBuf_;
// Note that we clear the internal wBuf_ prior to the underlying write
// to ensure we're in a sane state (i.e. internal buffer cleaned)
// if the underlying write throws up an exception
$this->wBuf_ = '';
$this->transport_->write($out);
$this->transport_->flush();
}
}

View file

@ -0,0 +1,243 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TTransportException;
use Thrift\Factory\TStringFuncFactory;
/**
* HTTP client for Thrift
*
* @package thrift.transport
*/
class THttpClient extends TTransport
{
/**
* The host to connect to
*
* @var string
*/
protected $host_;
/**
* The port to connect on
*
* @var int
*/
protected $port_;
/**
* The URI to request
*
* @var string
*/
protected $uri_;
/**
* The scheme to use for the request, i.e. http, https
*
* @var string
*/
protected $scheme_;
/**
* Buffer for the HTTP request data
*
* @var string
*/
protected $buf_;
/**
* Input socket stream.
*
* @var resource
*/
protected $handle_;
/**
* Read timeout
*
* @var float
*/
protected $timeout_;
/**
* http headers
*
* @var array
*/
protected $headers_;
/**
* Make a new HTTP client.
*
* @param string $host
* @param int $port
* @param string $uri
*/
public function __construct($host, $port = 80, $uri = '', $scheme = 'http')
{
if ((TStringFuncFactory::create()->strlen($uri) > 0) && ($uri{0} != '/')) {
$uri = '/' . $uri;
}
$this->scheme_ = $scheme;
$this->host_ = $host;
$this->port_ = $port;
$this->uri_ = $uri;
$this->buf_ = '';
$this->handle_ = null;
$this->timeout_ = null;
$this->headers_ = array();
}
/**
* Set read timeout
*
* @param float $timeout
*/
public function setTimeoutSecs($timeout)
{
$this->timeout_ = $timeout;
}
/**
* Whether this transport is open.
*
* @return boolean true if open
*/
public function isOpen()
{
return true;
}
/**
* Open the transport for reading/writing
*
* @throws TTransportException if cannot open
*/
public function open()
{
}
/**
* Close the transport.
*/
public function close()
{
if ($this->handle_) {
@fclose($this->handle_);
$this->handle_ = null;
}
}
/**
* Read some data into the array.
*
* @param int $len How much to read
* @return string The data that has been read
* @throws TTransportException if cannot read any more data
*/
public function read($len)
{
$data = @fread($this->handle_, $len);
if ($data === false || $data === '') {
$md = stream_get_meta_data($this->handle_);
if ($md['timed_out']) {
throw new TTransportException(
'THttpClient: timed out reading ' . $len . ' bytes from ' .
$this->host_ . ':' . $this->port_ . $this->uri_,
TTransportException::TIMED_OUT
);
} else {
throw new TTransportException(
'THttpClient: Could not read ' . $len . ' bytes from ' .
$this->host_ . ':' . $this->port_ . $this->uri_,
TTransportException::UNKNOWN
);
}
}
return $data;
}
/**
* Writes some data into the pending buffer
*
* @param string $buf The data to write
* @throws TTransportException if writing fails
*/
public function write($buf)
{
$this->buf_ .= $buf;
}
/**
* Opens and sends the actual request over the HTTP connection
*
* @throws TTransportException if a writing error occurs
*/
public function flush()
{
// God, PHP really has some esoteric ways of doing simple things.
$host = $this->host_ . ($this->port_ != 80 ? ':' . $this->port_ : '');
$headers = array();
$defaultHeaders = array('Host' => $host,
'Accept' => 'application/x-thrift',
'User-Agent' => 'PHP/THttpClient',
'Content-Type' => 'application/x-thrift',
'Content-Length' => TStringFuncFactory::create()->strlen($this->buf_));
foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) {
$headers[] = "$key: $value";
}
$options = array('method' => 'POST',
'header' => implode("\r\n", $headers),
'max_redirects' => 1,
'content' => $this->buf_);
if ($this->timeout_ > 0) {
$options['timeout'] = $this->timeout_;
}
$this->buf_ = '';
$contextid = stream_context_create(array('http' => $options));
$this->handle_ = @fopen(
$this->scheme_ . '://' . $host . $this->uri_,
'r',
false,
$contextid
);
// Connect failed?
if ($this->handle_ === false) {
$this->handle_ = null;
$error = 'THttpClient: Could not connect to ' . $host . $this->uri_;
throw new TTransportException($error, TTransportException::NOT_OPEN);
}
}
public function addHeaders($headers)
{
$this->headers_ = array_merge($this->headers_, $headers);
}
}

View file

@ -0,0 +1,106 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TTransportException;
use Thrift\Factory\TStringFuncFactory;
/**
* A memory buffer is a tranpsort that simply reads from and writes to an
* in-memory string buffer. Anytime you call write on it, the data is simply
* placed into a buffer, and anytime you call read, data is read from that
* buffer.
*
* @package thrift.transport
*/
class TMemoryBuffer extends TTransport
{
/**
* Constructor. Optionally pass an initial value
* for the buffer.
*/
public function __construct($buf = '')
{
$this->buf_ = $buf;
}
protected $buf_ = '';
public function isOpen()
{
return true;
}
public function open()
{
}
public function close()
{
}
public function write($buf)
{
$this->buf_ .= $buf;
}
public function read($len)
{
$bufLength = TStringFuncFactory::create()->strlen($this->buf_);
if ($bufLength === 0) {
throw new TTransportException(
'TMemoryBuffer: Could not read ' .
$len . ' bytes from buffer.',
TTransportException::UNKNOWN
);
}
if ($bufLength <= $len) {
$ret = $this->buf_;
$this->buf_ = '';
return $ret;
}
$ret = TStringFuncFactory::create()->substr($this->buf_, 0, $len);
$this->buf_ = TStringFuncFactory::create()->substr($this->buf_, $len);
return $ret;
}
public function getBuffer()
{
return $this->buf_;
}
public function available()
{
return TStringFuncFactory::create()->strlen($this->buf_);
}
public function putBack($data)
{
$this->buf_ = $data . $this->buf_;
}
}

View file

@ -32,20 +32,25 @@ use Thrift\Exception\TTransportException;
*/
class TNullTransport extends TTransport
{
public function isOpen()
{
return true;
}
public function isOpen()
{
return true;
}
public function open() {}
public function open()
{
}
public function close() {}
public function close()
{
}
public function read($len)
{
throw new TTransportException("Can't read from TNullTransport.");
}
public function write($buf) {}
public function read($len)
{
throw new TTransportException("Can't read from TNullTransport.");
}
public function write($buf)
{
}
}

View file

@ -0,0 +1,124 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TException;
use Thrift\Factory\TStringFuncFactory;
/**
* Php stream transport. Reads to and writes from the php standard streams
* php://input and php://output
*
* @package thrift.transport
*/
class TPhpStream extends TTransport
{
const MODE_R = 1;
const MODE_W = 2;
private $inStream_ = null;
private $outStream_ = null;
private $read_ = false;
private $write_ = false;
public function __construct($mode)
{
$this->read_ = $mode & self::MODE_R;
$this->write_ = $mode & self::MODE_W;
}
public function open()
{
if ($this->read_) {
$this->inStream_ = @fopen(self::inStreamName(), 'r');
if (!is_resource($this->inStream_)) {
throw new TException('TPhpStream: Could not open php://input');
}
}
if ($this->write_) {
$this->outStream_ = @fopen('php://output', 'w');
if (!is_resource($this->outStream_)) {
throw new TException('TPhpStream: Could not open php://output');
}
}
}
public function close()
{
if ($this->read_) {
@fclose($this->inStream_);
$this->inStream_ = null;
}
if ($this->write_) {
@fclose($this->outStream_);
$this->outStream_ = null;
}
}
public function isOpen()
{
return
(!$this->read_ || is_resource($this->inStream_)) &&
(!$this->write_ || is_resource($this->outStream_));
}
public function read($len)
{
$data = @fread($this->inStream_, $len);
if ($data === false || $data === '') {
throw new TException('TPhpStream: Could not read ' . $len . ' bytes');
}
return $data;
}
public function write($buf)
{
while (TStringFuncFactory::create()->strlen($buf) > 0) {
$got = @fwrite($this->outStream_, $buf);
if ($got === 0 || $got === false) {
throw new TException(
'TPhpStream: Could not write ' . TStringFuncFactory::create()->strlen($buf) . ' bytes'
);
}
$buf = TStringFuncFactory::create()->substr($buf, $got);
}
}
public function flush()
{
@fflush($this->outStream_);
}
private static function inStreamName()
{
if (php_sapi_name() == 'cli') {
return 'php://stdin';
}
return 'php://input';
}
}

View file

@ -0,0 +1,117 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TException;
use Thrift\Exception\TTransportException;
use Thrift\Factory\TStringFuncFactory;
/**
* Sockets implementation of the TTransport interface.
*
* @package thrift.transport
*/
class TSSLSocket extends TSocket
{
/**
* Remote port
*
* @var resource
*/
protected $context_ = null;
/**
* Socket constructor
*
* @param string $host Remote hostname
* @param int $port Remote port
* @param resource $context Stream context
* @param bool $persist Whether to use a persistent socket
* @param string $debugHandler Function to call for error logging
*/
public function __construct(
$host = 'localhost',
$port = 9090,
$context = null,
$debugHandler = null
) {
$this->host_ = $this->getSSLHost($host);
$this->port_ = $port;
$this->context_ = $context;
$this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log';
}
/**
* Creates a host name with SSL transport protocol
* if no transport protocol already specified in
* the host name.
*
* @param string $host Host to listen on
* @return string $host Host name with transport protocol
*/
private function getSSLHost($host)
{
$transport_protocol_loc = strpos($host, "://");
if ($transport_protocol_loc === false) {
$host = 'ssl://' . $host;
}
return $host;
}
/**
* Connects the socket.
*/
public function open()
{
if ($this->isOpen()) {
throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN);
}
if (empty($this->host_)) {
throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN);
}
if ($this->port_ <= 0) {
throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN);
}
$this->handle_ = @stream_socket_client(
$this->host_ . ':' . $this->port_,
$errno,
$errstr,
$this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000),
STREAM_CLIENT_CONNECT,
$this->context_
);
// Connect failed?
if ($this->handle_ === false) {
$error = 'TSocket: Could not connect to ' .
$this->host_ . ':' . $this->port_ . ' (' . $errstr . ' [' . $errno . '])';
if ($this->debug_) {
call_user_func($this->debugHandler_, $error);
}
throw new TException($error);
}
}
}

View file

@ -0,0 +1,366 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TException;
use Thrift\Exception\TTransportException;
use Thrift\Factory\TStringFuncFactory;
/**
* Sockets implementation of the TTransport interface.
*
* @package thrift.transport
*/
class TSocket extends TTransport
{
/**
* Handle to PHP socket
*
* @var resource
*/
protected $handle_ = null;
/**
* Remote hostname
*
* @var string
*/
protected $host_ = 'localhost';
/**
* Remote port
*
* @var int
*/
protected $port_ = '9090';
/**
* Send timeout in seconds.
*
* Combined with sendTimeoutUsec this is used for send timeouts.
*
* @var int
*/
protected $sendTimeoutSec_ = 0;
/**
* Send timeout in microseconds.
*
* Combined with sendTimeoutSec this is used for send timeouts.
*
* @var int
*/
protected $sendTimeoutUsec_ = 100000;
/**
* Recv timeout in seconds
*
* Combined with recvTimeoutUsec this is used for recv timeouts.
*
* @var int
*/
protected $recvTimeoutSec_ = 0;
/**
* Recv timeout in microseconds
*
* Combined with recvTimeoutSec this is used for recv timeouts.
*
* @var int
*/
protected $recvTimeoutUsec_ = 750000;
/**
* Persistent socket or plain?
*
* @var bool
*/
protected $persist_ = false;
/**
* Debugging on?
*
* @var bool
*/
protected $debug_ = false;
/**
* Debug handler
*
* @var mixed
*/
protected $debugHandler_ = null;
/**
* Socket constructor
*
* @param string $host Remote hostname
* @param int $port Remote port
* @param bool $persist Whether to use a persistent socket
* @param string $debugHandler Function to call for error logging
*/
public function __construct(
$host = 'localhost',
$port = 9090,
$persist = false,
$debugHandler = null
) {
$this->host_ = $host;
$this->port_ = $port;
$this->persist_ = $persist;
$this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log';
}
/**
* @param resource $handle
* @return void
*/
public function setHandle($handle)
{
$this->handle_ = $handle;
stream_set_blocking($this->handle_, false);
}
/**
* Sets the send timeout.
*
* @param int $timeout Timeout in milliseconds.
*/
public function setSendTimeout($timeout)
{
$this->sendTimeoutSec_ = floor($timeout / 1000);
$this->sendTimeoutUsec_ =
($timeout - ($this->sendTimeoutSec_ * 1000)) * 1000;
}
/**
* Sets the receive timeout.
*
* @param int $timeout Timeout in milliseconds.
*/
public function setRecvTimeout($timeout)
{
$this->recvTimeoutSec_ = floor($timeout / 1000);
$this->recvTimeoutUsec_ =
($timeout - ($this->recvTimeoutSec_ * 1000)) * 1000;
}
/**
* Sets debugging output on or off
*
* @param bool $debug
*/
public function setDebug($debug)
{
$this->debug_ = $debug;
}
/**
* Get the host that this socket is connected to
*
* @return string host
*/
public function getHost()
{
return $this->host_;
}
/**
* Get the remote port that this socket is connected to
*
* @return int port
*/
public function getPort()
{
return $this->port_;
}
/**
* Tests whether this is open
*
* @return bool true if the socket is open
*/
public function isOpen()
{
return is_resource($this->handle_);
}
/**
* Connects the socket.
*/
public function open()
{
if ($this->isOpen()) {
throw new TTransportException('Socket already connected', TTransportException::ALREADY_OPEN);
}
if (empty($this->host_)) {
throw new TTransportException('Cannot open null host', TTransportException::NOT_OPEN);
}
if ($this->port_ <= 0) {
throw new TTransportException('Cannot open without port', TTransportException::NOT_OPEN);
}
if ($this->persist_) {
$this->handle_ = @pfsockopen(
$this->host_,
$this->port_,
$errno,
$errstr,
$this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000)
);
} else {
$this->handle_ = @fsockopen(
$this->host_,
$this->port_,
$errno,
$errstr,
$this->sendTimeoutSec_ + ($this->sendTimeoutUsec_ / 1000000)
);
}
// Connect failed?
if ($this->handle_ === false) {
$error = 'TSocket: Could not connect to ' .
$this->host_ . ':' . $this->port_ . ' (' . $errstr . ' [' . $errno . '])';
if ($this->debug_) {
call_user_func($this->debugHandler_, $error);
}
throw new TException($error);
}
if (function_exists('socket_import_stream') && function_exists('socket_set_option')) {
$socket = socket_import_stream($this->handle_);
socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1);
}
}
/**
* Closes the socket.
*/
public function close()
{
@fclose($this->handle_);
$this->handle_ = null;
}
/**
* Read from the socket at most $len bytes.
*
* This method will not wait for all the requested data, it will return as
* soon as any data is received.
*
* @param int $len Maximum number of bytes to read.
* @return string Binary data
*/
public function read($len)
{
$null = null;
$read = array($this->handle_);
$readable = @stream_select(
$read,
$null,
$null,
$this->recvTimeoutSec_,
$this->recvTimeoutUsec_
);
if ($readable > 0) {
$data = fread($this->handle_, $len);
if ($data === false) {
throw new TTransportException('TSocket: Could not read ' . $len . ' bytes from ' .
$this->host_ . ':' . $this->port_);
} elseif ($data == '' && feof($this->handle_)) {
throw new TTransportException('TSocket read 0 bytes');
}
return $data;
} elseif ($readable === 0) {
throw new TTransportException('TSocket: timed out reading ' . $len . ' bytes from ' .
$this->host_ . ':' . $this->port_);
} else {
throw new TTransportException('TSocket: Could not read ' . $len . ' bytes from ' .
$this->host_ . ':' . $this->port_);
}
}
/**
* Write to the socket.
*
* @param string $buf The data to write
*/
public function write($buf)
{
$null = null;
$write = array($this->handle_);
// keep writing until all the data has been written
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 = fwrite($this->handle_, $buf);
if ($written === -1 || $written === false) {
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 = TStringFuncFactory::create()->substr($buf, $written);
} elseif ($writable === 0) {
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 ' . TStringFuncFactory::create()->strlen($buf) . ' bytes ' .
$this->host_ . ':' . $this->port_
);
}
}
}
/**
* Flush output to the socket.
*
* Since read(), readAll() and write() operate on the sockets directly,
* this is a no-op
*
* If you wish to have flushable buffering behaviour, wrap this TSocket
* in a TBufferedTransport.
*/
public function flush()
{
// no-op
}
}

View file

@ -0,0 +1,310 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TException;
/**
* This library makes use of APC cache to make hosts as down in a web
* environment. If you are running from the CLI or on a system without APC
* installed, then these null functions will step in and act like cache
* misses.
*/
if (!function_exists('apc_fetch')) {
function apc_fetch($key)
{
return false;
}
function apc_store($key, $var, $ttl = 0)
{
return false;
}
}
/**
* Sockets implementation of the TTransport interface that allows connection
* to a pool of servers.
*
* @package thrift.transport
*/
class TSocketPool extends TSocket
{
/**
* Remote servers. Array of associative arrays with 'host' and 'port' keys
*/
private $servers_ = array();
/**
* How many times to retry each host in connect
*
* @var int
*/
private $numRetries_ = 1;
/**
* Retry interval in seconds, how long to not try a host if it has been
* marked as down.
*
* @var int
*/
private $retryInterval_ = 60;
/**
* Max consecutive failures before marking a host down.
*
* @var int
*/
private $maxConsecutiveFailures_ = 1;
/**
* Try hosts in order? or Randomized?
*
* @var bool
*/
private $randomize_ = true;
/**
* Always try last host, even if marked down?
*
* @var bool
*/
private $alwaysTryLast_ = true;
/**
* Socket pool constructor
*
* @param array $hosts List of remote hostnames
* @param mixed $ports Array of remote ports, or a single common port
* @param bool $persist Whether to use a persistent socket
* @param mixed $debugHandler Function for error logging
*/
public function __construct(
$hosts = array('localhost'),
$ports = array(9090),
$persist = false,
$debugHandler = null
) {
parent::__construct(null, 0, $persist, $debugHandler);
if (!is_array($ports)) {
$port = $ports;
$ports = array();
foreach ($hosts as $key => $val) {
$ports[$key] = $port;
}
}
foreach ($hosts as $key => $host) {
$this->servers_ [] = array('host' => $host,
'port' => $ports[$key]);
}
}
/**
* Add a server to the pool
*
* This function does not prevent you from adding a duplicate server entry.
*
* @param string $host hostname or IP
* @param int $port port
*/
public function addServer($host, $port)
{
$this->servers_[] = array('host' => $host, 'port' => $port);
}
/**
* Sets how many time to keep retrying a host in the connect function.
*
* @param int $numRetries
*/
public function setNumRetries($numRetries)
{
$this->numRetries_ = $numRetries;
}
/**
* Sets how long to wait until retrying a host if it was marked down
*
* @param int $numRetries
*/
public function setRetryInterval($retryInterval)
{
$this->retryInterval_ = $retryInterval;
}
/**
* Sets how many time to keep retrying a host before marking it as down.
*
* @param int $numRetries
*/
public function setMaxConsecutiveFailures($maxConsecutiveFailures)
{
$this->maxConsecutiveFailures_ = $maxConsecutiveFailures;
}
/**
* Turns randomization in connect order on or off.
*
* @param bool $randomize
*/
public function setRandomize($randomize)
{
$this->randomize_ = $randomize;
}
/**
* Whether to always try the last server.
*
* @param bool $alwaysTryLast
*/
public function setAlwaysTryLast($alwaysTryLast)
{
$this->alwaysTryLast_ = $alwaysTryLast;
}
/**
* Connects the socket by iterating through all the servers in the pool
* and trying to find one that works.
*/
public function open()
{
// Check if we want order randomization
if ($this->randomize_) {
shuffle($this->servers_);
}
// Count servers to identify the "last" one
$numServers = count($this->servers_);
for ($i = 0; $i < $numServers; ++$i) {
// This extracts the $host and $port variables
extract($this->servers_[$i]);
// Check APC cache for a record of this server being down
$failtimeKey = 'thrift_failtime:' . $host . ':' . $port . '~';
// Cache miss? Assume it's OK
$lastFailtime = apc_fetch($failtimeKey);
if ($lastFailtime === false) {
$lastFailtime = 0;
}
$retryIntervalPassed = false;
// Cache hit...make sure enough the retry interval has elapsed
if ($lastFailtime > 0) {
$elapsed = time() - $lastFailtime;
if ($elapsed > $this->retryInterval_) {
$retryIntervalPassed = true;
if ($this->debug_) {
call_user_func(
$this->debugHandler_,
'TSocketPool: retryInterval ' .
'(' . $this->retryInterval_ . ') ' .
'has passed for host ' . $host . ':' . $port
);
}
}
}
// Only connect if not in the middle of a fail interval, OR if this
// is the LAST server we are trying, just hammer away on it
$isLastServer = false;
if ($this->alwaysTryLast_) {
$isLastServer = ($i == ($numServers - 1));
}
if (($lastFailtime === 0) ||
($isLastServer) ||
($lastFailtime > 0 && $retryIntervalPassed)) {
// Set underlying TSocket params to this one
$this->host_ = $host;
$this->port_ = $port;
// Try up to numRetries_ connections per server
for ($attempt = 0; $attempt < $this->numRetries_; $attempt++) {
try {
// Use the underlying TSocket open function
parent::open();
// Only clear the failure counts if required to do so
if ($lastFailtime > 0) {
apc_store($failtimeKey, 0);
}
// Successful connection, return now
return;
} catch (TException $tx) {
// Connection failed
}
}
// Mark failure of this host in the cache
$consecfailsKey = 'thrift_consecfails:' . $host . ':' . $port . '~';
// Ignore cache misses
$consecfails = apc_fetch($consecfailsKey);
if ($consecfails === false) {
$consecfails = 0;
}
// Increment by one
$consecfails++;
// Log and cache this failure
if ($consecfails >= $this->maxConsecutiveFailures_) {
if ($this->debug_) {
call_user_func(
$this->debugHandler_,
'TSocketPool: marking ' . $host . ':' . $port .
' as down for ' . $this->retryInterval_ . ' secs ' .
'after ' . $consecfails . ' failed attempts.'
);
}
// Store the failure time
apc_store($failtimeKey, time());
// Clear the count of consecutive failures
apc_store($consecfailsKey, 0);
} else {
apc_store($consecfailsKey, $consecfails);
}
}
}
// Oh no; we failed them all. The system is totally ill!
$error = 'TSocketPool: All hosts in pool are down. ';
$hosts = array();
foreach ($this->servers_ as $server) {
$hosts [] = $server['host'] . ':' . $server['port'];
}
$hostlist = implode(',', $hosts);
$error .= '(' . $hostlist . ')';
if ($this->debug_) {
call_user_func($this->debugHandler_, $error);
}
throw new TException($error);
}
}

View file

@ -0,0 +1,98 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.transport
*/
namespace Thrift\Transport;
use Thrift\Exception\TTransportException;
use Thrift\Factory\TStringFuncFactory;
/**
* Base interface for a transport agent.
*
* @package thrift.transport
*/
abstract class TTransport
{
/**
* Whether this transport is open.
*
* @return boolean true if open
*/
abstract public function isOpen();
/**
* Open the transport for reading/writing
*
* @throws TTransportException if cannot open
*/
abstract public function open();
/**
* Close the transport.
*/
abstract public function close();
/**
* Read some data into the array.
*
* @param int $len How much to read
* @return string The data that has been read
* @throws TTransportException if cannot read any more data
*/
abstract public function read($len);
/**
* Guarantees that the full amount of data is read.
*
* @return string The data, of exact length
* @throws TTransportException if cannot read data
*/
public function readAll($len)
{
// return $this->read($len);
$data = '';
$got = 0;
while (($got = TStringFuncFactory::create()->strlen($data)) < $len) {
$data .= $this->read($len - $got);
}
return $data;
}
/**
* Writes the given data out.
*
* @param string $buf The data to write
* @throws TTransportException if writing fails
*/
abstract public function write($buf);
/**
* Flushes any pending data out of a buffer
*
* @throws TTransportException if a writing error occurs
*/
public function flush()
{
}
}

View file

@ -30,7 +30,9 @@ abstract class TConstant
/**
* Don't instanciate this class
*/
protected function __construct() {}
protected function __construct()
{
}
/**
* Get a constant value
@ -41,8 +43,8 @@ abstract class TConstant
{
if (is_null(static::$$constant)) {
static::$$constant = call_user_func(
sprintf('static::init_%s', $constant)
);
sprintf('static::init_%s', $constant)
);
}
return static::$$constant;

View file

@ -27,8 +27,8 @@ namespace Thrift\Type;
*/
class TMessageType
{
const CALL = 1;
const REPLY = 2;
const EXCEPTION = 3;
const ONEWAY = 4;
const CALL = 1;
const REPLY = 2;
const EXCEPTION = 3;
const ONEWAY = 4;
}

View file

@ -27,21 +27,21 @@ namespace Thrift\Type;
*/
class TType
{
const STOP = 0;
const VOID = 1;
const BOOL = 2;
const BYTE = 3;
const I08 = 3;
const DOUBLE = 4;
const I16 = 6;
const I32 = 8;
const I64 = 10;
const STRING = 11;
const UTF7 = 11;
const STRUCT = 12;
const MAP = 13;
const SET = 14;
const LST = 15; // N.B. cannot use LIST keyword in PHP!
const UTF8 = 16;
const UTF16 = 17;
const STOP = 0;
const VOID = 1;
const BOOL = 2;
const BYTE = 3;
const I08 = 3;
const DOUBLE = 4;
const I16 = 6;
const I32 = 8;
const I64 = 10;
const STRING = 11;
const UTF7 = 11;
const STRUCT = 12;
const MAP = 13;
const SET = 14;
const LST = 15; // N.B. cannot use LIST keyword in PHP!
const UTF8 = 16;
const UTF16 = 17;
}

File diff suppressed because it is too large Load diff

View file

@ -21,6 +21,7 @@
PHP_FUNCTION(thrift_protocol_write_binary);
PHP_FUNCTION(thrift_protocol_read_binary);
PHP_FUNCTION(thrift_protocol_read_binary_after_message_begin);
extern zend_module_entry thrift_protocol_module_entry;
#define phpext_thrift_protocol_ptr &thrift_protocol_module_entry

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,194 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.test
*/
namespace Test\Thrift;
use ThriftTest\Xtruct;
use ThriftTest\Xtruct2;
use ThriftTest\Numberz;
use ThriftTest\Insanity;
class Fixtures
{
public static $bufsize = 8192; //big enough to read biggest serialized Fixture arg.
public static $testArgs = array();
public static function populateTestArgs()
{
self::$testArgs['testString1'] = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, Norsk (nynorsk), Norsk (bokmål), Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
self::$testArgs['testString2'] =
"quote: \\\" backslash:" .
" forwardslash-escaped: \\/ " .
" backspace: \b formfeed: \f newline: \n return: \r tab: " .
" now-all-of-them-together: \"\\\/\b\n\r\t" .
" now-a-bunch-of-junk: !@#\$%&()(&%$#{}{}<><><";
self::$testArgs['testString3'] =
"string that ends in double-backslash \\\\";
self::$testArgs['testUnicodeStringWithNonBMP'] =
"สวัสดี/𝒯";
self::$testArgs['testDouble'] = 3.1415926535898;
// TODO: add testBinary() call
self::$testArgs['testByte'] = 0x01;
self::$testArgs['testI32'] = pow(2, 30);
if (PHP_INT_SIZE == 8) {
self::$testArgs['testI64'] = pow(2, 60);
} else {
self::$testArgs['testI64'] = "1152921504606847000";
}
self::$testArgs['testStruct'] =
new Xtruct(
array(
'string_thing' => 'worked',
'byte_thing' => 0x01,
'i32_thing' => pow(2, 30),
'i64_thing' => self::$testArgs['testI64']
)
);
self::$testArgs['testNestNested'] =
new Xtruct(
array(
'string_thing' => 'worked',
'byte_thing' => 0x01,
'i32_thing' => pow(2, 30),
'i64_thing' => self::$testArgs['testI64']
)
);
self::$testArgs['testNest'] =
new Xtruct2(
array(
'byte_thing' => 0x01,
'struct_thing' => self::$testArgs['testNestNested'],
'i32_thing' => pow(2, 15)
)
);
self::$testArgs['testMap'] =
array(
7 => 77,
8 => 88,
9 => 99
);
self::$testArgs['testStringMap'] =
array(
"a" => "123",
"a b" => "with spaces ",
"same" => "same",
"0" => "numeric key",
"longValue" => self::$testArgs['testString1'],
self::$testArgs['testString1'] => "long key"
);
self::$testArgs['testSet'] = array(1 => true, 5 => true, 6 => true);
self::$testArgs['testList'] = array(1, 2, 3);
self::$testArgs['testEnum'] = Numberz::ONE;
self::$testArgs['testTypedef'] = 69;
self::$testArgs['testMapMapExpectedResult'] =
array(
4 => array(
1 => 1,
2 => 2,
3 => 3,
4 => 4,
),
-4 => array(
-4 => -4,
-3 => -3,
-2 => -2,
-1 => -1
)
);
// testInsanity ... takes a few steps to set up!
$xtruct1 =
new Xtruct(
array(
'string_thing' => 'Goodbye4',
'byte_thing' => 4,
'i32_thing' => 4,
'i64_thing' => 4
)
);
$xtruct2 =
new Xtruct(
array(
'string_thing' => 'Hello2',
'byte_thing' => 2,
'i32_thing' => 2,
'i64_thing' => 2
)
);
$userMap =
array(
Numberz::FIVE => 5,
Numberz::EIGHT => 8
);
$insanity2 =
new Insanity(
array(
'userMap' => $userMap,
'xtructs' => array($xtruct1, $xtruct2)
)
);
$insanity3 = $insanity2;
$insanity6 =
new Insanity(
array(
'userMap' => null,
'xtructs' => null
)
);
self::$testArgs['testInsanityExpectedResult'] =
array(
"1" => array(
Numberz::TWO => $insanity2,
Numberz::THREE => $insanity3
),
"2" => array(
Numberz::SIX => $insanity6
)
);
}
}

View file

@ -0,0 +1,116 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace Test\Thrift\JsonSerialize;
use PHPUnit\Framework\TestCase;
use stdClass;
require __DIR__ . '/../../../../vendor/autoload.php';
/**
* @runTestsInSeparateProcesses
*/
class JsonSerializeTest extends TestCase
{
protected function setUp()
{
if (version_compare(phpversion(), '5.4', '<')) {
$this->markTestSkipped('Requires PHP 5.4 or newer!');
}
/** @var \Composer\Autoload\ClassLoader $loader */
$loader = require __DIR__ . '/../../../../vendor/autoload.php';
$loader->addPsr4('', __DIR__ . '/../packages/phpjs');
}
public function testEmptyStruct()
{
$empty = new \ThriftTest\EmptyStruct(array('non_existing_key' => 'bar'));
$this->assertEquals(new stdClass(), json_decode(json_encode($empty)));
}
public function testStringsAndInts()
{
$input = array(
'string_thing' => 'foo',
'i64_thing' => 1234567890,
);
$xtruct = new \ThriftTest\Xtruct($input);
// Xtruct's 'i32_thing' and 'byte_thing' fields should not be present here!
$expected = new stdClass();
$expected->string_thing = $input['string_thing'];
$expected->i64_thing = $input['i64_thing'];
$this->assertEquals($expected, json_decode(json_encode($xtruct)));
}
public function testNestedStructs()
{
$xtruct2 = new \ThriftTest\Xtruct2(array(
'byte_thing' => 42,
'struct_thing' => new \ThriftTest\Xtruct(array(
'i32_thing' => 123456,
)),
));
$expected = new stdClass();
$expected->byte_thing = $xtruct2->byte_thing;
$expected->struct_thing = new stdClass();
$expected->struct_thing->i32_thing = $xtruct2->struct_thing->i32_thing;
$this->assertEquals($expected, json_decode(json_encode($xtruct2)));
}
public function testInsanity()
{
$xinput = array('string_thing' => 'foo');
$xtruct = new \ThriftTest\Xtruct($xinput);
$insanity = new \ThriftTest\Insanity(array(
'xtructs' => array($xtruct, $xtruct, $xtruct)
));
$expected = new stdClass();
$expected->xtructs = array((object)$xinput, (object)$xinput, (object)$xinput);
$this->assertEquals($expected, json_decode(json_encode($insanity)));
}
public function testNestedLists()
{
$bonk = new \ThriftTest\Bonk(array('message' => 'foo'));
$nested = new \ThriftTest\NestedListsBonk(array('bonk' => array(array(array($bonk)))));
$expected = new stdClass();
$expected->bonk = array(array(array((object)array('message' => 'foo'))));
$this->assertEquals($expected, json_decode(json_encode($nested)));
}
public function testMaps()
{
$intmap = new \ThriftTest\ThriftTest_testMap_args(['thing' => [0 => 'zero']]);
$emptymap = new \ThriftTest\ThriftTest_testMap_args([]);
$this->assertEquals('{"thing":{"0":"zero"}}', json_encode($intmap));
$this->assertEquals('{}', json_encode($emptymap));
}
public function testScalarTypes()
{
$b = new \ThriftTest\Bools(['im_true' => '1', 'im_false' => '0']);
$this->assertEquals('{"im_true":true,"im_false":false}', json_encode($b));
$s = new \ThriftTest\StructA(['s' => 42]);
$this->assertEquals('{"s":"42"}', json_encode($s));
}
}

View file

@ -17,11 +17,11 @@
# under the License.
#
THRIFT = $(top_builddir)/compiler/cpp/thrift
PHPUNIT=php $(top_srcdir)/vendor/bin/phpunit
stubs: ../../../test/ThriftTest.thrift TestValidators.thrift
mkdir -p ./packages
$(THRIFT) --gen php -r --out ./packages ../../../test/ThriftTest.thrift
mkdir -p ./packages/php
$(THRIFT) --gen php -r --out ./packages/php ../../../test/ThriftTest.thrift
mkdir -p ./packages/phpv
mkdir -p ./packages/phpvo
mkdir -p ./packages/phpjs
@ -29,23 +29,21 @@ stubs: ../../../test/ThriftTest.thrift TestValidators.thrift
$(THRIFT) --gen php:validate,oop -r --out ./packages/phpvo TestValidators.thrift
$(THRIFT) --gen php:json -r --out ./packages/phpjs TestValidators.thrift
check-json-serializer: stubs
if HAVE_PHPUNIT
$(PHPUNIT) --log-junit=TEST-json-serializer.xml Test/Thrift/JsonSerialize/
endif
deps: $(top_srcdir)/composer.json
composer install --working-dir=$(top_srcdir)
check-validator: stubs
php Test/Thrift/TestValidators.php
php Test/Thrift/TestValidators.php -oop
all-local: deps
check-protocol: stubs
if HAVE_PHPUNIT
$(PHPUNIT) --log-junit=TEST-log-json-protocol.xml Test/Thrift/Protocol/TestTJSONProtocol.php
$(PHPUNIT) --log-junit=TEST-binary-serializer.xml Test/Thrift/Protocol/TestBinarySerializer.php
$(PHPUNIT) --log-junit=TEST-log-simple-json-protocol.xml Test/Thrift/Protocol/TestTSimpleJSONProtocol.php
endif
check-json-serializer: deps stubs
$(PHPUNIT) --log-junit=TEST-log-json-serializer.xml JsonSerialize/
check: stubs \
check-validator: deps stubs
$(PHPUNIT) --log-junit=TEST-log-validator.xml Validator/
check-protocol: deps stubs
$(PHPUNIT) --log-junit=TEST-log-protocol.xml Protocol/
check: deps stubs \
check-protocol \
check-validator \
check-json-serializer
@ -53,9 +51,3 @@ check: stubs \
clean-local:
$(RM) -r ./packages
$(RM) TEST-*.xml
EXTRA_DIST = \
Test \
TestValidators.thrift

View file

@ -23,16 +23,10 @@
namespace Test\Thrift\Protocol;
use Thrift\ClassLoader\ThriftClassLoader;
use PHPUnit\Framework\TestCase;
use Thrift\Serializer\TBinarySerializer;
require_once __DIR__.'/../../../../lib/Thrift/ClassLoader/ThriftClassLoader.php';
$loader = new ThriftClassLoader();
$loader->registerNamespace('Thrift', __DIR__ . '/../../../../lib');
$loader->registerNamespace('Test', __DIR__ . '/../../..');
$loader->registerDefinition('ThriftTest', __DIR__ . '/../../../packages');
$loader->register();
require __DIR__ . '/../../../../vendor/autoload.php';
/***
* This test suite depends on running the compiler against the
@ -40,25 +34,27 @@ $loader->register();
*
* lib/php/test$ ../../../compiler/cpp/thrift --gen php -r \
* --out ./packages ../../../test/ThriftTest.thrift
*
* @runTestsInSeparateProcesses
*/
class TestBinarySerializer extends \PHPUnit_Framework_TestCase
class BinarySerializerTest extends TestCase
{
public function setUp()
{
/** @var \Composer\Autoload\ClassLoader $loader */
$loader = require __DIR__ . '/../../../../vendor/autoload.php';
$loader->addPsr4('', __DIR__ . '/../packages/php');
}
public function setUp()
{
}
/**
* We try to serialize and deserialize a random object to make sure no exceptions are thrown.
* @see THRIFT-1579
*/
public function testBinarySerializer()
{
$struct = new \ThriftTest\Xtruct(array('string_thing' => 'abc'));
$serialized = TBinarySerializer::serialize($struct, 'ThriftTest\\Xtruct');
$deserialized = TBinarySerializer::deserialize($serialized, 'ThriftTest\\Xtruct');
$this->assertEquals($struct, $deserialized);
}
/**
* We try to serialize and deserialize a random object to make sure no exceptions are thrown.
* @see THRIFT-1579
*/
public function testBinarySerializer()
{
$struct = new \ThriftTest\Xtruct(array('string_thing' => 'abc'));
$serialized = TBinarySerializer::serialize($struct, 'ThriftTest\\Xtruct');
$deserialized = TBinarySerializer::deserialize($serialized, 'ThriftTest\\Xtruct');
$this->assertEquals($struct, $deserialized);
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,518 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.test
*/
namespace Test\Thrift\Protocol;
use PHPUnit\Framework\TestCase;
use Test\Thrift\Fixtures;
use Thrift\Protocol\TJSONProtocol;
use Thrift\Transport\TMemoryBuffer;
require __DIR__ . '/../../../../vendor/autoload.php';
/***
* This test suite depends on running the compiler against the
* standard ThriftTest.thrift file:
*
* lib/php/test$ ../../../compiler/cpp/thrift --gen php -r \
* --out ./packages ../../../test/ThriftTest.thrift
*
* @runTestsInSeparateProcesses
*/
class TJSONProtocolTest extends TestCase
{
private $transport;
private $protocol;
public static function setUpBeforeClass()
{
/** @var \Composer\Autoload\ClassLoader $loader */
$loader = require __DIR__ . '/../../../../vendor/autoload.php';
$loader->addPsr4('', __DIR__ . '/../packages/php');
Fixtures::populateTestArgs();
TJSONProtocolFixtures::populateTestArgsJSON();
}
public function setUp()
{
$this->transport = new TMemoryBuffer();
$this->protocol = new TJSONProtocol($this->transport);
$this->transport->open();
}
/**
* WRITE TESTS
*/
public function testVoidWrite()
{
$args = new \ThriftTest\ThriftTest_testVoid_args();
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testVoid'];
$this->assertEquals($expected, $actual);
}
public function testString1Write()
{
$args = new \ThriftTest\ThriftTest_testString_args();
$args->thing = Fixtures::$testArgs['testString1'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testString1'];
$this->assertEquals($expected, $actual);
}
public function testString2Write()
{
$args = new \ThriftTest\ThriftTest_testString_args();
$args->thing = Fixtures::$testArgs['testString2'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testString2'];
$this->assertEquals($expected, $actual);
}
public function testDoubleWrite()
{
$args = new \ThriftTest\ThriftTest_testDouble_args();
$args->thing = Fixtures::$testArgs['testDouble'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testDouble'];
$this->assertEquals($expected, $actual);
}
public function testByteWrite()
{
$args = new \ThriftTest\ThriftTest_testByte_args();
$args->thing = Fixtures::$testArgs['testByte'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testByte'];
$this->assertEquals($expected, $actual);
}
public function testI32Write()
{
$args = new \ThriftTest\ThriftTest_testI32_args();
$args->thing = Fixtures::$testArgs['testI32'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testI32'];
$this->assertEquals($expected, $actual);
}
public function testI64Write()
{
$args = new \ThriftTest\ThriftTest_testI64_args();
$args->thing = Fixtures::$testArgs['testI64'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testI64'];
$this->assertEquals($expected, $actual);
}
public function testStructWrite()
{
$args = new \ThriftTest\ThriftTest_testStruct_args();
$args->thing = Fixtures::$testArgs['testStruct'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testStruct'];
$this->assertEquals($expected, $actual);
}
public function testNestWrite()
{
$args = new \ThriftTest\ThriftTest_testNest_args();
$args->thing = Fixtures::$testArgs['testNest'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testNest'];
$this->assertEquals($expected, $actual);
}
public function testMapWrite()
{
$args = new \ThriftTest\ThriftTest_testMap_args();
$args->thing = Fixtures::$testArgs['testMap'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testMap'];
$this->assertEquals($expected, $actual);
}
public function testStringMapWrite()
{
$args = new \ThriftTest\ThriftTest_testStringMap_args();
$args->thing = Fixtures::$testArgs['testStringMap'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testStringMap'];
/*
* The $actual returns unescaped string.
* It is required to to decode then encode it again
* to get the expected escaped unicode.
*/
$this->assertEquals($expected, json_encode(json_decode($actual)));
}
public function testSetWrite()
{
$args = new \ThriftTest\ThriftTest_testSet_args();
$args->thing = Fixtures::$testArgs['testSet'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testSet'];
$this->assertEquals($expected, $actual);
}
public function testListWrite()
{
$args = new \ThriftTest\ThriftTest_testList_args();
$args->thing = Fixtures::$testArgs['testList'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testList'];
$this->assertEquals($expected, $actual);
}
public function testEnumWrite()
{
$args = new \ThriftTest\ThriftTest_testEnum_args();
$args->thing = Fixtures::$testArgs['testEnum'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testEnum'];
$this->assertEquals($expected, $actual);
}
public function testTypedefWrite()
{
$args = new \ThriftTest\ThriftTest_testTypedef_args();
$args->thing = Fixtures::$testArgs['testTypedef'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testTypedef'];
$this->assertEquals($expected, $actual);
}
/**
* READ TESTS
*/
public function testVoidRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testVoid']
);
$args = new \ThriftTest\ThriftTest_testVoid_args();
$args->read($this->protocol);
}
public function testString1Read()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testString1']
);
$args = new \ThriftTest\ThriftTest_testString_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testString1'];
$this->assertEquals($expected, $actual);
}
public function testString2Read()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testString2']
);
$args = new \ThriftTest\ThriftTest_testString_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testString2'];
$this->assertEquals($expected, $actual);
}
public function testString3Write()
{
$args = new \ThriftTest\ThriftTest_testString_args();
$args->thing = Fixtures::$testArgs['testString3'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testString3'];
$this->assertEquals($expected, $actual);
}
public function testString4Write()
{
$args = new \ThriftTest\ThriftTest_testString_args();
$args->thing = Fixtures::$testArgs['testUnicodeStringWithNonBMP'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TJSONProtocolFixtures::$testArgsJSON['testUnicodeStringWithNonBMP'];
$this->assertEquals($expected, $actual);
}
public function testDoubleRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testDouble']
);
$args = new \ThriftTest\ThriftTest_testDouble_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testDouble'];
$this->assertEquals($expected, $actual);
}
public function testByteRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testByte']
);
$args = new \ThriftTest\ThriftTest_testByte_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testByte'];
$this->assertEquals($expected, $actual);
}
public function testI32Read()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testI32']
);
$args = new \ThriftTest\ThriftTest_testI32_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testI32'];
$this->assertEquals($expected, $actual);
}
public function testI64Read()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testI64']
);
$args = new \ThriftTest\ThriftTest_testI64_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testI64'];
$this->assertEquals($expected, $actual);
}
public function testStructRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testStruct']
);
$args = new \ThriftTest\ThriftTest_testStruct_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testStruct'];
$this->assertEquals($expected, $actual);
}
public function testNestRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testNest']
);
$args = new \ThriftTest\ThriftTest_testNest_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testNest'];
$this->assertEquals($expected, $actual);
}
public function testMapRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testMap']
);
$args = new \ThriftTest\ThriftTest_testMap_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testMap'];
$this->assertEquals($expected, $actual);
}
public function testStringMapRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testStringMap']
);
$args = new \ThriftTest\ThriftTest_testStringMap_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testStringMap'];
$this->assertEquals($expected, $actual);
}
public function testSetRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testSet']
);
$args = new \ThriftTest\ThriftTest_testSet_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testSet'];
$this->assertEquals($expected, $actual);
}
public function testListRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testList']
);
$args = new \ThriftTest\ThriftTest_testList_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testList'];
$this->assertEquals($expected, $actual);
}
public function testEnumRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testEnum']
);
$args = new \ThriftTest\ThriftTest_testEnum_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testEnum'];
$this->assertEquals($expected, $actual);
}
public function testTypedefRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testTypedef']
);
$args = new \ThriftTest\ThriftTest_testTypedef_args();
$args->read($this->protocol);
$actual = $args->thing;
$expected = Fixtures::$testArgs['testTypedef'];
$this->assertEquals($expected, $actual);
}
public function testMapMapRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testMapMap']
);
$result = new \ThriftTest\ThriftTest_testMapMap_result();
$result->read($this->protocol);
$actual = $result->success;
$expected = Fixtures::$testArgs['testMapMapExpectedResult'];
$this->assertEquals($expected, $actual);
}
public function testInsanityRead()
{
$this->transport->write(
TJSONProtocolFixtures::$testArgsJSON['testInsanity']
);
$result = new \ThriftTest\ThriftTest_testInsanity_result();
$result->read($this->protocol);
$actual = $result->success;
$expected = Fixtures::$testArgs['testInsanityExpectedResult'];
$this->assertEquals($expected, $actual);
}
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,254 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.test
*/
namespace Test\Thrift\Protocol;
use PHPUnit\Framework\TestCase;
use Test\Thrift\Fixtures;
use Thrift\Protocol\TSimpleJSONProtocol;
use Thrift\Transport\TMemoryBuffer;
require __DIR__ . '/../../../../vendor/autoload.php';
/***
* This test suite depends on running the compiler against the
* standard ThriftTest.thrift file:
*
* lib/php/test$ ../../../compiler/cpp/thrift --gen php -r \
* --out ./packages ../../../test/ThriftTest.thrift
*
* @runTestsInSeparateProcesses
*/
class TSimpleJSONProtocolTest extends TestCase
{
private $transport;
private $protocol;
public static function setUpBeforeClass()
{
/** @var \Composer\Autoload\ClassLoader $loader */
$loader = require __DIR__ . '/../../../../vendor/autoload.php';
$loader->addPsr4('', __DIR__ . '/../packages/php');
Fixtures::populateTestArgs();
TSimpleJSONProtocolFixtures::populateTestArgsSimpleJSON();
}
public function setUp()
{
$this->transport = new TMemoryBuffer();
$this->protocol = new TSimpleJSONProtocol($this->transport);
$this->transport->open();
}
/**
* WRITE TESTS
*/
public function testVoidWrite()
{
$args = new \ThriftTest\ThriftTest_testVoid_args();
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testVoid'];
$this->assertEquals($expected, $actual);
}
public function testString1Write()
{
$args = new \ThriftTest\ThriftTest_testString_args();
$args->thing = Fixtures::$testArgs['testString1'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testString1'];
$this->assertEquals($expected, $actual);
}
public function testString2Write()
{
$args = new \ThriftTest\ThriftTest_testString_args();
$args->thing = Fixtures::$testArgs['testString2'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testString2'];
$this->assertEquals($expected, $actual);
}
public function testDoubleWrite()
{
$args = new \ThriftTest\ThriftTest_testDouble_args();
$args->thing = Fixtures::$testArgs['testDouble'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testDouble'];
$this->assertEquals($expected, $actual);
}
public function testByteWrite()
{
$args = new \ThriftTest\ThriftTest_testByte_args();
$args->thing = Fixtures::$testArgs['testByte'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testByte'];
$this->assertEquals($expected, $actual);
}
public function testI32Write()
{
$args = new \ThriftTest\ThriftTest_testI32_args();
$args->thing = Fixtures::$testArgs['testI32'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testI32'];
$this->assertEquals($expected, $actual);
}
public function testI64Write()
{
$args = new \ThriftTest\ThriftTest_testI64_args();
$args->thing = Fixtures::$testArgs['testI64'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testI64'];
$this->assertEquals($expected, $actual);
}
public function testStructWrite()
{
$args = new \ThriftTest\ThriftTest_testStruct_args();
$args->thing = Fixtures::$testArgs['testStruct'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testStruct'];
$this->assertEquals($expected, $actual);
}
public function testNestWrite()
{
$args = new \ThriftTest\ThriftTest_testNest_args();
$args->thing = Fixtures::$testArgs['testNest'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testNest'];
$this->assertEquals($expected, $actual);
}
public function testMapWrite()
{
$args = new \ThriftTest\ThriftTest_testMap_args();
$args->thing = Fixtures::$testArgs['testMap'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testMap'];
$this->assertEquals($expected, $actual);
}
public function testStringMapWrite()
{
$args = new \ThriftTest\ThriftTest_testStringMap_args();
$args->thing = Fixtures::$testArgs['testStringMap'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testStringMap'];
$this->assertEquals($expected, $actual);
}
public function testSetWrite()
{
$args = new \ThriftTest\ThriftTest_testSet_args();
$args->thing = Fixtures::$testArgs['testSet'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testSet'];
$this->assertEquals($expected, $actual);
}
public function testListWrite()
{
$args = new \ThriftTest\ThriftTest_testList_args();
$args->thing = Fixtures::$testArgs['testList'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testList'];
$this->assertEquals($expected, $actual);
}
public function testEnumWrite()
{
$args = new \ThriftTest\ThriftTest_testEnum_args();
$args->thing = Fixtures::$testArgs['testEnum'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testEnum'];
$this->assertEquals($expected, $actual);
}
public function testTypedefWrite()
{
$args = new \ThriftTest\ThriftTest_testTypedef_args();
$args->thing = Fixtures::$testArgs['testTypedef'];
$args->write($this->protocol);
$actual = $this->transport->read(Fixtures::$bufsize);
$expected = TSimpleJSONProtocolFixtures::$testArgsJSON['testTypedef'];
$this->assertEquals($expected, $actual);
}
}

View file

@ -1,194 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @package thrift.test
*/
namespace Test\Thrift;
use ThriftTest\Xtruct;
use ThriftTest\Xtruct2;
use ThriftTest\Numberz;
use ThriftTest\Insanity;
class Fixtures
{
public static $testArgs = array();
public static function populateTestArgs()
{
self::$testArgs['testString1'] = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, Norsk (nynorsk), Norsk (bokmål), Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
self::$testArgs['testString2'] =
"quote: \\\" backslash:" .
" forwardslash-escaped: \\/ " .
" backspace: \b formfeed: \f newline: \n return: \r tab: " .
" now-all-of-them-together: \"\\\/\b\n\r\t" .
" now-a-bunch-of-junk: !@#\$%&()(&%$#{}{}<><><";
self::$testArgs['testString3'] =
"string that ends in double-backslash \\\\";
self::$testArgs['testUnicodeStringWithNonBMP'] =
"สวัสดี/𝒯";
self::$testArgs['testDouble'] = 3.1415926535898;
// TODO: add testBinary() call
self::$testArgs['testByte'] = 0x01;
self::$testArgs['testI32'] = pow( 2, 30 );
if (PHP_INT_SIZE == 8) {
self::$testArgs['testI64'] = pow( 2, 60 );
} else {
self::$testArgs['testI64'] = "1152921504606847000";
}
self::$testArgs['testStruct'] =
new Xtruct(
array(
'string_thing' => 'worked',
'byte_thing' => 0x01,
'i32_thing' => pow( 2, 30 ),
'i64_thing' => self::$testArgs['testI64']
)
);
self::$testArgs['testNestNested'] =
new Xtruct(
array(
'string_thing' => 'worked',
'byte_thing' => 0x01,
'i32_thing' => pow( 2, 30 ),
'i64_thing' => self::$testArgs['testI64']
)
);
self::$testArgs['testNest'] =
new Xtruct2(
array(
'byte_thing' => 0x01,
'struct_thing' => self::$testArgs['testNestNested'],
'i32_thing' => pow( 2, 15 )
)
);
self::$testArgs['testMap'] =
array(
7 => 77,
8 => 88,
9 => 99
);
self::$testArgs['testStringMap'] =
array(
"a" => "123",
"a b" => "with spaces ",
"same" => "same",
"0" => "numeric key",
"longValue" => self::$testArgs['testString1'],
self::$testArgs['testString1'] => "long key"
);
self::$testArgs['testSet'] = array( 1 => true, 5 => true, 6 => true );
self::$testArgs['testList'] = array( 1, 2, 3 );
self::$testArgs['testEnum'] = Numberz::ONE;
self::$testArgs['testTypedef'] = 69;
self::$testArgs['testMapMapExpectedResult'] =
array(
4 => array(
1 => 1,
2 => 2,
3 => 3,
4 => 4,
),
-4 => array(
-4 => -4,
-3 => -3,
-2 => -2,
-1 => -1
)
);
// testInsanity ... takes a few steps to set up!
$xtruct1 =
new Xtruct(
array(
'string_thing' => 'Goodbye4',
'byte_thing' => 4,
'i32_thing' => 4,
'i64_thing' => 4
)
);
$xtruct2 =
new Xtruct(
array(
'string_thing' => 'Hello2',
'byte_thing' =>2,
'i32_thing' => 2,
'i64_thing' => 2
)
);
$userMap =
array(
Numberz::FIVE => 5,
Numberz::EIGHT => 8
);
$insanity2 =
new Insanity(
array(
'userMap' => $userMap,
'xtructs' => array($xtruct1,$xtruct2)
)
);
$insanity3 = $insanity2;
$insanity6 =
new Insanity(
array(
'userMap' => null,
'xtructs' => null
)
);
self::$testArgs['testInsanityExpectedResult'] =
array(
"1" => array(
Numberz::TWO => $insanity2,
Numberz::THREE => $insanity3
),
"2" => array(
Numberz::SIX => $insanity6
)
);
}
}

View file

@ -1,116 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace Test\Thrift\JsonSerialize;
use stdClass;
use Thrift\ClassLoader\ThriftClassLoader;
require_once __DIR__.'/../../../../lib/Thrift/ClassLoader/ThriftClassLoader.php';
$loader = new ThriftClassLoader();
$loader->registerNamespace('Thrift', __DIR__ . '/../../../../lib');
$loader->registerNamespace('Test', __DIR__ . '/../../..');
$loader->registerDefinition('ThriftTest', __DIR__ . '/../../../packages/phpjs');
$loader->register();
class JsonSerializeTest extends \PHPUnit_Framework_TestCase
{
protected function setUp() {
if (version_compare(phpversion(), '5.4', '<')) {
$this->markTestSkipped('Requires PHP 5.4 or newer!');
}
}
public function testEmptyStruct()
{
$empty = new \ThriftTest\EmptyStruct(array('non_existing_key' => 'bar'));
$this->assertEquals(new stdClass(), json_decode(json_encode($empty)));
}
public function testStringsAndInts()
{
$input = array(
'string_thing' => 'foo',
'i64_thing' => 1234567890,
);
$xtruct = new \ThriftTest\Xtruct($input);
// Xtruct's 'i32_thing' and 'byte_thing' fields should not be present here!
$expected = new stdClass();
$expected->string_thing = $input['string_thing'];
$expected->i64_thing = $input['i64_thing'];
$this->assertEquals($expected, json_decode(json_encode($xtruct)));
}
public function testNestedStructs()
{
$xtruct2 = new \ThriftTest\Xtruct2(array(
'byte_thing' => 42,
'struct_thing' => new \ThriftTest\Xtruct(array(
'i32_thing' => 123456,
)),
));
$expected = new stdClass();
$expected->byte_thing = $xtruct2->byte_thing;
$expected->struct_thing = new stdClass();
$expected->struct_thing->i32_thing = $xtruct2->struct_thing->i32_thing;
$this->assertEquals($expected, json_decode(json_encode($xtruct2)));
}
public function testInsanity()
{
$xinput = array('string_thing' => 'foo');
$xtruct = new \ThriftTest\Xtruct($xinput);
$insanity = new \ThriftTest\Insanity(array(
'xtructs' => array($xtruct, $xtruct, $xtruct)
));
$expected = new stdClass();
$expected->xtructs = array((object) $xinput, (object) $xinput, (object) $xinput);
$this->assertEquals($expected, json_decode(json_encode($insanity)));
}
public function testNestedLists()
{
$bonk = new \ThriftTest\Bonk(array('message' => 'foo'));
$nested = new \ThriftTest\NestedListsBonk(array('bonk' => array(array(array($bonk)))));
$expected = new stdClass();
$expected->bonk = array(array(array((object) array('message' => 'foo'))));
$this->assertEquals($expected, json_decode(json_encode($nested)));
}
public function testMaps()
{
$intmap = new \ThriftTest\ThriftTest_testMap_args(['thing' => [0 => 'zero']]);
$emptymap = new \ThriftTest\ThriftTest_testMap_args([]);
$this->assertEquals('{"thing":{"0":"zero"}}', json_encode($intmap));
$this->assertEquals('{}', json_encode($emptymap));
}
public function testScalarTypes()
{
$b = new \ThriftTest\Bools(['im_true' => '1', 'im_false' => '0']);
$this->assertEquals('{"im_true":true,"im_false":false}', json_encode($b));
$s = new \ThriftTest\StructA(['s' => 42]);
$this->assertEquals('{"s":"42"}', json_encode($s));
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,156 +0,0 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace test\php;
require_once __DIR__.'/../../../lib/Thrift/ClassLoader/ThriftClassLoader.php';
use Thrift\ClassLoader\ThriftClassLoader;
use Thrift\Exception\TProtocolException;
use Thrift\Protocol\TBinaryProtocol;
use Thrift\Transport\TMemoryBuffer;
$oop_mode = (isset($argv[1]) && $argv[1] === '-oop');
$GEN_DIR = $oop_mode ? 'phpvo' : 'phpv';
$loader = new ThriftClassLoader();
$loader->registerNamespace('Thrift', __DIR__ . '/../../../lib');
$loader->registerDefinition('ThriftTest', __DIR__ . '/../../packages/' . $GEN_DIR);
$loader->registerDefinition('TestValidators', __DIR__ . '/../../packages/' . $GEN_DIR);
$loader->register();
// Would be nice to have PHPUnit here, but for now just hack it.
set_exception_handler(function ($e) {
my_assert(false, "Unexpected exception caught: " . $e->getMessage());
});
set_error_handler(function ($errno, $errmsg) {
my_assert(false, "Unexpected PHP error: " . $errmsg);
});
// Empty structs should not have validators
assert_has_no_read_validator('ThriftTest\EmptyStruct');
assert_has_no_write_validator('ThriftTest\EmptyStruct');
// Bonk has only opt_in_req_out fields
{
assert_has_no_read_validator('ThriftTest\Bonk');
assert_has_a_write_validator('ThriftTest\Bonk');
{
// Check that we can read an empty object
$bonk = new \ThriftTest\Bonk();
$transport = new TMemoryBuffer("\000");
$protocol = new TBinaryProtocol($transport);
$bonk->read($protocol);
}
{
// ...but not write an empty object
$bonk = new \ThriftTest\Bonk();
$transport = new TMemoryBuffer();
$protocol = new TBinaryProtocol($transport);
assert_protocol_exception_thrown(function () use ($bonk, $protocol) { $bonk->write($protocol); },
'Bonk was able to write an empty object');
}
}
// StructA has a single required field
{
assert_has_a_read_validator('ThriftTest\StructA');
assert_has_a_write_validator('ThriftTest\StructA');
{
// Check that we are not able to write StructA with a missing required field
$structa = new \ThriftTest\StructA();
$transport = new TMemoryBuffer();
$protocol = new TBinaryProtocol($transport);
assert_protocol_exception_thrown(function () use ($structa, $protocol) { $structa->write($protocol); },
'StructA was able to write an empty object');
}
{
// Check that we are able to read and write a message with a good StructA
$transport = new TMemoryBuffer(base64_decode('CwABAAAAA2FiYwA='));
$protocol = new TBinaryProtocol($transport);
$structa = new \ThriftTest\StructA();
$structa->read($protocol);
$structa->write($protocol);
}
}
// Unions should not get write validators
assert_has_no_write_validator('TestValidators\UnionOfStrings');
// Service _result classes should not get any validators
assert_has_no_read_validator('TestValidators\TestService_test_result');
assert_has_no_write_validator('TestValidators\TestService_test_result');
function assert_has_a_read_validator($class)
{
my_assert(has_read_validator_method($class),
$class . ' class should have a read validator');
}
function assert_has_no_read_validator($class)
{
my_assert(!has_read_validator_method($class),
$class . ' class should not have a read validator');
}
function assert_has_a_write_validator($class)
{
my_assert(has_write_validator_method($class),
$class . ' class should have a write validator');
}
function assert_has_no_write_validator($class)
{
my_assert(!has_write_validator_method($class),
$class . ' class should not have a write validator');
}
function assert_protocol_exception_thrown($callable, $message)
{
try {
call_user_func($callable);
my_assert(false, $message);
} catch (TProtocolException $e) {
}
}
function has_write_validator_method($class)
{
$rc = new \ReflectionClass($class);
return $rc->hasMethod('_validateForWrite');
}
function has_read_validator_method($class)
{
$rc = new \ReflectionClass($class);
return $rc->hasMethod('_validateForRead');
}
function my_assert($something, $message)
{
if (!$something) {
fwrite(STDERR, basename(__FILE__) . " FAILED: $message\n");
exit(1);
}
}

View file

@ -0,0 +1,154 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
namespace Test\Thrift;
use PHPUnit\Framework\TestCase;
use Thrift\Exception\TProtocolException;
use Thrift\Protocol\TBinaryProtocol;
use Thrift\Transport\TMemoryBuffer;
abstract class BaseValidatorTest extends TestCase
{
public function testEmptyStructValidator()
{
$this->assertNoReadValidator('ThriftTest\EmptyStruct');
$this->assertNoWriteValidator('ThriftTest\EmptyStruct');
}
public function testBonkValidator()
{
$this->assertNoReadValidator('ThriftTest\Bonk');
$this->assertHasWriteValidator('ThriftTest\Bonk');
}
public function testStructAValidator()
{
$this->assertHasReadValidator('ThriftTest\StructA');
$this->assertHasWriteValidator('ThriftTest\StructA');
}
public function testUnionOfStringsValidator()
{
$this->assertNoWriteValidator('TestValidators\UnionOfStrings');
}
public function testServiceResultValidator()
{
$this->assertNoReadValidator('TestValidators\TestService_test_result');
$this->assertNoWriteValidator('TestValidators\TestService_test_result');
}
public function testReadEmpty()
{
$bonk = new \ThriftTest\Bonk();
$transport = new TMemoryBuffer("\000");
$protocol = new TBinaryProtocol($transport);
$bonk->read($protocol);
}
public function testWriteEmpty()
{
$bonk = new \ThriftTest\Bonk();
$transport = new TMemoryBuffer();
$protocol = new TBinaryProtocol($transport);
try {
$bonk->write($protocol);
$this->fail('Bonk was able to write an empty object');
} catch (TProtocolException $e) {
}
}
public function testWriteWithMissingRequired()
{
// Check that we are not able to write StructA with a missing required field
$structa = new \ThriftTest\StructA();
$transport = new TMemoryBuffer();
$protocol = new TBinaryProtocol($transport);
try {
$structa->write($protocol);
$this->fail('StructA was able to write an empty object');
} catch (TProtocolException $e) {
}
}
public function testReadStructA()
{
$transport = new TMemoryBuffer(base64_decode('CwABAAAAA2FiYwA='));
$protocol = new TBinaryProtocol($transport);
$structa = new \ThriftTest\StructA();
$structa->read($protocol);
$this->assertEquals("abc", $structa->s);
}
public function testWriteStructA()
{
$transport = new TMemoryBuffer();
$protocol = new TBinaryProtocol($transport);
$structa = new \ThriftTest\StructA();
$structa->s = "abc";
$structa->write($protocol);
$writeResult = base64_encode($transport->getBuffer());
$this->assertEquals('CwABAAAAA2FiYwA=', $writeResult);
}
protected static function assertHasReadValidator($class)
{
if (!static::hasReadValidator($class)) {
static::fail($class . ' class should have a read validator');
}
}
protected static function assertNoReadValidator($class)
{
if (static::hasReadValidator($class)) {
static::fail($class . ' class should not have a write validator');
}
}
protected static function assertHasWriteValidator($class)
{
if (!static::hasWriteValidator($class)) {
static::fail($class . ' class should have a write validator');
}
}
protected static function assertNoWriteValidator($class)
{
if (static::hasWriteValidator($class)) {
static::fail($class . ' class should not have a write validator');
}
}
private static function hasReadValidator($class)
{
$rc = new \ReflectionClass($class);
return $rc->hasMethod('_validateForRead');
}
private static function hasWriteValidator($class)
{
$rc = new \ReflectionClass($class);
return $rc->hasMethod('_validateForWrite');
}
}

Some files were not shown because too many files have changed in this diff Show more