Moving from govendor to dep, updated dependencies (#48)

* Moving from govendor to dep.

* Making the pull request template more friendly.

* Fixing akward space in PR template.

* goimports run on whole project using ` goimports -w $(find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./gen-go/*")`

source of command: https://gist.github.com/bgentry/fd1ffef7dbde01857f66
This commit is contained in:
Renan DelValle 2018-01-07 13:13:47 -08:00 committed by GitHub
parent 9631aa3aab
commit 8d445c1c77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2186 changed files with 400410 additions and 352 deletions

View file

@ -0,0 +1,380 @@
<?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

@ -0,0 +1,210 @@
<?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.
*
* ClassLoader to load Thrift library and definitions
* Inspired from UniversalClassLoader from Symfony 2
*
* @package thrift.classloader
*/
namespace Thrift\ClassLoader;
class ThriftClassLoader
{
/**
* Namespaces path
* @var array
*/
protected $namespaces = array();
/**
* Thrift definition paths
* @var type
*/
protected $definitions = array();
/**
* Do we use APC cache ?
* @var boolean
*/
protected $apc = false;
/**
* APC Cache prefix
* @var string
*/
protected $apc_prefix;
/**
* Set autoloader to use APC cache
* @param boolean $apc
* @param string $apc_prefix
*/
public function __construct($apc = false, $apc_prefix = null)
{
$this->apc = $apc;
$this->apc_prefix = $apc_prefix;
}
/**
* Registers a 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;
}
/**
* Registers a Thrift 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;
}
/**
* Registers this instance as an autoloader.
*
* @param Boolean $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Loads the given class, definition or interface.
*
* @param string $class The name of the class
*/
public function loadClass($class)
{
if (
(true === $this->apc && ($file = $this->findFileInApc($class))) or
($file = $this->findFile($class))
)
{
require_once $file;
}
}
/**
* Loads the given class or interface in APC.
* @param string $class The name of the class
* @return string
*/
protected function findFileInApc($class)
{
if (false === $file = apc_fetch($this->apc_prefix.$class)) {
apc_store($this->apc_prefix.$class, $file = $this->findFile($class));
}
return $file;
}
/**
* Find class in namespaces or definitions directories
* @param string $class
* @return string
*/
public function findFile($class)
{
// Remove first backslash
if ('\\' == $class[0]) {
$class = substr($class, 1);
}
if (false !== $pos = strrpos($class, '\\')) {
// Namespaced class name
$namespace = substr($class, 0, $pos);
// Iterate in normal namespaces
foreach ($this->namespaces as $ns => $dirs) {
//Don't interfere with other autoloaders
if (0 !== strpos($namespace, $ns)) {
continue;
}
foreach ($dirs as $dir) {
$className = substr($class, $pos + 1);
$file = $dir.DIRECTORY_SEPARATOR.
str_replace('\\', DIRECTORY_SEPARATOR, $namespace).
DIRECTORY_SEPARATOR.
$className.'.php';
if (file_exists($file)) {
return $file;
}
}
}
// Iterate in Thrift namespaces
// Remove first part of namespace
$m = explode('\\', $class);
// Ignore wrong call
if (count($m) <= 1) {
return;
}
$class = array_pop($m);
$namespace = implode('\\', $m);
foreach ($this->definitions as $ns => $dirs) {
//Don't interfere with other autoloaders
if (0 !== strpos($namespace, $ns)) {
continue;
}
foreach ($dirs as $dir) {
/**
* Available in service: Interface, Client, Processor, Rest
* And every service methods (_.+)
*/
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';
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 $_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,383 @@
<?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

@ -0,0 +1,50 @@
<?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\Exception;
/**
* Protocol module. Contains all the types and definitions needed to implement
* a protocol encoder/decoder.
*
* @package thrift.protocol
*/
/**
* Protocol exceptions
*/
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;
public function __construct($message=null, $code=0)
{
parent::__construct($message, $code);
}
}

View file

@ -0,0 +1,40 @@
<?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\Exception;
/**
* Transport exceptions
*/
class TTransportException extends TException
{
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);
}
}

View file

@ -0,0 +1,45 @@
<?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\Factory;
use Thrift\Protocol\TBinaryProtocol;
/**
* Binary Protocol Factory
*/
class TBinaryProtocolFactory implements TProtocolFactory
{
private $strictRead_ = false;
private $strictWrite_ = false;
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_);
}
}

View file

@ -0,0 +1,40 @@
<?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\Factory;
use Thrift\Protocol\TCompactProtocol;
/**
* Compact Protocol Factory
*/
class TCompactProtocolFactory implements TProtocolFactory
{
public function __construct()
{
}
public function getProtocol($trans)
{
return new TCompactProtocol($trans);
}
}

View file

@ -0,0 +1,40 @@
<?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\Factory;
use Thrift\Protocol\TJSONProtocol;
/**
* JSON Protocol Factory
*/
class TJSONProtocolFactory implements TProtocolFactory
{
public function __construct()
{
}
public function getProtocol($trans)
{
return new TJSONProtocol($trans);
}
}

View file

@ -0,0 +1,36 @@
<?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\Factory;
/**
* Protocol factory creates protocol objects from transports
*/
interface TProtocolFactory
{
/**
* Build a protocol from the base transport
*
* @return Thrift\Protocol\TProtocol protocol
*/
public function getProtocol($trans);
}

View file

@ -0,0 +1,66 @@
<?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\Factory;
use Thrift\StringFunc\Mbstring;
use Thrift\StringFunc\Core;
class TStringFuncFactory
{
private static $_instance;
/**
* Get the Singleton instance of TStringFunc implementation that is
* compatible with the current system's mbstring.func_overload settings.
*
* @return TStringFunc
*/
public static function create()
{
if (!self::$_instance) {
self::_setInstance();
}
return self::$_instance;
}
private static function _setInstance()
{
/**
* Cannot use str* functions for byte counting because multibyte
* characters will be read a single bytes.
*
* See: http://us.php.net/manual/en/mbstring.overload.php
*/
if (ini_get('mbstring.func_overload') & 2) {
self::$_instance = new Mbstring();
}
/**
* mbstring is not installed or does not have function overloading
* of the str* functions enabled so use PHP core str* functions for
* byte counting.
*/
else {
self::$_instance = new 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

@ -0,0 +1,39 @@
<?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\JSON;
class BaseContext
{
public function escapeNum()
{
return false;
}
public function write()
{
}
public function read()
{
}
}

View file

@ -0,0 +1,54 @@
<?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\JSON;
use Thrift\Protocol\TJSONProtocol;
class ListContext extends BaseContext
{
private $first_ = true;
private $p_;
public function __construct($p)
{
$this->p_ = $p;
}
public function write()
{
if ($this->first_) {
$this->first_ = false;
} else {
$this->p_->getTransport()->write(TJSONProtocol::COMMA);
}
}
public function read()
{
if ($this->first_) {
$this->first_ = false;
} else {
$this->p_->readJSONSyntaxChar(TJSONProtocol::COMMA);
}
}
}

View file

@ -0,0 +1,57 @@
<?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\JSON;
class LookaheadReader
{
private $hasData_ = false;
private $data_ = array();
private $p_;
public function __construct($p)
{
$this->p_ = $p;
}
public function read()
{
if ($this->hasData_) {
$this->hasData_ = false;
} else {
$this->data_ = $this->p_->getTransport()->readAll(1);
}
return substr($this->data_, 0, 1);
}
public function peek()
{
if (!$this->hasData_) {
$this->data_ = $this->p_->getTransport()->readAll(1);
}
$this->hasData_ = true;
return substr($this->data_, 0, 1);
}
}

View file

@ -0,0 +1,64 @@
<?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\JSON;
use Thrift\Protocol\TJSONProtocol;
class PairContext extends BaseContext
{
private $first_ = true;
private $colon_ = true;
private $p_ = null;
public function __construct($p)
{
$this->p_ = $p;
}
public function write()
{
if ($this->first_) {
$this->first_ = false;
$this->colon_ = true;
} else {
$this->p_->getTransport()->write($this->colon_ ? TJSONProtocol::COLON : TJSONProtocol::COMMA);
$this->colon_ = !$this->colon_;
}
}
public function read()
{
if ($this->first_) {
$this->first_ = false;
$this->colon_ = true;
} else {
$this->p_->readJSONSyntaxChar($this->colon_ ? TJSONProtocol::COLON : TJSONProtocol::COMMA);
$this->colon_ = !$this->colon_;
}
}
public function escapeNum()
{
return $this->colon_;
}
}

View file

@ -0,0 +1,33 @@
<?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\SimpleJSON;
use Thrift\Exception\TException;
class CollectionMapKeyException extends TException
{
public function __construct($message)
{
parent::__construct($message);
}
}

View file

@ -0,0 +1,36 @@
<?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\SimpleJSON;
class Context
{
public function write()
{
}
public function isMapKey()
{
return false;
}
}

View file

@ -0,0 +1,45 @@
<?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\SimpleJSON;
use Thrift\Protocol\TSimpleJSONProtocol;
class ListContext extends Context
{
protected $first_ = true;
private $p_;
public function __construct($p)
{
$this->p_ = $p;
}
public function write()
{
if ($this->first_) {
$this->first_ = false;
} else {
$this->p_->getTransport()->write(TSimpleJSONProtocol::COMMA);
}
}
}

View file

@ -0,0 +1,51 @@
<?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\SimpleJSON;
use Thrift\Protocol\TSimpleJSONProtocol;
class MapContext extends StructContext
{
protected $isKey = true;
private $p_;
public function __construct($p)
{
parent::__construct($p);
}
public function write()
{
parent::write();
$this->isKey = !$this->isKey;
}
public function isMapKey()
{
// we want to coerce map keys to json strings regardless
// of their type
return $this->isKey;
}
}

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.protocol
*/
namespace Thrift\Protocol\SimpleJSON;
use Thrift\Protocol\TSimpleJSONProtocol;
class StructContext extends Context
{
protected $first_ = true;
protected $colon_ = true;
private $p_;
public function __construct($p)
{
$this->p_ = $p;
}
public function write()
{
if ($this->first_) {
$this->first_ = false;
$this->colon_ = true;
} else {
$this->p_->getTransport()->write(
$this->colon_ ?
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,65 @@
<?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

@ -0,0 +1,807 @@
<?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\Protocol\JSON\BaseContext;
use Thrift\Protocol\JSON\LookaheadReader;
use Thrift\Protocol\JSON\PairContext;
use Thrift\Protocol\JSON\ListContext;
/**
* JSON implementation of thrift protocol, ported from Java.
*/
class TJSONProtocol extends TProtocol
{
const COMMA = ',';
const COLON = ':';
const LBRACE = '{';
const RBRACE = '}';
const LBRACKET = '[';
const RBRACKET = ']';
const QUOTE = '"';
const BACKSLASH = '\\';
const ZERO = '0';
const ESCSEQ = '\\';
const DOUBLEESC = '__DOUBLE_ESCAPE_SEQUENCE__';
const VERSION = 1;
public static $JSON_CHAR_TABLE = array(
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
1, 1, '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
);
public static $ESCAPE_CHARS = array('"', '\\', '/', "b", "f", "n", "r", "t");
public static $ESCAPE_CHAR_VALS = array(
'"', '\\', '/', "\x08", "\f", "\n", "\r", "\t",
);
const NAME_BOOL = "tf";
const NAME_BYTE = "i8";
const NAME_I16 = "i16";
const NAME_I32 = "i32";
const NAME_I64 = "i64";
const NAME_DOUBLE = "dbl";
const NAME_STRUCT = "rec";
const NAME_STRING = "str";
const NAME_MAP = "map";
const NAME_LIST = "lst";
const NAME_SET = "set";
private function getTypeNameForTypeID($typeID)
{
switch ($typeID) {
case TType::BOOL:
return self::NAME_BOOL;
case TType::BYTE:
return self::NAME_BYTE;
case TType::I16:
return self::NAME_I16;
case TType::I32:
return self::NAME_I32;
case TType::I64:
return self::NAME_I64;
case TType::DOUBLE:
return self::NAME_DOUBLE;
case TType::STRING:
return self::NAME_STRING;
case TType::STRUCT:
return self::NAME_STRUCT;
case TType::MAP:
return self::NAME_MAP;
case TType::SET:
return self::NAME_SET;
case TType::LST:
return self::NAME_LIST;
default:
throw new TProtocolException("Unrecognized type", TProtocolException::UNKNOWN);
}
}
private function getTypeIDForTypeName($name)
{
$result = TType::STOP;
if (strlen($name) > 1) {
switch (substr($name, 0, 1)) {
case 'd':
$result = TType::DOUBLE;
break;
case 'i':
switch (substr($name, 1, 1)) {
case '8':
$result = TType::BYTE;
break;
case '1':
$result = TType::I16;
break;
case '3':
$result = TType::I32;
break;
case '6':
$result = TType::I64;
break;
}
break;
case 'l':
$result = TType::LST;
break;
case 'm':
$result = TType::MAP;
break;
case 'r':
$result = TType::STRUCT;
break;
case 's':
if (substr($name, 1, 1) == 't') {
$result = TType::STRING;
} elseif (substr($name, 1, 1) == 'e') {
$result = TType::SET;
}
break;
case 't':
$result = TType::BOOL;
break;
}
}
if ($result == TType::STOP) {
throw new TProtocolException("Unrecognized type", TProtocolException::INVALID_DATA);
}
return $result;
}
public $contextStack_ = array();
public $context_;
public $reader_;
private function pushContext($c)
{
array_push($this->contextStack_, $this->context_);
$this->context_ = $c;
}
private function popContext()
{
$this->context_ = array_pop($this->contextStack_);
}
public function __construct($trans)
{
parent::__construct($trans);
$this->context_ = new BaseContext();
$this->reader_ = new LookaheadReader($this);
}
public function reset()
{
$this->contextStack_ = array();
$this->context_ = new BaseContext();
$this->reader_ = new LookaheadReader($this);
}
private $tmpbuf_ = array(4);
public function readJSONSyntaxChar($b)
{
$ch = $this->reader_->read();
if (substr($ch, 0, 1) != $b) {
throw new TProtocolException("Unexpected character: " . $ch, TProtocolException::INVALID_DATA);
}
}
private function hexVal($s)
{
for ($i = 0; $i < strlen($s); $i++) {
$ch = substr($s, $i, 1);
if (!($ch >= "a" && $ch <= "f") && !($ch >= "0" && $ch <= "9")) {
throw new TProtocolException("Expected hex character " . $ch, TProtocolException::INVALID_DATA);
}
}
return hexdec($s);
}
private function hexChar($val)
{
return dechex($val);
}
private function hasJSONUnescapedUnicode()
{
if (PHP_MAJOR_VERSION > 5
|| (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 4))
return true;
return false;
}
private function unescapedUnicode($str)
{
if ($this->hasJSONUnescapedUnicode()) {
return json_encode($str, JSON_UNESCAPED_UNICODE);
}
$json = json_encode($str);
/*
* Unescaped character outside the Basic Multilingual Plane
* 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',
function ($matches) {
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',
function ($matches) {
return mb_convert_encoding(pack('H*', $matches[1]), 'UTF-8', 'UTF-16BE');
}, $json);
return $json;
}
private function writeJSONString($b)
{
$this->context_->write();
if (is_numeric($b) && $this->context_->escapeNum()) {
$this->trans_->write(self::QUOTE);
}
$this->trans_->write($this->unescapedUnicode($b));
if (is_numeric($b) && $this->context_->escapeNum()) {
$this->trans_->write(self::QUOTE);
}
}
private function writeJSONInteger($num)
{
$this->context_->write();
if ($this->context_->escapeNum()) {
$this->trans_->write(self::QUOTE);
}
$this->trans_->write($num);
if ($this->context_->escapeNum()) {
$this->trans_->write(self::QUOTE);
}
}
private function writeJSONDouble($num)
{
$this->context_->write();
if ($this->context_->escapeNum()) {
$this->trans_->write(self::QUOTE);
}
$this->trans_->write(json_encode($num));
if ($this->context_->escapeNum()) {
$this->trans_->write(self::QUOTE);
}
}
private function writeJSONBase64($data)
{
$this->context_->write();
$this->trans_->write(self::QUOTE);
$this->trans_->write(json_encode(base64_encode($data)));
$this->trans_->write(self::QUOTE);
}
private function writeJSONObjectStart()
{
$this->context_->write();
$this->trans_->write(self::LBRACE);
$this->pushContext(new PairContext($this));
}
private function writeJSONObjectEnd()
{
$this->popContext();
$this->trans_->write(self::RBRACE);
}
private function writeJSONArrayStart()
{
$this->context_->write();
$this->trans_->write(self::LBRACKET);
$this->pushContext(new ListContext($this));
}
private function writeJSONArrayEnd()
{
$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 ($ch == self::ESCSEQ && $lastChar == self::ESCSEQ) {
$lastChar = self::DOUBLEESC;
} else {
$lastChar = $ch;
}
}
return json_decode($jsonString);
}
private function isJSONNumeric($b)
{
switch ($b) {
case '+':
case '-':
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'E':
case 'e':
return true;
}
return false;
}
private function readJSONNumericChars()
{
$strbld = array();
while (true) {
$ch = $this->reader_->peek();
if (!$this->isJSONNumeric($ch)) {
break;
}
$strbld[] = $this->reader_->read();
}
return implode("", $strbld);
}
private function readJSONInteger()
{
$this->context_->read();
if ($this->context_->escapeNum()) {
$this->readJSONSyntaxChar(self::QUOTE);
}
$str = $this->readJSONNumericChars();
if ($this->context_->escapeNum()) {
$this->readJSONSyntaxChar(self::QUOTE);
}
if (!is_numeric($str)) {
throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA);
}
return intval($str);
}
/**
* Identical to readJSONInteger but without the final cast.
* Needed for proper handling of i64 on 32 bit machines. Why a
* separate function? So we don't have to force the rest of the
* use cases through the extra conditional.
*/
private function readJSONIntegerAsString()
{
$this->context_->read();
if ($this->context_->escapeNum()) {
$this->readJSONSyntaxChar(self::QUOTE);
}
$str = $this->readJSONNumericChars();
if ($this->context_->escapeNum()) {
$this->readJSONSyntaxChar(self::QUOTE);
}
if (!is_numeric($str)) {
throw new TProtocolException("Invalid data in numeric: " . $str, TProtocolException::INVALID_DATA);
}
return $str;
}
private function readJSONDouble()
{
$this->context_->read();
if (substr($this->reader_->peek(), 0, 1) == self::QUOTE) {
$arr = $this->readJSONString(true);
if ($arr == "NaN") {
return NAN;
} elseif ($arr == "Infinity") {
return INF;
} elseif (!$this->context_->escapeNum()) {
throw new TProtocolException("Numeric data unexpectedly quoted " . $arr,
TProtocolException::INVALID_DATA);
}
return floatval($arr);
} else {
if ($this->context_->escapeNum()) {
$this->readJSONSyntaxChar(self::QUOTE);
}
return floatval($this->readJSONNumericChars());
}
}
private function readJSONBase64()
{
$arr = $this->readJSONString(false);
$data = base64_decode($arr, true);
if ($data === false) {
throw new TProtocolException("Invalid base64 data " . $arr, TProtocolException::INVALID_DATA);
}
return $data;
}
private function readJSONObjectStart()
{
$this->context_->read();
$this->readJSONSyntaxChar(self::LBRACE);
$this->pushContext(new PairContext($this));
}
private function readJSONObjectEnd()
{
$this->readJSONSyntaxChar(self::RBRACE);
$this->popContext();
}
private function readJSONArrayStart()
{
$this->context_->read();
$this->readJSONSyntaxChar(self::LBRACKET);
$this->pushContext(new ListContext($this));
}
private function readJSONArrayEnd()
{
$this->readJSONSyntaxChar(self::RBRACKET);
$this->popContext();
}
/**
* 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
*/
public function writeMessageBegin($name, $type, $seqid)
{
$this->writeJSONArrayStart();
$this->writeJSONInteger(self::VERSION);
$this->writeJSONString($name);
$this->writeJSONInteger($type);
$this->writeJSONInteger($seqid);
}
/**
* Close the message
*/
public function writeMessageEnd()
{
$this->writeJSONArrayEnd();
}
/**
* Writes a struct header.
*
* @param string $name Struct name
* @throws TException on write error
* @return int How many bytes written
*/
public function writeStructBegin($name)
{
$this->writeJSONObjectStart();
}
/**
* Close a struct.
*
* @throws TException on write error
* @return int How many bytes written
*/
public function writeStructEnd()
{
$this->writeJSONObjectEnd();
}
public function writeFieldBegin($fieldName, $fieldType, $fieldId)
{
$this->writeJSONInteger($fieldId);
$this->writeJSONObjectStart();
$this->writeJSONString($this->getTypeNameForTypeID($fieldType));
}
public function writeFieldEnd()
{
$this->writeJsonObjectEnd();
}
public function writeFieldStop()
{
}
public function writeMapBegin($keyType, $valType, $size)
{
$this->writeJSONArrayStart();
$this->writeJSONString($this->getTypeNameForTypeID($keyType));
$this->writeJSONString($this->getTypeNameForTypeID($valType));
$this->writeJSONInteger($size);
$this->writeJSONObjectStart();
}
public function writeMapEnd()
{
$this->writeJSONObjectEnd();
$this->writeJSONArrayEnd();
}
public function writeListBegin($elemType, $size)
{
$this->writeJSONArrayStart();
$this->writeJSONString($this->getTypeNameForTypeID($elemType));
$this->writeJSONInteger($size);
}
public function writeListEnd()
{
$this->writeJSONArrayEnd();
}
public function writeSetBegin($elemType, $size)
{
$this->writeJSONArrayStart();
$this->writeJSONString($this->getTypeNameForTypeID($elemType));
$this->writeJSONInteger($size);
}
public function writeSetEnd()
{
$this->writeJSONArrayEnd();
}
public function writeBool($bool)
{
$this->writeJSONInteger($bool ? 1 : 0);
}
public function writeByte($byte)
{
$this->writeJSONInteger($byte);
}
public function writeI16($i16)
{
$this->writeJSONInteger($i16);
}
public function writeI32($i32)
{
$this->writeJSONInteger($i32);
}
public function writeI64($i64)
{
$this->writeJSONInteger($i64);
}
public function writeDouble($dub)
{
$this->writeJSONDouble($dub);
}
public function writeString($str)
{
$this->writeJSONString($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
*/
public function readMessageBegin(&$name, &$type, &$seqid)
{
$this->readJSONArrayStart();
if ($this->readJSONInteger() != self::VERSION) {
throw new TProtocolException("Message contained bad version", TProtocolException::BAD_VERSION);
}
$name = $this->readJSONString(false);
$type = $this->readJSONInteger();
$seqid = $this->readJSONInteger();
return true;
}
/**
* Read the close of message
*/
public function readMessageEnd()
{
$this->readJSONArrayEnd();
}
public function readStructBegin(&$name)
{
$this->readJSONObjectStart();
return 0;
}
public function readStructEnd()
{
$this->readJSONObjectEnd();
}
public function readFieldBegin(&$name, &$fieldType, &$fieldId)
{
$ch = $this->reader_->peek();
$name = "";
if (substr($ch, 0, 1) == self::RBRACE) {
$fieldType = TType::STOP;
} else {
$fieldId = $this->readJSONInteger();
$this->readJSONObjectStart();
$fieldType = $this->getTypeIDForTypeName($this->readJSONString(false));
}
}
public function readFieldEnd()
{
$this->readJSONObjectEnd();
}
public function readMapBegin(&$keyType, &$valType, &$size)
{
$this->readJSONArrayStart();
$keyType = $this->getTypeIDForTypeName($this->readJSONString(false));
$valType = $this->getTypeIDForTypeName($this->readJSONString(false));
$size = $this->readJSONInteger();
$this->readJSONObjectStart();
}
public function readMapEnd()
{
$this->readJSONObjectEnd();
$this->readJSONArrayEnd();
}
public function readListBegin(&$elemType, &$size)
{
$this->readJSONArrayStart();
$elemType = $this->getTypeIDForTypeName($this->readJSONString(false));
$size = $this->readJSONInteger();
return true;
}
public function readListEnd()
{
$this->readJSONArrayEnd();
}
public function readSetBegin(&$elemType, &$size)
{
$this->readJSONArrayStart();
$elemType = $this->getTypeIDForTypeName($this->readJSONString(false));
$size = $this->readJSONInteger();
return true;
}
public function readSetEnd()
{
$this->readJSONArrayEnd();
}
public function readBool(&$bool)
{
$bool = $this->readJSONInteger() == 0 ? false : true;
return true;
}
public function readByte(&$byte)
{
$byte = $this->readJSONInteger();
return true;
}
public function readI16(&$i16)
{
$i16 = $this->readJSONInteger();
return true;
}
public function readI32(&$i32)
{
$i32 = $this->readJSONInteger();
return true;
}
public function readI64(&$i64)
{
if (PHP_INT_SIZE === 4) {
$i64 = $this->readJSONIntegerAsString();
} else {
$i64 = $this->readJSONInteger();
}
return true;
}
public function readDouble(&$dub)
{
$dub = $this->readJSONDouble();
return true;
}
public function readString(&$str)
{
$str = $this->readJSONString(false);
return true;
}
}

View file

@ -0,0 +1,85 @@
<?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\TMessageType;
/**
* <code>TMultiplexedProtocol</code> is a protocol-independent concrete decorator
* that allows a Thrift client to communicate with a multiplexing Thrift server,
* by prepending the service name to the function name during function calls.
*
* @package Thrift\Protocol
*/
class TMultiplexedProtocol extends TProtocolDecorator
{
/**
* Separator between service name and function name.
* Should be the same as used at multiplexed Thrift server.
*
* @var string
*/
const SEPARATOR = ":";
/**
* The name of service.
*
* @var string
*/
private $serviceName_;
/**
* Constructor of <code>TMultiplexedProtocol</code> class.
*
* Wrap the specified protocol, allowing it to be used to communicate with a
* multiplexing server. The <code>$serviceName</code> is required as it is
* prepended to the message header so that the multiplexing server can broker
* the function call to the proper service.
*
* @param TProtocol $protocol
* @param string $serviceName The name of service.
*/
public function __construct(TProtocol $protocol, $serviceName)
{
parent::__construct($protocol);
$this->serviceName_ = $serviceName;
}
/**
* Writes the message header.
* Prepends the service name to the function name, separated by <code>TMultiplexedProtocol::SEPARATOR</code>.
*
* @param string $name Function name.
* @param int $type Message type.
* @param int $seqid The sequence id of this message.
*/
public function writeMessageBegin($name, $type, $seqid)
{
if ($type == TMessageType::CALL || $type == TMessageType::ONEWAY) {
$nameWithService = $this->serviceName_ . self::SEPARATOR . $name;
parent::writeMessageBegin($nameWithService, $type, $seqid);
} else {
parent::writeMessageBegin($name, $type, $seqid);
}
}
}

View file

@ -0,0 +1,352 @@
<?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

@ -0,0 +1,284 @@
<?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\Exception\TException;
/**
* <code>TProtocolDecorator</code> forwards all requests to an enclosed
* <code>TProtocol</code> instance, providing a way to author concise
* concrete decorator subclasses. While it has no abstract methods, it
* is marked abstract as a reminder that by itself, it does not modify
* the behaviour of the enclosed <code>TProtocol</code>.
*
* @package Thrift\Protocol
*/
abstract class TProtocolDecorator extends TProtocol
{
/**
* Instance of protocol, to which all operations will be forwarded.
*
* @var TProtocol
*/
private $concreteProtocol_;
/**
* Constructor of <code>TProtocolDecorator</code> class.
* Encloses the specified protocol.
*
* @param TProtocol $protocol All operations will be forward to this instance. Must be non-null.
*/
protected function __construct(TProtocol $protocol)
{
parent::__construct($protocol->getTransport());
$this->concreteProtocol_ = $protocol;
}
/**
* 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
*/
public function writeMessageBegin($name, $type, $seqid)
{
return $this->concreteProtocol_->writeMessageBegin($name, $type, $seqid);
}
/**
* Closes the message.
*/
public function writeMessageEnd()
{
return $this->concreteProtocol_->writeMessageEnd();
}
/**
* Writes a struct header.
*
* @param string $name Struct name
*
* @throws TException on write error
* @return int How many bytes written
*/
public function writeStructBegin($name)
{
return $this->concreteProtocol_->writeStructBegin($name);
}
/**
* Close a struct.
*
* @throws TException on write error
* @return int How many bytes written
*/
public function writeStructEnd()
{
return $this->concreteProtocol_->writeStructEnd();
}
public function writeFieldBegin($fieldName, $fieldType, $fieldId)
{
return $this->concreteProtocol_->writeFieldBegin($fieldName, $fieldType, $fieldId);
}
public function writeFieldEnd()
{
return $this->concreteProtocol_->writeFieldEnd();
}
public function writeFieldStop()
{
return $this->concreteProtocol_->writeFieldStop();
}
public function writeMapBegin($keyType, $valType, $size)
{
return $this->concreteProtocol_->writeMapBegin($keyType, $valType, $size);
}
public function writeMapEnd()
{
return $this->concreteProtocol_->writeMapEnd();
}
public function writeListBegin($elemType, $size)
{
return $this->concreteProtocol_->writeListBegin($elemType, $size);
}
public function writeListEnd()
{
return $this->concreteProtocol_->writeListEnd();
}
public function writeSetBegin($elemType, $size)
{
return $this->concreteProtocol_->writeSetBegin($elemType, $size);
}
public function writeSetEnd()
{
return $this->concreteProtocol_->writeSetEnd();
}
public function writeBool($bool)
{
return $this->concreteProtocol_->writeBool($bool);
}
public function writeByte($byte)
{
return $this->concreteProtocol_->writeByte($byte);
}
public function writeI16($i16)
{
return $this->concreteProtocol_->writeI16($i16);
}
public function writeI32($i32)
{
return $this->concreteProtocol_->writeI32($i32);
}
public function writeI64($i64)
{
return $this->concreteProtocol_->writeI64($i64);
}
public function writeDouble($dub)
{
return $this->concreteProtocol_->writeDouble($dub);
}
public function writeString($str)
{
return $this->concreteProtocol_->writeString($str);
}
/**
* Reads 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
*/
public function readMessageBegin(&$name, &$type, &$seqid)
{
return $this->concreteProtocol_->readMessageBegin($name, $type, $seqid);
}
/**
* Read the close of message
*/
public function readMessageEnd()
{
return $this->concreteProtocol_->readMessageEnd();
}
public function readStructBegin(&$name)
{
return $this->concreteProtocol_->readStructBegin($name);
}
public function readStructEnd()
{
return $this->concreteProtocol_->readStructEnd();
}
public function readFieldBegin(&$name, &$fieldType, &$fieldId)
{
return $this->concreteProtocol_->readFieldBegin($name, $fieldType, $fieldId);
}
public function readFieldEnd()
{
return $this->concreteProtocol_->readFieldEnd();
}
public function readMapBegin(&$keyType, &$valType, &$size)
{
$this->concreteProtocol_->readMapBegin($keyType, $valType, $size);
}
public function readMapEnd()
{
return $this->concreteProtocol_->readMapEnd();
}
public function readListBegin(&$elemType, &$size)
{
$this->concreteProtocol_->readListBegin($elemType, $size);
}
public function readListEnd()
{
return $this->concreteProtocol_->readListEnd();
}
public function readSetBegin(&$elemType, &$size)
{
return $this->concreteProtocol_->readSetBegin($elemType, $size);
}
public function readSetEnd()
{
return $this->concreteProtocol_->readSetEnd();
}
public function readBool(&$bool)
{
return $this->concreteProtocol_->readBool($bool);
}
public function readByte(&$byte)
{
return $this->concreteProtocol_->readByte($byte);
}
public function readI16(&$i16)
{
return $this->concreteProtocol_->readI16($i16);
}
public function readI32(&$i32)
{
return $this->concreteProtocol_->readI32($i32);
}
public function readI64(&$i64)
{
return $this->concreteProtocol_->readI64($i64);
}
public function readDouble(&$dub)
{
return $this->concreteProtocol_->readDouble($dub);
}
public function readString(&$str)
{
return $this->concreteProtocol_->readString($str);
}
}

View file

@ -0,0 +1,371 @@
<?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\Exception\TException;
use Thrift\Exception\TProtocolException;
use Thrift\Protocol\SimpleJSON\Context;
use Thrift\Protocol\SimpleJSON\ListContext;
use Thrift\Protocol\SimpleJSON\StructContext;
use Thrift\Protocol\SimpleJSON\MapContext;
use Thrift\Protocol\SimpleJSON\CollectionMapKeyException;
/**
* SimpleJSON implementation of thrift protocol, ported from Java.
*/
class TSimpleJSONProtocol extends TProtocol
{
const COMMA = ',';
const COLON = ':';
const LBRACE = '{';
const RBRACE = '}';
const LBRACKET = '[';
const RBRACKET = ']';
const QUOTE = '"';
const NAME_MAP = "map";
const NAME_LIST = "lst";
const NAME_SET = "set";
protected $writeContext_ = null;
protected $writeContextStack_ = [];
/**
* Push a new write context onto the stack.
*/
protected function pushWriteContext(Context $c) {
$this->writeContextStack_[] = $this->writeContext_;
$this->writeContext_ = $c;
}
/**
* Pop the last write context off the stack
*/
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) {
if ($this->writeContext_->isMapKey()) {
throw new CollectionMapKeyException(
"Cannot serialize a map with keys that are of type " .
$invalidKeyType
);
}
}
private function writeJSONString($b)
{
$this->writeContext_->write();
$this->trans_->write(json_encode((string)$b));
}
private function writeJSONInteger($num)
{
$isMapKey = $this->writeContext_->isMapKey();
$this->writeContext_->write();
if ($isMapKey) {
$this->trans_->write(self::QUOTE);
}
$this->trans_->write((int)$num);
if ($isMapKey) {
$this->trans_->write(self::QUOTE);
}
}
private function writeJSONDouble($num)
{
$isMapKey = $this->writeContext_->isMapKey();
$this->writeContext_->write();
if ($isMapKey) {
$this->trans_->write(self::QUOTE);
}
$this->trans_->write(json_encode((float)$num));
if ($isMapKey) {
$this->trans_->write(self::QUOTE);
}
}
/**
* Constructor
*/
public function __construct($trans)
{
parent::__construct($trans);
$this->writeContext_ = new Context();
}
/**
* 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
*/
public function writeMessageBegin($name, $type, $seqid)
{
$this->trans_->write(self::LBRACKET);
$this->pushWriteContext(new ListContext($this));
$this->writeJSONString($name);
$this->writeJSONInteger($type);
$this->writeJSONInteger($seqid);
}
/**
* Close the message
*/
public function writeMessageEnd()
{
$this->popWriteContext();
$this->trans_->write(self::RBRACKET);
}
/**
* Writes a struct header.
*
* @param string $name Struct name
*/
public function writeStructBegin($name)
{
$this->writeContext_->write();
$this->trans_->write(self::LBRACE);
$this->pushWriteContext(new StructContext($this));
}
/**
* Close a struct.
*/
public function writeStructEnd()
{
$this->popWriteContext();
$this->trans_->write(self::RBRACE);
}
public function writeFieldBegin($fieldName, $fieldType, $fieldId)
{
$this->writeJSONString($fieldName);
}
public function writeFieldEnd()
{
}
public function writeFieldStop()
{
}
public function writeMapBegin($keyType, $valType, $size)
{
$this->assertContextIsNotMapKey(self::NAME_MAP);
$this->writeContext_->write();
$this->trans_->write(self::LBRACE);
$this->pushWriteContext(new MapContext($this));
}
public function writeMapEnd()
{
$this->popWriteContext();
$this->trans_->write(self::RBRACE);
}
public function writeListBegin($elemType, $size)
{
$this->assertContextIsNotMapKey(self::NAME_LIST);
$this->writeContext_->write();
$this->trans_->write(self::LBRACKET);
$this->pushWriteContext(new ListContext($this));
// No metadata!
}
public function writeListEnd()
{
$this->popWriteContext();
$this->trans_->write(self::RBRACKET);
}
public function writeSetBegin($elemType, $size)
{
$this->assertContextIsNotMapKey(self::NAME_SET);
$this->writeContext_->write();
$this->trans_->write(self::LBRACKET);
$this->pushWriteContext(new ListContext($this));
// No metadata!
}
public function writeSetEnd()
{
$this->popWriteContext();
$this->trans_->write(self::RBRACKET);
}
public function writeBool($bool)
{
$this->writeJSONInteger($bool ? 1 : 0);
}
public function writeByte($byte)
{
$this->writeJSONInteger($byte);
}
public function writeI16($i16)
{
$this->writeJSONInteger($i16);
}
public function writeI32($i32)
{
$this->writeJSONInteger($i32);
}
public function writeI64($i64)
{
$this->writeJSONInteger($i64);
}
public function writeDouble($dub)
{
$this->writeJSONDouble($dub);
}
public function writeString($str)
{
$this->writeJSONString($str);
}
/**
* Reading methods.
*
* simplejson is not meant to be read back into thrift
* - see http://wiki.apache.org/thrift/ThriftUsageJava
* - use JSON instead
*/
public function readMessageBegin(&$name, &$type, &$seqid)
{
throw new TException("Not implemented");
}
public function readMessageEnd()
{
throw new TException("Not implemented");
}
public function readStructBegin(&$name)
{
throw new TException("Not implemented");
}
public function readStructEnd()
{
throw new TException("Not implemented");
}
public function readFieldBegin(&$name, &$fieldType, &$fieldId)
{
throw new TException("Not implemented");
}
public function readFieldEnd()
{
throw new TException("Not implemented");
}
public function readMapBegin(&$keyType, &$valType, &$size)
{
throw new TException("Not implemented");
}
public function readMapEnd()
{
throw new TException("Not implemented");
}
public function readListBegin(&$elemType, &$size)
{
throw new TException("Not implemented");
}
public function readListEnd()
{
throw new TException("Not implemented");
}
public function readSetBegin(&$elemType, &$size)
{
throw new TException("Not implemented");
}
public function readSetEnd()
{
throw new TException("Not implemented");
}
public function readBool(&$bool)
{
throw new TException("Not implemented");
}
public function readByte(&$byte)
{
throw new TException("Not implemented");
}
public function readI16(&$i16)
{
throw new TException("Not implemented");
}
public function readI32(&$i32)
{
throw new TException("Not implemented");
}
public function readI64(&$i64)
{
throw new TException("Not implemented");
}
public function readDouble(&$dub)
{
throw new TException("Not implemented");
}
public function readString(&$str)
{
throw new TException("Not implemented");
}
}

View file

@ -0,0 +1,85 @@
<?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,120 @@
<?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,94 @@
<?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,100 @@
<?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,122 @@
<?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,58 @@
<?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,40 @@
<?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\StringFunc;
class Core implements TStringFunc
{
public function substr($str, $start, $length = null)
{
// specifying a null $length would return an empty string
if ($length === null) {
return substr($str, $start);
}
return substr($str, $start, $length);
}
public function strlen($str)
{
return strlen($str);
}
}

View file

@ -0,0 +1,46 @@
<?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\StringFunc;
class Mbstring implements TStringFunc
{
public function substr($str, $start, $length = null)
{
/**
* We need to set the charset parameter, which is the second
* optional parameter and the first optional parameter can't
* be null or false as a "magic" value because that would
* cause an empty string to be returned, so we need to
* actually calculate the proper length value.
*/
if ($length === null) {
$length = $this->strlen($str) - $start;
}
return mb_substr($str, $start, $length, '8bit');
}
public function strlen($str)
{
return mb_strlen($str, '8bit');
}
}

View file

@ -0,0 +1,28 @@
<?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\StringFunc;
interface TStringFunc
{
public function substr($str, $start, $length = null);
public function strlen($str);
}

View file

@ -0,0 +1,143 @@
<?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\Exception\TException;
use Thrift\Protocol\TProtocol;
use Thrift\Protocol\TMultiplexedProtocol;
use Thrift\Protocol\TProtocolDecorator;
use Thrift\Type\TMessageType;
/**
* <code>TMultiplexedProcessor</code> is a Processor allowing
* a single <code>TServer</code> to provide multiple services.
*
* <p>To do so, you instantiate the processor and then register additional
* processors with it, as shown in the following example:</p>
*
* <blockquote><code>
* $processor = new TMultiplexedProcessor();
*
* processor->registerProcessor(
* "Calculator",
* new \tutorial\CalculatorProcessor(new CalculatorHandler()));
*
* processor->registerProcessor(
* "WeatherReport",
* new \tutorial\WeatherReportProcessor(new WeatherReportHandler()));
*
* $processor->process($protocol, $protocol);
* </code></blockquote>
*/
class TMultiplexedProcessor
{
private $serviceProcessorMap_;
/**
* 'Register' a service with this <code>TMultiplexedProcessor</code>. This
* allows us to broker requests to individual services by using the service
* name to select them at request time.
*
* @param serviceName Name of a service, has to be identical to the name
* declared in the Thrift IDL, e.g. "WeatherReport".
* @param processor Implementation of a service, usually referred to
* as "handlers", e.g. WeatherReportHandler implementing WeatherReport.Iface.
*/
public function registerProcessor($serviceName, $processor)
{
$this->serviceProcessorMap_[$serviceName] = $processor;
}
/**
* This implementation of <code>process</code> performs the following steps:
*
* <ol>
* <li>Read the beginning of the message.</li>
* <li>Extract the service name from the message.</li>
* <li>Using the service name to locate the appropriate processor.</li>
* <li>Dispatch to the processor, with a decorated instance of TProtocol
* that allows readMessageBegin() to return the original Message.</li>
* </ol>
*
* @throws TException If the message type is not CALL or ONEWAY, if
* the service name was not found in the message, or if the service
* name was not found in the service map.
*/
public function process(TProtocol $input, TProtocol $output)
{
/*
Use the actual underlying protocol (e.g. TBinaryProtocol) to read the
message header. This pulls the message "off the wire", which we'll
deal with at the end of this method.
*/
$input->readMessageBegin($fname, $mtype, $rseqid);
if ($mtype !== TMessageType::CALL && $mtype != TMessageType::ONEWAY) {
throw new TException("This should not have happened!?");
}
// Extract the service name and the new Message name.
if (strpos($fname, TMultiplexedProtocol::SEPARATOR) === false) {
throw new TException("Service name not found in message name: {$fname}. Did you " .
"forget to use a TMultiplexProtocol in your client?");
}
list($serviceName, $messageName) = explode(':', $fname, 2);
if (!array_key_exists($serviceName, $this->serviceProcessorMap_)) {
throw new TException("Service name not found: {$serviceName}. Did you forget " .
"to call registerProcessor()?");
}
// Dispatch processing to the stored processor
$processor = $this->serviceProcessorMap_[$serviceName];
return $processor->process(
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

@ -0,0 +1,181 @@
<?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

@ -0,0 +1,231 @@
<?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

@ -0,0 +1,193 @@
<?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,229 @@
<?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,100 @@
<?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

@ -0,0 +1,51 @@
<?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;
/**
* Transport that only accepts writes and ignores them.
* This is useful for measuring the serialized size of structures.
*
* @package thrift.transport
*/
class TNullTransport extends TTransport
{
public function isOpen()
{
return true;
}
public function open() {}
public function close() {}
public function read($len)
{
throw new TTransportException("Can't read from TNullTransport.");
}
public function write($buf) {}
}

View file

@ -0,0 +1,123 @@
<?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,112 @@
<?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,337 @@
<?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

@ -0,0 +1,300 @@
<?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,95 @@
<?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,50 @@
<?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\Type;
/**
* Base class for constant Management
*/
abstract class TConstant
{
/**
* Don't instanciate this class
*/
protected function __construct() {}
/**
* Get a constant value
* @param string $constant
* @return mixed
*/
public static function get($constant)
{
if (is_null(static::$$constant)) {
static::$$constant = call_user_func(
sprintf('static::init_%s', $constant)
);
}
return static::$$constant;
}
}

View file

@ -0,0 +1,34 @@
<?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\Type;
/**
* Message types for RPC
*/
class TMessageType
{
const CALL = 1;
const REPLY = 2;
const EXCEPTION = 3;
const ONEWAY = 4;
}

View file

@ -0,0 +1,47 @@
<?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\Type;
/**
* Data types that can be sent via Thrift
*/
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;
}