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 * Sockets implementation of the TTransport interface. 16 * 17 * @package thrift.transport 18 * @author Mark Slee <mcslee@facebook.com> 19 */ 20class TSocket extends TTransport { 21 22 /** 23 * Handle to PHP socket 24 * 25 * @var resource 26 */ 27 private $handle_ = null; 28 29 /** 30 * Remote hostname 31 * 32 * @var string 33 */ 34 protected $host_ = 'localhost'; 35 36 /** 37 * Remote port 38 * 39 * @var int 40 */ 41 protected $port_ = '9090'; 42 43 /** 44 * Send timeout in milliseconds 45 * 46 * @var int 47 */ 48 private $sendTimeout_ = 100; 49 50 /** 51 * Recv timeout in milliseconds 52 * 53 * @var int 54 */ 55 private $recvTimeout_ = 750; 56 57 /** 58 * Is send timeout set? 59 * 60 * @var bool 61 */ 62 private $sendTimeoutSet_ = FALSE; 63 64 /** 65 * Persistent socket or plain? 66 * 67 * @var bool 68 */ 69 private $persist_ = FALSE; 70 71 /** 72 * Debugging on? 73 * 74 * @var bool 75 */ 76 protected $debug_ = FALSE; 77 78 /** 79 * Debug handler 80 * 81 * @var mixed 82 */ 83 protected $debugHandler_ = null; 84 85 /** 86 * Socket constructor 87 * 88 * @param string $host Remote hostname 89 * @param int $port Remote port 90 * @param bool $persist Whether to use a persistent socket 91 * @param string $debugHandler Function to call for error logging 92 */ 93 public function __construct($host='localhost', 94 $port=9090, 95 $persist=FALSE, 96 $debugHandler=null) { 97 $this->host_ = $host; 98 $this->port_ = $port; 99 $this->persist_ = $persist; 100 $this->debugHandler_ = $debugHandler ? $debugHandler : 'error_log'; 101 } 102 103 /** 104 * Sets the send timeout. 105 * 106 * @param int $timeout 107 */ 108 public function setSendTimeout($timeout) { 109 $this->sendTimeout_ = $timeout; 110 } 111 112 /** 113 * Sets the receive timeout. 114 * 115 * @param int $timeout 116 */ 117 public function setRecvTimeout($timeout) { 118 $this->recvTimeout_ = $timeout; 119 } 120 121 /** 122 * Sets debugging output on or off 123 * 124 * @param bool $debug 125 */ 126 public function setDebug($debug) { 127 $this->debug_ = $debug; 128 } 129 130 /** 131 * Get the host that this socket is connected to 132 * 133 * @return string host 134 */ 135 public function getHost() { 136 return $this->host_; 137 } 138 139 /** 140 * Get the remote port that this socket is connected to 141 * 142 * @return int port 143 */ 144 public function getPort() { 145 return $this->port_; 146 } 147 148 /** 149 * Tests whether this is open 150 * 151 * @return bool true if the socket is open 152 */ 153 public function isOpen() { 154 return is_resource($this->handle_); 155 } 156 157 /** 158 * Connects the socket. 159 */ 160 public function open() { 161 162 if ($this->persist_) { 163 $this->handle_ = @pfsockopen($this->host_, 164 $this->port_, 165 $errno, 166 $errstr, 167 $this->sendTimeout_/1000.0); 168 } else { 169 $this->handle_ = @fsockopen($this->host_, 170 $this->port_, 171 $errno, 172 $errstr, 173 $this->sendTimeout_/1000.0); 174 } 175 176 // Connect failed? 177 if ($this->handle_ === FALSE) { 178 $error = 'TSocket: Could not connect to '.$this->host_.':'.$this->port_.' ('.$errstr.' ['.$errno.'])'; 179 if ($this->debug_) { 180 call_user_func($this->debugHandler_, $error); 181 } 182 throw new TException($error); 183 } 184 185 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000); 186 $this->sendTimeoutSet_ = TRUE; 187 } 188 189 /** 190 * Closes the socket. 191 */ 192 public function close() { 193 if (!$this->persist_) { 194 @fclose($this->handle_); 195 $this->handle_ = null; 196 } 197 } 198 199 /** 200 * Uses stream get contents to do the reading 201 * 202 * @param int $len How many bytes 203 * @return string Binary data 204 */ 205 public function readAll($len) { 206 if ($this->sendTimeoutSet_) { 207 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000); 208 $this->sendTimeoutSet_ = FALSE; 209 } 210 // This call does not obey stream_set_timeout values! 211 // $buf = @stream_get_contents($this->handle_, $len); 212 213 $pre = null; 214 while (TRUE) { 215 $buf = @fread($this->handle_, $len); 216 if ($buf === FALSE || $buf === '') { 217 $md = stream_get_meta_data($this->handle_); 218 if ($md['timed_out']) { 219 throw new TException('TSocket: timed out reading '.$len.' bytes from '. 220 $this->host_.':'.$this->port_); 221 } else { 222 throw new TException('TSocket: Could not read '.$len.' bytes from '. 223 $this->host_.':'.$this->port_); 224 } 225 } else if (($sz = strlen($buf)) < $len) { 226 $md = stream_get_meta_data($this->handle_); 227 if ($md['timed_out']) { 228 throw new TException('TSocket: timed out reading '.$len.' bytes from '. 229 $this->host_.':'.$this->port_); 230 } else { 231 $pre .= $buf; 232 $len -= $sz; 233 } 234 } else { 235 return $pre.$buf; 236 } 237 } 238 } 239 240 /** 241 * Read from the socket 242 * 243 * @param int $len How many bytes 244 * @return string Binary data 245 */ 246 public function read($len) { 247 if ($this->sendTimeoutSet_) { 248 stream_set_timeout($this->handle_, 0, $this->recvTimeout_*1000); 249 $this->sendTimeoutSet_ = FALSE; 250 } 251 $data = @fread($this->handle_, $len); 252 if ($data === FALSE || $data === '') { 253 $md = stream_get_meta_data($this->handle_); 254 if ($md['timed_out']) { 255 throw new TException('TSocket: timed out reading '.$len.' bytes from '. 256 $this->host_.':'.$this->port_); 257 } else { 258 throw new TException('TSocket: Could not read '.$len.' bytes from '. 259 $this->host_.':'.$this->port_); 260 } 261 } 262 return $data; 263 } 264 265 /** 266 * Write to the socket. 267 * 268 * @param string $buf The data to write 269 */ 270 public function write($buf) { 271 if (!$this->sendTimeoutSet_) { 272 stream_set_timeout($this->handle_, 0, $this->sendTimeout_*1000); 273 $this->sendTimeoutSet_ = TRUE; 274 } 275 while (strlen($buf) > 0) { 276 $got = @fwrite($this->handle_, $buf); 277 if ($got === 0 || $got === FALSE) { 278 $md = stream_get_meta_data($this->handle_); 279 if ($md['timed_out']) { 280 throw new TException('TSocket: timed out writing '.strlen($buf).' bytes from '. 281 $this->host_.':'.$this->port_); 282 } else { 283 throw new TException('TSocket: Could not write '.strlen($buf).' bytes '. 284 $this->host_.':'.$this->port_); 285 } 286 } 287 $buf = substr($buf, $got); 288 } 289 } 290 291 /** 292 * Flush output to the socket. 293 */ 294 public function flush() { 295 $ret = fflush($this->handle_); 296 if ($ret === FALSE) { 297 throw new TException('TSocket: Could not flush: '. 298 $this->host_.':'.$this->port_); 299 } 300 } 301} 302 303?> 304