* @copyright 2014 Fabian Grutschus. All rights reserved. * @license BSD * @link http://github.com/fabiang/xmpp */ namespace Fabiang\Xmpp\Stream; use Fabiang\Xmpp\Exception\InvalidArgumentException; use Fabiang\Xmpp\Util\ErrorHandler; /** * Stream functions wrapper class. * * @package Xmpp\Stream */ class SocketClient { const BUFFER_LENGTH = 4096; /** * Resource. * * @var resource */ protected $resource; /** * Address. * * @var string */ protected $address; /** * Options used to create a stream context * @see http://php.net/manual/en/function.stream-context-create.php * * @var array */ protected $options; /** * Constructor takes address as argument. * * @param string $address */ public function __construct($address, $options = null) { $this->address = $address; $this->options = $options; } /** * Connect. * * @param integer $timeout Timeout for connection * @param boolean $persistent Persitent connection * @return void */ public function connect($timeout = 30, $persistent = false) { $flags = STREAM_CLIENT_CONNECT; if (true === $persistent) { $flags |= STREAM_CLIENT_PERSISTENT; } // call stream_socket_client with custom error handler enabled $handler = new ErrorHandler( function ($address, $timeout, $flags, array $options = null) { $errno = null; $errstr = null; if (!empty($options)) { $context = stream_context_create($options); return stream_socket_client($address, $errno, $errstr, $timeout, $flags, $context); } return stream_socket_client($address, $errno, $errstr, $timeout, $flags); }, $this->address, $timeout, $flags, $this->options ); $resource = $handler->execute(__FILE__, __LINE__); stream_set_timeout($resource, $timeout); $this->resource = $resource; } /** * Reconnect and optionally use different address. * * @param string $address * @param integer $timeout * @param bool $persistent */ public function reconnect($address = null, $timeout = 30, $persistent = false) { $this->close(); if (null !== $this->address) { $this->address = $address; } $this->connect($timeout, $persistent); } /** * Close stream. * * @return void */ public function close() { fclose($this->resource); } /** * Set stream blocking mode. * * @param boolean $flag Flag * @return $this */ public function setBlocking($flag = true) { stream_set_blocking($this->resource, (int)$flag); return $this; } /** * Read from stream. * * @param integer $length Bytes to read * @return string */ public function read($length = self::BUFFER_LENGTH) { return fread($this->resource, $length); } /** * Write to stream. * * @param string $string String * @param integer $length Limit * @return void */ public function write($string, $length = null) { if (null !== $length) { fwrite($this->resource, $string, $length); } else { fwrite($this->resource, $string); } } /** * Enable/disable cryptography on stream. * * @param boolean $enable Flag * @param integer $cryptoType One of the STREAM_CRYPTO_METHOD_* constants. * @return void * @throws InvalidArgumentException */ public function crypto($enable, $cryptoType = null) { if (false === $enable) { $handler = new ErrorHandler('stream_socket_enable_crypto', $this->resource, false); return $handler->execute(__FILE__, __LINE__); } if (null === $cryptoType) { throw new InvalidArgumentException('Second argument is require when enabling crypto an stream'); } return stream_socket_enable_crypto($this->resource, $enable, $cryptoType); } /** * Get socket stream. * * @return resource */ public function getResource() { return $this->resource; } /** * Return address. * * @return string */ public function getAddress() { return $this->address; } }