socket.php 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. <?php
  2. /**
  3. * base include file for SimpleTest
  4. * @package SimpleTest
  5. * @subpackage MockObjects
  6. * @version $Id: socket.php 1788 2008-04-27 11:01:59Z pp11 $
  7. */
  8. /**#@+
  9. * include SimpleTest files
  10. */
  11. require_once(dirname(__FILE__) . '/compatibility.php');
  12. /**#@-*/
  13. /**
  14. * Stashes an error for later. Useful for constructors
  15. * until PHP gets exceptions.
  16. * @package SimpleTest
  17. * @subpackage WebTester
  18. */
  19. class SimpleStickyError {
  20. private $error = 'Constructor not chained';
  21. /**
  22. * Sets the error to empty.
  23. * @access public
  24. */
  25. function __construct() {
  26. $this->clearError();
  27. }
  28. /**
  29. * Test for an outstanding error.
  30. * @return boolean True if there is an error.
  31. * @access public
  32. */
  33. function isError() {
  34. return ($this->error != '');
  35. }
  36. /**
  37. * Accessor for an outstanding error.
  38. * @return string Empty string if no error otherwise
  39. * the error message.
  40. * @access public
  41. */
  42. function getError() {
  43. return $this->error;
  44. }
  45. /**
  46. * Sets the internal error.
  47. * @param string Error message to stash.
  48. * @access protected
  49. */
  50. function setError($error) {
  51. $this->error = $error;
  52. }
  53. /**
  54. * Resets the error state to no error.
  55. * @access protected
  56. */
  57. function clearError() {
  58. $this->setError('');
  59. }
  60. }
  61. class SimpleFileSocket extends SimpleStickyError {
  62. private $handle;
  63. private $is_open = false;
  64. private $sent = '';
  65. private $block_size;
  66. /**
  67. * Opens a socket for reading and writing.
  68. * @param SimpleUrl $file Target URI to fetch.
  69. * @param integer $block_size Size of chunk to read.
  70. * @access public
  71. */
  72. function __construct($file, $block_size = 1024) {
  73. parent::__construct();
  74. if (! ($this->handle = $this->openFile($file, $error))) {
  75. $file_string = $file->asString();
  76. $this->setError("Cannot open [$file_string] with [$error]");
  77. return;
  78. }
  79. $this->is_open = true;
  80. $this->block_size = $block_size;
  81. }
  82. /**
  83. * Writes some data to the socket and saves alocal copy.
  84. * @param string $message String to send to socket.
  85. * @return boolean True if successful.
  86. * @access public
  87. */
  88. function write($message) {
  89. return true;
  90. }
  91. /**
  92. * Reads data from the socket. The error suppresion
  93. * is a workaround for PHP4 always throwing a warning
  94. * with a secure socket.
  95. * @return integer/boolean Incoming bytes. False
  96. * on error.
  97. * @access public
  98. */
  99. function read() {
  100. $raw = @fread($this->handle, $this->block_size);
  101. if ($raw === false) {
  102. $this->setError('Cannot read from socket');
  103. $this->close();
  104. }
  105. return $raw;
  106. }
  107. /**
  108. * Accessor for socket open state.
  109. * @return boolean True if open.
  110. * @access public
  111. */
  112. function isOpen() {
  113. return $this->is_open;
  114. }
  115. /**
  116. * Closes the socket preventing further reads.
  117. * Cannot be reopened once closed.
  118. * @return boolean True if successful.
  119. * @access public
  120. */
  121. function close() {
  122. if (!$this->is_open) return false;
  123. $this->is_open = false;
  124. return fclose($this->handle);
  125. }
  126. /**
  127. * Accessor for content so far.
  128. * @return string Bytes sent only.
  129. * @access public
  130. */
  131. function getSent() {
  132. return $this->sent;
  133. }
  134. /**
  135. * Actually opens the low level socket.
  136. * @param SimpleUrl $file SimpleUrl file target.
  137. * @param string $error Recipient of error message.
  138. * @param integer $timeout Maximum time to wait for connection.
  139. * @access protected
  140. */
  141. protected function openFile($file, &$error) {
  142. return @fopen($file->asString(), 'r');
  143. }
  144. }
  145. /**
  146. * Wrapper for TCP/IP socket.
  147. * @package SimpleTest
  148. * @subpackage WebTester
  149. */
  150. class SimpleSocket extends SimpleStickyError {
  151. private $handle;
  152. private $is_open = false;
  153. private $sent = '';
  154. private $lock_size;
  155. /**
  156. * Opens a socket for reading and writing.
  157. * @param string $host Hostname to send request to.
  158. * @param integer $port Port on remote machine to open.
  159. * @param integer $timeout Connection timeout in seconds.
  160. * @param integer $block_size Size of chunk to read.
  161. * @access public
  162. */
  163. function __construct($host, $port, $timeout, $block_size = 255) {
  164. parent::__construct();
  165. if (! ($this->handle = $this->openSocket($host, $port, $error_number, $error, $timeout))) {
  166. $this->setError("Cannot open [$host:$port] with [$error] within [$timeout] seconds");
  167. return;
  168. }
  169. $this->is_open = true;
  170. $this->block_size = $block_size;
  171. SimpleTestCompatibility::setTimeout($this->handle, $timeout);
  172. }
  173. /**
  174. * Writes some data to the socket and saves alocal copy.
  175. * @param string $message String to send to socket.
  176. * @return boolean True if successful.
  177. * @access public
  178. */
  179. function write($message) {
  180. if ($this->isError() || ! $this->isOpen()) {
  181. return false;
  182. }
  183. $count = fwrite($this->handle, $message);
  184. if (! $count) {
  185. if ($count === false) {
  186. $this->setError('Cannot write to socket');
  187. $this->close();
  188. }
  189. return false;
  190. }
  191. fflush($this->handle);
  192. $this->sent .= $message;
  193. return true;
  194. }
  195. /**
  196. * Reads data from the socket. The error suppresion
  197. * is a workaround for PHP4 always throwing a warning
  198. * with a secure socket.
  199. * @return integer/boolean Incoming bytes. False
  200. * on error.
  201. * @access public
  202. */
  203. function read() {
  204. if ($this->isError() || ! $this->isOpen()) {
  205. return false;
  206. }
  207. $raw = @fread($this->handle, $this->block_size);
  208. if ($raw === false) {
  209. $this->setError('Cannot read from socket');
  210. $this->close();
  211. }
  212. return $raw;
  213. }
  214. /**
  215. * Accessor for socket open state.
  216. * @return boolean True if open.
  217. * @access public
  218. */
  219. function isOpen() {
  220. return $this->is_open;
  221. }
  222. /**
  223. * Closes the socket preventing further reads.
  224. * Cannot be reopened once closed.
  225. * @return boolean True if successful.
  226. * @access public
  227. */
  228. function close() {
  229. $this->is_open = false;
  230. return fclose($this->handle);
  231. }
  232. /**
  233. * Accessor for content so far.
  234. * @return string Bytes sent only.
  235. * @access public
  236. */
  237. function getSent() {
  238. return $this->sent;
  239. }
  240. /**
  241. * Actually opens the low level socket.
  242. * @param string $host Host to connect to.
  243. * @param integer $port Port on host.
  244. * @param integer $error_number Recipient of error code.
  245. * @param string $error Recipoent of error message.
  246. * @param integer $timeout Maximum time to wait for connection.
  247. * @access protected
  248. */
  249. protected function openSocket($host, $port, &$error_number, &$error, $timeout) {
  250. return @fsockopen($host, $port, $error_number, $error, $timeout);
  251. }
  252. }
  253. /**
  254. * Wrapper for TCP/IP socket over TLS.
  255. * @package SimpleTest
  256. * @subpackage WebTester
  257. */
  258. class SimpleSecureSocket extends SimpleSocket {
  259. /**
  260. * Opens a secure socket for reading and writing.
  261. * @param string $host Hostname to send request to.
  262. * @param integer $port Port on remote machine to open.
  263. * @param integer $timeout Connection timeout in seconds.
  264. * @access public
  265. */
  266. function __construct($host, $port, $timeout) {
  267. parent::__construct($host, $port, $timeout);
  268. }
  269. /**
  270. * Actually opens the low level socket.
  271. * @param string $host Host to connect to.
  272. * @param integer $port Port on host.
  273. * @param integer $error_number Recipient of error code.
  274. * @param string $error Recipient of error message.
  275. * @param integer $timeout Maximum time to wait for connection.
  276. * @access protected
  277. */
  278. function openSocket($host, $port, &$error_number, &$error, $timeout) {
  279. return parent::openSocket("tls://$host", $port, $error_number, $error, $timeout);
  280. }
  281. }
  282. ?>