1<?php 2 3/** 4 * Copyright (c) 2006- Facebook 5 * Distributed under the Thrift Software License 6 * 7 * See accompanying file LICENSE or visit the Thrift site at: 8 * http://developers.facebook.com/thrift/ 9 * 10 * @package thrift.transport 11 * @author Mark Slee <mcslee@facebook.com> 12 */ 13 14/** 15 * Framed transport. Writes and reads data in chunks that are stamped with 16 * their length. 17 * 18 * @package thrift.transport 19 * @author Mark Slee <mcslee@facebook.com> 20 */ 21class TFramedTransport extends TTransport { 22 23 /** 24 * Underlying transport object. 25 * 26 * @var TTransport 27 */ 28 private $transport_; 29 30 /** 31 * Buffer for read data. 32 * 33 * @var string 34 */ 35 private $rBuf_; 36 37 /** 38 * Buffer for queued output data 39 * 40 * @var string 41 */ 42 private $wBuf_; 43 44 /** 45 * Whether to frame reads 46 * 47 * @var bool 48 */ 49 private $read_; 50 51 /** 52 * Whether to frame writes 53 * 54 * @var bool 55 */ 56 private $write_; 57 58 /** 59 * Constructor. 60 * 61 * @param TTransport $transport Underlying transport 62 */ 63 public function __construct($transport=null, $read=true, $write=true) { 64 $this->transport_ = $transport; 65 $this->read_ = $read; 66 $this->write_ = $write; 67 } 68 69 public function isOpen() { 70 return $this->transport_->isOpen(); 71 } 72 73 public function open() { 74 $this->transport_->open(); 75 } 76 77 public function close() { 78 $this->transport_->close(); 79 } 80 81 /** 82 * Reads from the buffer. When more data is required reads another entire 83 * chunk and serves future reads out of that. 84 * 85 * @param int $len How much data 86 */ 87 public function read($len) { 88 if (!$this->read_) { 89 return $this->transport_->read($len); 90 } 91 92 if (strlen($this->rBuf_) === 0) { 93 $this->readFrame(); 94 } 95 96 // Just return full buff 97 if ($len >= strlen($this->rBuf_)) { 98 $out = $this->rBuf_; 99 $this->rBuf_ = null; 100 return $out; 101 } 102 103 // Return substr 104 $out = substr($this->rBuf_, 0, $len); 105 $this->rBuf_ = substr($this->rBuf_, $len); 106 return $out; 107 } 108 109 /** 110 * Put previously read data back into the buffer 111 * 112 * @param string $data data to return 113 */ 114 public function putBack($data) { 115 if (strlen($this->rBuf_) === 0) { 116 $this->rBuf_ = $data; 117 } else { 118 $this->rBuf_ = ($data . $this->rBuf_); 119 } 120 } 121 122 /** 123 * Reads a chunk of data into the internal read buffer. 124 */ 125 private function readFrame() { 126 $buf = $this->transport_->readAll(4); 127 $val = unpack('N', $buf); 128 $sz = $val[1]; 129 130 $this->rBuf_ = $this->transport_->readAll($sz); 131 } 132 133 /** 134 * Writes some data to the pending output buffer. 135 * 136 * @param string $buf The data 137 * @param int $len Limit of bytes to write 138 */ 139 public function write($buf, $len=null) { 140 if (!$this->write_) { 141 return $this->transport_->write($buf, $len); 142 } 143 144 if ($len !== null && $len < strlen($buf)) { 145 $buf = substr($buf, 0, $len); 146 } 147 $this->wBuf_ .= $buf; 148 } 149 150 /** 151 * Writes the output buffer to the stream in the format of a 4-byte length 152 * followed by the actual data. 153 */ 154 public function flush() { 155 if (!$this->write_) { 156 return $this->transport_->flush(); 157 } 158 159 $out = pack('N', strlen($this->wBuf_)); 160 $out .= $this->wBuf_; 161 162 // Note that we clear the internal wBuf_ prior to the underlying write 163 // to ensure we're in a sane state (i.e. internal buffer cleaned) 164 // if the underlying write throws up an exception 165 $this->wBuf_ = ''; 166 $this->transport_->write($out); 167 $this->transport_->flush(); 168 } 169 170} 171