update PEAR

This commit is contained in:
Ibnu Maksum
2023-10-05 16:55:44 +07:00
parent 1861358415
commit 071df91de0
64 changed files with 3872 additions and 2100 deletions

View File

@ -2,6 +2,7 @@
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
@ -12,7 +13,7 @@
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -64,36 +65,52 @@ class Client
const FILTER_ALL = 3;
/**
* @var Communicator The communicator for this client.
* The communicator for this client.
*
* @var Communicator
*/
protected $com;
/**
* @var int The number of currently pending requests.
* The number of currently pending requests.
*
* @var int
*/
protected $pendingRequestsCount = 0;
/**
* @var array An array of responses that have not yet been extracted or
* passed to a callback. Key is the tag of the request, and the value
* is an array of associated responses.
* An array of responses that have not yet been extracted
* or passed to a callback.
*
* Key is the tag of the request, and the value is an array of
* associated responses.
*
* @var array<string,Response[]>
*/
protected $responseBuffer = array();
/**
* @var array An array of callbacks to be executed as responses come.
* Key is the tag of the request, and the value is the callback for it.
* An array of callbacks to be executed as responses come.
*
* Key is the tag of the request, and the value is the callback for it.
*
* @var array<string,callback>
*/
protected $callbacks = array();
/**
* @var Registry A registry for the operations. Particularly helpful at
* persistent connections.
* A registry for the operations.
*
* Particularly helpful at persistent connections.
*
* @var Registry
*/
protected $registry = null;
/**
* @var bool Whether to stream future responses.
* Whether to stream future responses.
*
* @var bool
*/
private $_streamingResponses = false;
@ -103,24 +120,25 @@ class Client
* Creates a new instance of a RouterOS API client with the specified
* settings.
*
* @param string $host Hostname (IP or domain) of the RouterOS server.
* @param string $username The RouterOS username.
* @param string $password The RouterOS password.
* @param int|null $port The port on which the RouterOS server provides
* the API service. You can also specify NULL, in which case the port
* will automatically be chosen between 8728 and 8729, depending on the
* value of $crypto.
* @param bool $persist Whether or not the connection should be a
* @param string $host Hostname (IP or domain) of RouterOS.
* @param string $username The RouterOS username.
* @param string $password The RouterOS password.
* @param int|null $port The port on which the RouterOS host
* provides the API service. You can also specify NULL, in which case
* the port will automatically be chosen between 8728 and 8729,
* depending on the value of $crypto.
* @param bool $persist Whether or not the connection should be a
* persistent one.
* @param float $timeout The timeout for the connection.
* @param string $crypto The encryption for this connection. Must be one
* of the PEAR2\Net\Transmitter\NetworkStream::CRYPTO_* constants. Off
* by default. RouterOS currently supports only TLS, but the setting is
* provided in this fashion for forward compatibility's sake. And for
* the sake of simplicity, if you specify an encryption, don't specify a
* context and your default context uses the value "DEFAULT" for
* ciphers, "ADH" will be automatically added to the list of ciphers.
* @param resource $context A context for the socket.
* @param double|null $timeout The timeout for the connection.
* @param string $crypto The encryption for this connection.
* Must be one of the PEAR2\Net\Transmitter\NetworkStream::CRYPTO_*
* constants. Off by default. RouterOS currently supports only TLS, but
* the setting is provided in this fashion for forward compatibility's
* sake. And for the sake of simplicity, if you specify an encryption,
* don't specify a context and your default context uses the value
* "DEFAULT" for ciphers, "ADH" will be automatically added to the list
* of ciphers.
* @param resource|null $context A context for the socket.
*
* @see sendSync()
* @see sendAsync()
@ -131,15 +149,10 @@ class Client
$password = '',
$port = 8728,
$persist = false,
$timeout = 10,
$timeout = null,
$crypto = N::CRYPTO_OFF,
$context = null
) {
if(strpos($host,":")>-1){
$part = explode(":",$host);
$host = $part[0];
$port = $part[1];
}
$this->com = new Communicator(
$host,
$port,
@ -183,7 +196,7 @@ class Client
* the class is invoked and its returned value is returned by this function.
*
* @param mixed $arg Value can be either a {@link Request} to send, which
* would be sent asynchoniously if it has a tag, and synchroniously if
* would be sent asynchronously if it has a tag, and synchronously if
* not, a number to loop with or NULL to complete all pending requests.
* Any other value is converted to string and treated as the tag of a
* request to complete.
@ -210,7 +223,7 @@ class Client
* @param string $username The RouterOS username.
* @param string $password The RouterOS password.
* @param int|null $timeout The time to wait for each response. NULL
* waits indefinetly.
* waits indefinitely.
*
* @return bool TRUE on success, FALSE on failure.
*/
@ -263,7 +276,7 @@ class Client
* @param string $password The RouterOS password. Potentially parsed
* already by iconv.
* @param int|null $timeout The time to wait for each response. NULL
* waits indefinetly.
* waits indefinitely.
*
* @return bool TRUE on success, FALSE on failure.
*/
@ -274,15 +287,31 @@ class Client
$timeout = null
) {
$request = new Request('/login');
// Update Mikrotik Versi terbaru
// sayangnya ini ngga aman, bagusnya di setup ke port SSL
$request->setArgument('name', $username);
$request->setArgument('password', $password);
$request->send($com);
$response = new Response($com, false, $timeout);
return $response->getType() === Response::TYPE_FINAL;
null === $response->getProperty('ret');
}
$request->setArgument('name', $username);
$request->setArgument('password', $password);
// $request->setArgument(
// 'response',
// '00' . md5(
// chr(0) . $password
// . pack('H*', $response->getProperty('ret'))
// )
// );
$request->verify($com)->send($com);
$response = new Response($com, false, $timeout);
if ($response->getType() === Response::TYPE_FINAL) {
return null === $response->getProperty('ret');
} else {
while ($response->getType() !== Response::TYPE_FINAL
&& $response->getType() !== Response::TYPE_FATAL
) {
$response = new Response($com, false, $timeout);
}
return false;
}
}
/**
* Sets the charset(s) for this connection.
@ -307,6 +336,7 @@ class Client
* @return string|array The old charset. If $charsetType is
* {@link Communicator::CHARSET_ALL}, the old values will be returned as
* an array with the types as keys, and charsets as values.
*
* @see Communicator::setDefaultCharset()
*/
public function setCharset(
@ -326,6 +356,7 @@ class Client
* @return string|array The current charset. If $charsetType is
* {@link Communicator::CHARSET_ALL}, the current values will be
* returned as an array with the types as keys, and charsets as values.
*
* @see setCharset()
*/
public function getCharset($charsetType)
@ -336,16 +367,18 @@ class Client
/**
* Sends a request and waits for responses.
*
* @param Request $request The request to send.
* @param callback $callback Optional. A function that is to be executed
* when new responses for this request are available. The callback takes
* two parameters. The {@link Response} object as the first, and the
* {@link Client} object as the second one. If the function returns
* TRUE, the request is canceled. Note that the callback may be executed
* one last time after that with a response that notifies about the
* canceling.
* @param Request $request The request to send.
* @param callback|null $callback Optional. A function that is to be
* executed when new responses for this request are available.
* The callback takes two parameters. The {@link Response} object as
* the first, and the {@link Client} object as the second one. If the
* callback returns TRUE, the request is canceled. Note that the
* callback may be executed at least two times after that. Once with a
* {@link Response::TYPE_ERROR} response that notifies about the
* canceling, plus the {@link Response::TYPE_FINAL} response.
*
* @return $this The client object.
*
* @see completeRequest()
* @see loop()
* @see cancelRequest()
@ -392,10 +425,11 @@ class Client
* pending request and/or has responses that are not yet extracted.
*
* @param string $tag The tag of the request to look for.
* @param int $filter One of the FILTER_* consntants. Limits the search
* @param int $filter One of the FILTER_* constants. Limits the search
* to the specified places.
*
* @return bool TRUE if the request is active, FALSE otherwise.
*
* @see getPendingRequestsCount()
* @see completeRequest()
*/
@ -417,6 +451,7 @@ class Client
* @param Request $request The request to send.
*
* @return ResponseCollection The received responses as a collection.
*
* @see sendAsync()
* @see close()
*/
@ -437,8 +472,8 @@ class Client
* Starts an event loop for the RouterOS callbacks and finishes when a
* specified request is completed.
*
* @param string $tag The tag of the request to complete. Setting NULL
* completes all requests.
* @param string|null $tag The tag of the request to complete.
* Setting NULL completes all requests.
*
* @return ResponseCollection A collection of {@link Response} objects that
* haven't been passed to a callback function or previously extracted
@ -481,11 +516,13 @@ class Client
* Gets all new responses for a request that haven't been passed to a
* callback and clears the buffer from them.
*
* @param string $tag The tag of the request to extract new responses for.
* @param string|null $tag The tag of the request to extract
* new responses for.
* Specifying NULL with extract new responses for all requests.
*
* @return ResponseCollection A collection of {@link Response} objects for
* the specified request.
*
* @see loop()
*/
public function extractNewResponses($tag = null)
@ -526,12 +563,13 @@ class Client
* are no more pending requests or when a specified timeout has passed
* (whichever comes first).
*
* @param int $sTimeout Timeout for the loop. If NULL, there is no time
* limit.
* @param int $usTimeout Microseconds to add to the time limit.
* @param int|null $sTimeout Timeout for the loop.
* If NULL, there is no time limit.
* @param int $usTimeout Microseconds to add to the time limit.
*
* @return bool TRUE when there are any more pending requests, FALSE
* otherwise.
*
* @see extractNewResponses()
* @see getPendingRequestsCount()
*/
@ -581,6 +619,7 @@ class Client
* Gets the number of pending requests.
*
* @return int The number of pending requests.
*
* @see isRequestActive()
*/
public function getPendingRequestsCount()
@ -592,15 +631,16 @@ class Client
* Cancels a request.
*
* Cancels an active request. Using this function in favor of a plain call
* to the "/cancel" command is highly reccomended, as it also updates the
* to the "/cancel" command is highly recommended, as it also updates the
* counter of pending requests properly. Note that canceling a request also
* removes any responses for it that were not previously extracted with
* {@link static::extractNewResponses()}.
*
* @param string $tag Tag of the request to cancel. Setting NULL will cancel
* all requests.
* @param string|null $tag Tag of the request to cancel.
* Setting NULL will cancel all requests.
*
* @return $this The client object.
*
* @see sendAsync()
* @see close()
*/
@ -671,6 +711,7 @@ class Client
* @param bool $streamingResponses Whether to stream future responses.
*
* @return bool The previous value of the setting.
*
* @see isStreamingResponses()
*/
public function setStreamingResponses($streamingResponses)
@ -686,6 +727,7 @@ class Client
* Gets whether future responses are streamed.
*
* @return bool The value of the setting.
*
* @see setStreamingResponses()
*/
public function isStreamingResponses()
@ -758,12 +800,13 @@ class Client
* @param Request $request The request to send.
*
* @return $this The client object.
*
* @see sendSync()
* @see sendAsync()
*/
protected function send(Request $request)
{
$request->send($this->com, $this->registry);
$request->verify($this->com)->send($this->com, $this->registry);
$this->pendingRequestsCount++;
return $this;
}
@ -774,9 +817,10 @@ class Client
* Dispatches the next response in queue, i.e. it executes the associated
* callback if there is one, or places the response in the response buffer.
*
* @param int $sTimeout If a response is not immediatly available, wait
* this many seconds. If NULL, wait indefinetly.
* @param int $usTimeout Microseconds to add to the waiting time.
* @param int|null $sTimeout If a response is not immediately available,
* wait this many seconds.
* If NULL, wait indefinitely.
* @param int $usTimeout Microseconds to add to the waiting time.
*
* @throws SocketException When there's no response within the time limit.
* @return Response The dispatched response.
@ -805,7 +849,14 @@ class Client
if ('' != $tag) {
if ($this->isRequestActive($tag, self::FILTER_CALLBACK)) {
if ($this->callbacks[$tag]($response, $this)) {
$this->cancelRequest($tag);
try {
$this->cancelRequest($tag);
} catch (DataFlowException $e) {
if ($e->getCode() !== DataFlowException::CODE_UNKNOWN_REQUEST
) {
throw $e;
}
}
} elseif ($isLastForRequest) {
unset($this->callbacks[$tag]);
}

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -27,13 +28,13 @@ use PEAR2\Net\Transmitter as T;
/**
* A RouterOS communicator.
*
*
* Implementation of the RouterOS API protocol. Unlike the other classes in this
* package, this class doesn't provide any conviniences beyond the low level
* package, this class doesn't provide any conveniences beyond the low level
* implementation details (automatic word length encoding/decoding, charset
* translation and data integrity), and because of that, its direct usage is
* strongly discouraged.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -47,67 +48,76 @@ class Communicator
* Used when getting/setting all (default) charsets.
*/
const CHARSET_ALL = -1;
/**
* Used when getting/setting the (default) remote charset.
*
*
* The remote charset is the charset in which RouterOS stores its data.
* If you want to keep compatibility with your Winbox, this charset should
* match the default charset from your Windows' regional settings.
*/
const CHARSET_REMOTE = 0;
/**
* Used when getting/setting the (default) local charset.
*
*
* The local charset is the charset in which the data from RouterOS will be
* returned as. This charset should match the charset of the place the data
* will eventually be written to.
*/
const CHARSET_LOCAL = 1;
/**
* @var array An array with the default charset types as keys, and the
* default charsets as values.
* An array with the default charset.
*
* Charset types as keys, and the default charsets as values.
*
* @var array<string,string|null>
*/
protected static $defaultCharsets = array(
self::CHARSET_REMOTE => null,
self::CHARSET_LOCAL => null
);
/**
* @var array An array with the current charset types as keys, and the
* current charsets as values.
* An array with the current charset.
*
* Charset types as keys, and the current charsets as values.
*
* @var array<string,string|null>
*/
protected $charsets = array();
/**
* @var T\TcpClient The transmitter for the connection.
* The transmitter for the connection.
*
* @var T\TcpClient
*/
protected $trans;
/**
* Creates a new connection with the specified options.
*
* @param string $host Hostname (IP or domain) of the RouterOS server.
* @param int|null $port The port on which the RouterOS server provides
* the API service. You can also specify NULL, in which case the port
* will automatically be chosen between 8728 and 8729, depending on the
* value of $crypto.
* @param bool $persist Whether or not the connection should be a
*
* @param string $host Hostname (IP or domain) of RouterOS.
* @param int|null $port The port on which the RouterOS host
* provides the API service. You can also specify NULL, in which case
* the port will automatically be chosen between 8728 and 8729,
* depending on the value of $crypto.
* @param bool $persist Whether or not the connection should be a
* persistent one.
* @param float $timeout The timeout for the connection.
* @param string $key A string that uniquely identifies the
* @param double|null $timeout The timeout for the connection.
* @param string $key A string that uniquely identifies the
* connection.
* @param string $crypto The encryption for this connection. Must be one
* of the PEAR2\Net\Transmitter\NetworkStream::CRYPTO_* constants. Off
* by default. RouterOS currently supports only TLS, but the setting is
* provided in this fashion for forward compatibility's sake. And for
* the sake of simplicity, if you specify an encryption, don't specify a
* context and your default context uses the value "DEFAULT" for
* ciphers, "ADH" will be automatically added to the list of ciphers.
* @param resource $context A context for the socket.
*
* @param string $crypto The encryption for this connection.
* Must be one of the PEAR2\Net\Transmitter\NetworkStream::CRYPTO_*
* constants. Off by default. RouterOS currently supports only TLS, but
* the setting is provided in this fashion for forward compatibility's
* sake. And for the sake of simplicity, if you specify an encryption,
* don't specify a context and your default context uses the value
* "DEFAULT" for ciphers, "ADH" will be automatically added to the list
* of ciphers.
* @param resource|null $context A context for the socket.
*
* @see sendWord()
*/
public function __construct(
@ -126,7 +136,16 @@ class Communicator
if (!isset($opts['ssl']['ciphers'])
|| 'DEFAULT' === $opts['ssl']['ciphers']
) {
stream_context_set_option($context, 'ssl', 'ciphers', 'ADH');
stream_context_set_option(
$context,
array(
'ssl' => array(
'ciphers' => 'ADH',
'verify_peer' => false,
'verify_peer_name' => false
)
)
);
}
}
// @codeCoverageIgnoreStart
@ -158,31 +177,31 @@ class Communicator
self::CHARSET_ALL
);
}
/**
* A shorthand gateway.
*
*
* This is a magic PHP method that allows you to call the object as a
* function. Depending on the argument given, one of the other functions in
* the class is invoked and its returned value is returned by this function.
*
* @param string $string A string of the word to send, or NULL to get the
* next word as a string.
*
*
* @param string|null $string A string of the word to send, or NULL to get
* the next word as a string.
*
* @return int|string If a string is provided, returns the number of bytes
* sent, otherwise retuns the next word as a string.
* sent, otherwise returns the next word as a string.
*/
public function __invoke($string = null)
{
return null === $string ? $this->getNextWord()
: $this->sendWord($string);
}
/**
* Checks whether a variable is a seekable stream resource.
*
*
* @param mixed $var The value to check.
*
*
* @return bool TRUE if $var is a seekable stream, FALSE otherwise.
*/
public static function isSeekableStream($var)
@ -193,16 +212,16 @@ class Communicator
}
return false;
}
/**
* Uses iconv to convert a stream from one charset to another.
*
*
* @param string $inCharset The charset of the stream.
* @param string $outCharset The desired resulting charset.
* @param resource $stream The stream to convert. The stream is assumed
* to be seekable, and is read from its current position to its end,
* after which, it is seeked back to its starting position.
*
*
* @return resource A new stream that uses the $out_charset. The stream is a
* subset from the original stream, from its current position to its
* end, seeked at its start.
@ -216,22 +235,25 @@ class Communicator
'convert.iconv.' . $inCharset . '.' . $outCharset,
STREAM_FILTER_WRITE
);
flock($stream, LOCK_SH);
while (!feof($stream)) {
$bytes += stream_copy_to_stream($stream, $result, 0xFFFFF);
$reader = new T\Stream($stream, false);
$writer = new T\Stream($result, false);
$chunkSize = $reader->getChunk(T\Stream::DIRECTION_RECEIVE);
while ($reader->isAvailable() && $reader->isDataAwaiting()) {
$bytes += $writer->send(fread($stream, $chunkSize));
}
fseek($stream, -$bytes, SEEK_CUR);
flock($stream, LOCK_UN);
stream_filter_remove($iconvFilter);
rewind($result);
return $result;
}
/**
* Sets the default charset(s) for new connections.
*
*
* @param mixed $charset The charset to set. If $charsetType is
* {@link self::CHARSET_ALL}, you can supply either a string to use for
* all charsets, or an array with the charset types as keys, and the
@ -239,10 +261,11 @@ class Communicator
* @param int $charsetType Which charset to set. Valid values are the
* CHARSET_* constants. Any other value is treated as
* {@link self::CHARSET_ALL}.
*
*
* @return string|array The old charset. If $charsetType is
* {@link self::CHARSET_ALL}, the old values will be returned as an
* array with the types as keys, and charsets as values.
*
* @see setCharset()
*/
public static function setDefaultCharset(
@ -263,17 +286,18 @@ class Communicator
return $oldCharsets;
}
}
/**
* Gets the default charset(s).
*
*
* @param int $charsetType Which charset to get. Valid values are the
* CHARSET_* constants. Any other value is treated as
* {@link self::CHARSET_ALL}.
*
*
* @return string|array The current charset. If $charsetType is
* {@link self::CHARSET_ALL}, the current values will be returned as an
* array with the types as keys, and charsets as values.
*
* @see setDefaultCharset()
*/
public static function getDefaultCharset($charsetType)
@ -284,12 +308,12 @@ class Communicator
/**
* Gets the length of a seekable stream.
*
*
* Gets the length of a seekable stream.
*
*
* @param resource $stream The stream to check. The stream is assumed to be
* seekable.
*
*
* @return double The number of bytes in the stream between its current
* position and its end.
*/
@ -302,17 +326,17 @@ class Communicator
fseek($stream, $streamPosition, SEEK_SET);
return $streamLength;
}
/**
* Sets the charset(s) for this connection.
*
*
* Sets the charset(s) for this connection. The specified charset(s) will be
* used for all future words. When sending, {@link self::CHARSET_LOCAL} is
* converted to {@link self::CHARSET_REMOTE}, and when receiving,
* {@link self::CHARSET_REMOTE} is converted to {@link self::CHARSET_LOCAL}.
* Setting NULL to either charset will disable charset convertion, and data
* Setting NULL to either charset will disable charset conversion, and data
* will be both sent and received "as is".
*
*
* @param mixed $charset The charset to set. If $charsetType is
* {@link self::CHARSET_ALL}, you can supply either a string to use for
* all charsets, or an array with the charset types as keys, and the
@ -320,10 +344,11 @@ class Communicator
* @param int $charsetType Which charset to set. Valid values are the
* CHARSET_* constants. Any other value is treated as
* {@link self::CHARSET_ALL}.
*
*
* @return string|array The old charset. If $charsetType is
* {@link self::CHARSET_ALL}, the old values will be returned as an
* array with the types as keys, and charsets as values.
*
* @see setDefaultCharset()
*/
public function setCharset($charset, $charsetType = self::CHARSET_ALL)
@ -342,17 +367,18 @@ class Communicator
return $oldCharsets;
}
}
/**
* Gets the charset(s) for this connection.
*
*
* @param int $charsetType Which charset to get. Valid values are the
* CHARSET_* constants. Any other value is treated as
* {@link self::CHARSET_ALL}.
*
*
* @return string|array The current charset. If $charsetType is
* {@link self::CHARSET_ALL}, the current values will be returned as an
* array with the types as keys, and charsets as values.
*
* @see getDefaultCharset()
* @see setCharset()
*/
@ -364,7 +390,7 @@ class Communicator
/**
* Gets the transmitter for this connection.
*
*
* @return T\TcpClient The transmitter for this connection.
*/
public function getTransmitter()
@ -374,12 +400,13 @@ class Communicator
/**
* Sends a word.
*
*
* Sends a word and automatically encodes its length when doing so.
*
*
* @param string $word The word to send.
*
*
* @return int The number of bytes sent.
*
* @see sendWordFromStream()
* @see getNextWord()
*/
@ -407,16 +434,17 @@ class Communicator
/**
* Sends a word based on a stream.
*
*
* Sends a word based on a stream and automatically encodes its length when
* doing so. The stream is read from its current position to its end, and
* then returned to its current position. Because of those operations, the
* supplied stream must be seekable.
*
*
* @param string $prefix A string to prepend before the stream contents.
* @param resource $stream The seekable stream to send.
*
*
* @return int The number of bytes sent.
*
* @see sendWord()
*/
public function sendWordFromStream($prefix, $stream)
@ -441,31 +469,31 @@ class Communicator
$stream
);
}
flock($stream, LOCK_SH);
$totalLength = strlen($prefix) + self::seekableStreamLength($stream);
static::verifyLengthSupport($totalLength);
$bytes = $this->trans->send(self::encodeLength($totalLength) . $prefix);
$bytes += $this->trans->send($stream);
flock($stream, LOCK_UN);
return $bytes;
}
/**
* Verifies that the length is supported.
*
*
* Verifies if the specified length is supported by the API. Throws a
* {@link LengthException} if that's not the case. Currently, RouterOS
* supports words up to 0xFFFFFFFF in length, so that's the only check
* performed.
*
*
* @param int $length The length to verify.
*
*
* @return void
*/
protected static function verifyLengthSupport($length)
public static function verifyLengthSupport($length)
{
if ($length > 0xFFFFFFFF) {
throw new LengthException(
@ -478,10 +506,10 @@ class Communicator
}
/**
* Encodes the length as requred by the RouterOS API.
*
* Encodes the length as required by the RouterOS API.
*
* @param int $length The length to encode.
*
*
* @return string The encoded length.
*/
public static function encodeLength($length)
@ -519,11 +547,12 @@ class Communicator
/**
* Get the next word in queue as a string.
*
*
* Get the next word in queue as a string, after automatically decoding its
* length.
*
*
* @return string The word.
*
* @see close()
*/
public function getNextWord()
@ -541,7 +570,7 @@ class Communicator
'word'
);
}
if (null !== ($remoteCharset = $this->getCharset(self::CHARSET_REMOTE))
&& null !== ($localCharset = $this->getCharset(self::CHARSET_LOCAL))
) {
@ -551,17 +580,18 @@ class Communicator
$word
);
}
return $word;
}
/**
* Get the next word in queue as a stream.
*
*
* Get the next word in queue as a stream, after automatically decoding its
* length.
*
*
* @return resource The word, as a stream.
*
* @see close()
*/
public function getNextWordAsStream()
@ -575,7 +605,7 @@ class Communicator
$remoteCharset . '.' . $localCharset . '//IGNORE//TRANSLIT'
);
}
if ($this->trans->isPersistent()) {
$old = $this->trans->lock(T\Stream::DIRECTION_RECEIVE);
$stream = $this->trans->receiveStream(
@ -591,20 +621,21 @@ class Communicator
'stream word'
);
}
return $stream;
}
/**
* Decodes the lenght of the incoming message.
*
* Decodes the lenght of the incoming message, as specified by the RouterOS
* Decodes the length of the incoming message.
*
* Decodes the length of the incoming message, as specified by the RouterOS
* API.
*
*
* @param T\Stream $trans The transmitter from which to decode the length of
* the incoming message.
*
* @return int The decoded length.
*
* @return int|double The decoded length.
* Is of type "double" only for values above "2 << 31".
*/
public static function decodeLength(T\Stream $trans)
{
@ -618,18 +649,19 @@ class Communicator
}
/**
* Decodes the lenght of the incoming message.
*
* Decodes the lenght of the incoming message, as specified by the RouterOS
* Decodes the length of the incoming message.
*
* Decodes the length of the incoming message, as specified by the RouterOS
* API.
*
*
* Difference with the non private function is that this one doesn't perform
* locking if the connection is a persistent one.
*
*
* @param T\Stream $trans The transmitter from which to decode the length of
* the incoming message.
*
* @return int The decoded length.
*
* @return int|double The decoded length.
* Is of type "double" only for values above "2 << 31".
*/
private static function _decodeLength(T\Stream $trans)
{
@ -661,7 +693,7 @@ class Communicator
/**
* Closes the opened connection, even if it is a persistent one.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function close()

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -27,7 +28,7 @@ use RuntimeException;
/**
* Exception thrown when the request/response cycle goes an unexpected way.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -22,7 +23,7 @@ namespace PEAR2\Net\RouterOS;
/**
* Generic exception class of this package.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -24,7 +25,7 @@ use InvalidArgumentException as I;
/**
* Exception thrown when there's something wrong with message arguments.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -25,9 +26,14 @@ namespace PEAR2\Net\RouterOS;
*/
use LengthException as L;
/**
* Used in $previous
*/
use Exception as E;
/**
* Exception thrown when there is a problem with a word's length.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -36,30 +42,31 @@ use LengthException as L;
*/
class LengthException extends L implements Exception
{
const CODE_UNSUPPORTED = 1200;
const CODE_INVALID = 1300;
const CODE_BEYOND_SHEME = 1301;
/**
* The problematic length.
*
* @var mixed The problematic length.
* @var int|double|null
*/
private $_length;
/**
* Creates a new LengthException.
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param \Exception $previous The previous exception used for the exception
* chaining.
* @param number $length The length.
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param E|null $previous The previous exception used for the
* exception chaining.
* @param int|double|null $length The length.
*/
public function __construct(
$message,
$code = 0,
$previous = null,
E $previous = null,
$length = null
) {
parent::__construct($message, $code, $previous);
@ -68,8 +75,8 @@ class LengthException extends L implements Exception
/**
* Gets the length.
*
* @return number The length.
*
* @return int|double|null The length.
*/
public function getLength()
{
@ -81,7 +88,7 @@ class LengthException extends L implements Exception
/**
* Returns a string representation of the exception.
*
*
* @return string The exception as a string.
*/
public function __toString()

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -31,13 +32,13 @@ use Countable;
use IteratorAggregate;
/**
* Requred for IteratorAggregate::getIterator() to work properly with foreach.
* Required for IteratorAggregate::getIterator() to work properly with foreach.
*/
use ArrayObject;
/**
* Represents a RouterOS message.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -48,27 +49,32 @@ abstract class Message implements IteratorAggregate, Countable
{
/**
* @var array An array with message attributes. Each array key is the the
* name of an attribute, and the correspding array value is the value
* for that attribute.
* An array with message attributes.
*
* Each array key is the the name of an attribute,
* and the corresponding array value is the value for that attribute.
*
* @var array<string,string|resource>
*/
protected $attributes = array();
/**
* @var string An optional tag to associate the message with.
* An optional tag to associate the message with.
*
* @var string
*/
private $_tag = null;
/**
* A shorthand gateway.
*
*
* This is a magic PHP method that allows you to call the object as a
* function. Depending on the argument given, one of the other functions in
* the class is invoked and its returned value is returned by this function.
*
* @param string $name The name of an attribute to get the value of, or NULL
* to get the tag.
*
*
* @param string|null $name The name of an attribute to get the value of,
* or NULL to get the tag.
*
* @return string|resource The value of the specified attribute,
* or the tag if NULL is provided.
*/
@ -82,9 +88,9 @@ abstract class Message implements IteratorAggregate, Countable
/**
* Sanitizes a name of an attribute (message or query one).
*
*
* @param mixed $name The name to sanitize.
*
*
* @return string The sanitized name.
*/
public static function sanitizeAttributeName($name)
@ -103,10 +109,10 @@ abstract class Message implements IteratorAggregate, Countable
/**
* Sanitizes a value of an attribute (message or query one).
*
*
* @param mixed $value The value to sanitize.
*
* @return string The sanitized value.
*
* @return string|resource The sanitized value.
*/
public static function sanitizeAttributeValue($value)
{
@ -119,8 +125,9 @@ abstract class Message implements IteratorAggregate, Countable
/**
* Gets the tag that the message is associated with.
*
*
* @return string The current tag or NULL if there isn't a tag.
*
* @see setTag()
*/
public function getTag()
@ -130,13 +137,14 @@ abstract class Message implements IteratorAggregate, Countable
/**
* Sets the tag to associate the request with.
*
*
* Sets the tag to associate the message with. Setting NULL erases the
* currently set tag.
*
*
* @param string $tag The tag to set.
*
*
* @return $this The message object.
*
* @see getTag()
*/
protected function setTag($tag)
@ -147,11 +155,12 @@ abstract class Message implements IteratorAggregate, Countable
/**
* Gets the value of an attribute.
*
*
* @param string $name The name of the attribute.
*
*
* @return string|resource|null The value of the specified attribute.
* Returns NULL if such an attribute is not set.
*
* @see setAttribute()
*/
protected function getAttribute($name)
@ -165,9 +174,10 @@ abstract class Message implements IteratorAggregate, Countable
/**
* Gets all arguments in an array.
*
*
* @return ArrayObject An ArrayObject with the keys being argument names,
* and the array values being argument values.
*
* @see getArgument()
* @see setArgument()
*/
@ -177,40 +187,30 @@ abstract class Message implements IteratorAggregate, Countable
}
/**
* Counts the number of arguments.
*
* @param int $mode The counter mode.
* Either COUNT_NORMAL or COUNT_RECURSIVE.
* When in normal mode, counts the number of arguments.
* When in recursive mode, counts the number of API words
* (including the empty word at the end).
*
* @return int The number of arguments/words.
* Counts the number of attributes.
*
* @return int The number of attributes.
*/
public function count($mode = COUNT_NORMAL)
public function count()
{
$result = count($this->attributes);
if ($mode !== COUNT_NORMAL) {
$result += 2/*first+last word*/
+ (int)(null !== $this->getTag());
}
return $result;
return count($this->attributes);
}
/**
* Sets an attribute for the message.
*
*
* @param string $name Name of the attribute.
* @param string|resource|null $value Value of the attribute as a string or
* seekable stream.
* Setting the value to NULL removes an argument of this name.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
*
*
* @return $this The message object.
*
* @see getArgument()
*/
protected function setAttribute($name, $value = '')
@ -226,7 +226,7 @@ abstract class Message implements IteratorAggregate, Countable
/**
* Removes all attributes from the message.
*
*
* @return $this The message object.
*/
protected function removeAllAttributes()

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -28,7 +29,7 @@ use Exception as E;
/**
* Exception thrown when encountering something not supported by RouterOS or
* this package.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -40,24 +41,30 @@ class NotSupportedException extends E implements Exception
const CODE_CONTROL_BYTE = 1601;
const CODE_MENU_MISMATCH = 60000;
const CODE_ARG_PROHIBITED = 60001;
/**
* @var mixed The unsuppported value.
* The unsupported value.
*
* @var mixed
*/
private $_value;
/**
* Creates a new NotSupportedException.
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param \Exception $previous The previous exception used for the exception
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param E|null $previous The previous exception used for the exception
* chaining.
* @param mixed $value The unsupported value.
* @param mixed $value The unsupported value.
*/
public function __construct(
$message,
$code = 0,
$previous = null,
E $previous = null,
$value = null
) {
parent::__construct($message, $code, $previous);
@ -66,7 +73,7 @@ class NotSupportedException extends E implements Exception
/**
* Gets the unsupported value.
*
*
* @return mixed The unsupported value.
*/
public function getValue()
@ -79,7 +86,7 @@ class NotSupportedException extends E implements Exception
/**
* Returns a string representation of the exception.
*
*
* @return string The exception as a string.
*/
public function __toString()

View File

@ -0,0 +1,43 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Base of this class.
*/
use DomainException;
/**
* Exception thrown when a value can't be parsed properly.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class ParserException extends DomainException implements Exception
{
const CODE_DATETIME = 1;
const CODE_DATEINTERVAL = 2;
const CODE_ARRAY = 3;
}

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -27,7 +28,7 @@ use PEAR2\Net\Transmitter as T;
/**
* Represents a query for RouterOS requests.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -41,31 +42,35 @@ class Query
* Checks if the property exists.
*/
const OP_EX = '';
/**
* Checks if the property does not exist.
*/
const OP_NEX = '-';
/**
* Checks if the property equals a certain value.
*/
const OP_EQ = '=';
/**
* Checks if the property is less than a certain value.
*/
const OP_LT = '<';
/**
* Checks if the property is greather than a certain value.
* Checks if the property is greater than a certain value.
*/
const OP_GT = '>';
/**
* @var array An array of the words forming the query. Each value is an
* array with the first member being the predicate (operator and name),
* and the second member being the value for the predicate.
* An array of the words forming the query.
*
* Each value is an array with the first member being the predicate
* (operator and name), and the second member being the value
* for the predicate.
*
* @var array<string,string|null>[]
*/
protected $words = array();
@ -73,16 +78,16 @@ class Query
* This class is not to be instantiated normally, but by static methods
* instead. Use {@link static::where()} to create an instance of it.
*/
private function __construct()
protected function __construct()
{
}
/**
* Sanitizes the operator of a condition.
*
*
* @param string $operator The operator to sanitize.
*
*
* @return string The sanitized operator.
*/
protected static function sanitizeOperator($operator)
@ -107,18 +112,18 @@ class Query
/**
* Creates a new query with an initial condition.
*
*
* @param string $name The name of the property to test.
* @param string|resource|null $value Value of the property as a string
* or seekable stream. Not required for existence tests.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
* @param string $operator One of the OP_* constants.
* Describes the operation to perform.
*
*
* @return static A new query object.
*/
public static function where(
@ -132,7 +137,7 @@ class Query
/**
* Negates the query.
*
*
* @return $this The query object.
*/
public function not()
@ -143,18 +148,18 @@ class Query
/**
* Adds a condition as an alternative to the query.
*
*
* @param string $name The name of the property to test.
* @param string|resource|null $value Value of the property as a string
* or seekable stream. Not required for existence tests.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
* @param string $operator One of the OP_* constants.
* Describes the operation to perform.
*
*
* @return $this The query object.
*/
public function orWhere($name, $value = null, $operator = self::OP_EX)
@ -165,18 +170,18 @@ class Query
/**
* Adds a condition in addition to the query.
*
*
* @param string $name The name of the property to test.
* @param string|resource|null $value Value of the property as a string
* or seekable stream. Not required for existence tests.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
* @param string $operator One of the OP_* constants.
* Describes the operation to perform.
*
*
* @return $this The query object.
*/
public function andWhere($name, $value = null, $operator = self::OP_EX)
@ -187,9 +192,9 @@ class Query
/**
* Sends the query over a communicator.
*
*
* @param Communicator $com The communicator to send the query over.
*
*
* @return int The number of bytes sent.
*/
public function send(Communicator $com)
@ -205,12 +210,12 @@ class Query
/**
* Sends the query over a communicator.
*
*
* The only difference with the non private equivalent is that this one does
* not do locking.
*
*
* @param Communicator $com The communicator to send the query over.
*
*
* @return int The number of bytes sent.
*/
private function _send(Communicator $com)
@ -239,20 +244,53 @@ class Query
return $bytes;
}
/**
* Verifies the query.
*
* Verifies the query against a communicator, i.e. whether the query
* could successfully be sent (assuming the connection is still opened).
*
* @param Communicator $com The Communicator to check against.
*
* @return $this The query object itself.
*
* @throws LengthException If the resulting length of an API word is not
* supported.
*/
public function verify(Communicator $com)
{
foreach ($this->words as $queryWord) {
list($predicate, $value) = $queryWord;
if (null === $value) {
$com::verifyLengthSupport(strlen('?' . $predicate));
} elseif (is_string($value)) {
$com::verifyLengthSupport(
strlen('?' . $predicate . '=' . $value)
);
} else {
$com::verifyLengthSupport(
strlen('?' . $predicate . '=') +
$com::seekableStreamLength($value)
);
}
}
return $this;
}
/**
* Adds a condition.
*
*
* @param string $name The name of the property to test.
* @param string|resource|null $value Value of the property as a string
* or seekable stream. Not required for existence tests.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
* @param string $operator One of the ACTION_* constants.
* Describes the operation to perform.
*
*
* @return $this The query object.
*/
protected function addWhere($name, $value, $operator)

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -27,12 +28,12 @@ use PEAR2\Cache\SHM;
/**
* A RouterOS registry.
*
*
* Provides functionality for managing the request/response flow. Particularly
* useful in persistent connections.
*
*
* Note that this class is not meant to be called directly.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -42,28 +43,36 @@ use PEAR2\Cache\SHM;
class Registry
{
/**
* @var SHM The storage.
* The storage.
*
* @var SHM
*/
protected $shm;
/**
* @var int ID of request. Populated at first instance in request.
* ID of request. Populated at first instance in request.
*
* @var int
*/
protected static $requestId = -1;
/**
* @var int ID to be given to next instance, after incrementing it.
* ID to be given to next instance, after incrementing it.
*
* @var int
*/
protected static $instanceIdSeed = -1;
/**
* @var int ID of instance within the request.
* ID of instance within the request.
*
* @var int
*/
protected $instanceId;
/**
* Creates a registry.
*
*
* @param string $uri An URI to bind the registry to.
*/
public function __construct($uri)
@ -76,16 +85,17 @@ class Registry
$this->instanceId = ++self::$instanceIdSeed;
$this->shm->add('responseBuffer_' . $this->getOwnershipTag(), array());
}
/**
* Parses a tag.
*
*
* Parses a tag to reveal the ownership part of it, and the original tag.
*
*
* @param string $tag The tag (as received) to parse.
*
* @return array An array with the first member being the ownership tag, and
* the second one being the original tag.
*
* @return array<int,string|null> An array with
* the first member being the ownership tag, and
* the second one being the original tag.
*/
public static function parseTag($tag)
{
@ -99,10 +109,10 @@ class Registry
}
return $result;
}
/**
* Checks if this instance is the tagless mode owner.
*
*
* @return bool TRUE if this instance is the tagless mode owner, FALSE
* otherwise.
*/
@ -114,21 +124,21 @@ class Registry
$this->shm->unlock('taglessModeOwner');
return $result;
}
/**
* Sets the "tagless mode" setting.
*
* While in tagless mode, this instance will claim owhership of any
*
* While in tagless mode, this instance will claim ownership of any
* responses without a tag. While not in this mode, any requests without a
* tag will be given to all instances.
*
*
* Regardless of mode, if the type of the response is
* {@link Response::TYPE_FATAL}, it will be given to all instances.
*
*
* @param bool $taglessMode TRUE to claim tagless ownership, FALSE to
* release such ownership, if taken.
*
* @return bool TRUE on success, FALSE on failure.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function setTaglessMode($taglessMode)
{
@ -143,26 +153,26 @@ class Registry
&& $this->shm->unlock('taglessModeOwner')
&& $this->shm->unlock('taglessMode'));
}
/**
* Get the ownership tag for this instance.
*
* @return string The ownership tag for this registry instance.
*
* @return string The ownership tag for this registry instance.
*/
public function getOwnershipTag()
{
return self::$requestId . '_' . $this->instanceId . '__';
}
/**
* Add a response to the registry.
*
*
* @param Response $response The response to add. The caller of this
* function is responsible for ensuring that the ownership tag and the
* original tag are separated, so that only the original one remains in
* the response.
* @param string $ownershipTag The ownership tag that the response had.
*
*
* @return bool TRUE if the request was added to its buffer, FALSE if
* this instance owns the response, and therefore doesn't need to add
* the response to its buffer.
@ -175,7 +185,7 @@ class Registry
) {
return false;
}
if (null === $ownershipTag) {
$this->shm->lock('taglessModeOwner');
if ($this->shm->exists('taglessModeOwner')
@ -194,18 +204,18 @@ class Registry
return true;
}
}
$this->_add($response, 'responseBuffer_' . $ownershipTag);
return true;
}
/**
* Adds a response to a buffer.
*
*
* @param Response $response The response to add.
* @param string $targetBufferName The name of the buffer to add the
* response to.
*
*
* @return void
*/
private function _add(Response $response, $targetBufferName)
@ -217,11 +227,11 @@ class Registry
$this->shm->unlock($targetBufferName);
}
}
/**
* Gets the next response from this instance's buffer.
*
* @return Response|null The next response, or NULL if there isn't one.
*
* @return Response|null The next response, or NULL if there isn't one.
*/
public function getNextResponse()
{
@ -239,13 +249,13 @@ class Registry
}
return $response;
}
/**
* Closes the registry.
*
*
* Closes the registry, meaning that all buffers are cleared.
*
* @return void
*
* @return void
*/
public function close()
{
@ -253,12 +263,12 @@ class Registry
self::$instanceIdSeed = -1;
$this->shm->clear();
}
/**
* Removes a buffer.
*
*
* @param string $targetBufferName The buffer to remove.
*
*
* @return void
*/
private function _close($targetBufferName)
@ -268,9 +278,9 @@ class Registry
$this->shm->unlock($targetBufferName);
}
}
/**
* Removes this instance's buffer.
* Removes this instance's buffer.
*/
public function __destruct()
{

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -27,7 +28,7 @@ use PEAR2\Net\Transmitter as T;
/**
* Represents a RouterOS request.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -38,23 +39,27 @@ class Request extends Message
{
/**
* @var string The command to be executed.
* The command to be executed.
*
* @var string
*/
private $_command;
/**
* @var Query A query for the command.
* A query for the command.
*
* @var Query
*/
private $_query;
/**
* Creates a request to send to RouterOS.
*
* @param string $command The command to send. Can also contain arguments
* expressed in a shell-like syntax.
* @param Query $query A query to associate with the request.
* @param string $tag The tag for the request.
*
*
* @param string $command The command to send.
* Can also contain arguments expressed in a shell-like syntax.
* @param Query|null $query A query to associate with the request.
* @param string|null $tag The tag for the request.
*
* @see setCommand()
* @see setArgument()
* @see setTag()
@ -75,20 +80,20 @@ class Request extends Message
$this->setQuery($query);
$this->setTag($tag);
}
/**
* A shorthand gateway.
*
*
* This is a magic PHP method that allows you to call the object as a
* function. Depending on the argument given, one of the other functions in
* the class is invoked and its returned value is returned by this function.
*
*
* @param Query|Communicator|string|null $arg A {@link Query} to associate
* the request with, a {@link Communicator} to send the request over,
* an argument to get the value of, or NULL to get the tag. If a
* second argument is provided, this becomes the name of the argument to
* set the value of, and the second argument is the value to set.
*
*
* @return string|resource|int|$this Whatever the long form
* function returns.
*/
@ -108,14 +113,15 @@ class Request extends Message
/**
* Sets the command to send to RouterOS.
*
*
* Sets the command to send to RouterOS. The command can use the API or CLI
* syntax of RouterOS, but either way, it must be absolute (begin with a
* "/") and without arguments.
*
*
* @param string $command The command to send.
*
*
* @return $this The request object.
*
* @see getCommand()
* @see setArgument()
*/
@ -161,10 +167,11 @@ class Request extends Message
/**
* Gets the command that will be send to RouterOS.
*
*
* Gets the command that will be send to RouterOS in its API syntax.
*
*
* @return string The command to send.
*
* @see setCommand()
*/
public function getCommand()
@ -174,11 +181,12 @@ class Request extends Message
/**
* Sets the query to send with the command.
*
* @param Query $query The query to be set. Setting NULL will remove the
* currently associated query.
*
*
* @param Query|null $query The query to be set.
* Setting NULL will remove the currently associated query.
*
* @return $this The request object.
*
* @see getQuery()
*/
public function setQuery(Query $query = null)
@ -189,8 +197,9 @@ class Request extends Message
/**
* Gets the currently associated query
*
* @return Query The currently associated query.
*
* @return Query|null The currently associated query.
*
* @see setQuery()
*/
public function getQuery()
@ -200,13 +209,14 @@ class Request extends Message
/**
* Sets the tag to associate the request with.
*
*
* Sets the tag to associate the request with. Setting NULL erases the
* currently set tag.
*
* @param string $tag The tag to set.
*
*
* @param string|null $tag The tag to set.
*
* @return $this The request object.
*
* @see getTag()
*/
public function setTag($tag)
@ -216,18 +226,19 @@ class Request extends Message
/**
* Sets an argument for the request.
*
*
* @param string $name Name of the argument.
* @param string|resource|null $value Value of the argument as a string or
* seekable stream.
* Setting the value to NULL removes an argument of this name.
* If a seekable stream is provided, it is sent from its current
* posistion to its end, and the pointer is seeked back to its current
* position to its end, and the pointer is seeked back to its current
* position after sending.
* Non seekable streams, as well as all other types, are casted to a
* string.
*
*
* @return $this The request object.
*
* @see getArgument()
*/
public function setArgument($name, $value = '')
@ -237,11 +248,12 @@ class Request extends Message
/**
* Gets the value of an argument.
*
*
* @param string $name The name of the argument.
*
*
* @return string|resource|null The value of the specified argument.
* Returns NULL if such an argument is not set.
*
* @see setAttribute()
*/
public function getArgument($name)
@ -251,7 +263,7 @@ class Request extends Message
/**
* Removes all arguments from the request.
*
*
* @return $this The request object.
*/
public function removeAllArguments()
@ -261,11 +273,12 @@ class Request extends Message
/**
* Sends a request over a communicator.
*
* @param Communicator $com The communicator to send the request over.
* @param Registry $reg An optional registry to sync the request with.
*
*
* @param Communicator $com The communicator to send the request over.
* @param Registry|null $reg An optional registry to sync the request with.
*
* @return int The number of bytes sent.
*
* @see Client::sendSync()
* @see Client::sendAsync()
*/
@ -291,13 +304,14 @@ class Request extends Message
/**
* Sends a request over a communicator.
*
*
* The only difference with the non private equivalent is that this one does
* not do locking.
*
*
* @param Communicator $com The communicator to send the request over.
*
*
* @return int The number of bytes sent.
*
* @see Client::sendSync()
* @see Client::sendAsync()
*/
@ -329,19 +343,53 @@ class Request extends Message
$bytes += $com->sendWord('');
return $bytes;
}
/**
* Verifies the request.
*
* Verifies the request against a communicator, i.e. whether the request
* could successfully be sent (assuming the connection is still opened).
*
* @param Communicator $com The Communicator to check against.
*
* @return $this The request object itself.
*
* @throws LengthException If the resulting length of an API word is not
* supported.
*/
public function verify(Communicator $com)
{
$com::verifyLengthSupport(strlen($this->getCommand()));
$com::verifyLengthSupport(strlen('.tag=' . (string)$this->getTag()));
foreach ($this->attributes as $name => $value) {
if (is_string($value)) {
$com::verifyLengthSupport(strlen('=' . $name . '=' . $value));
} else {
$com::verifyLengthSupport(
strlen('=' . $name . '=') +
$com::seekableStreamLength($value)
);
}
}
$query = $this->getQuery();
if ($query instanceof Query) {
$query->verify($com);
}
return $this;
}
/**
* Parses the arguments of a command.
*
*
* @param string $string The argument string to parse.
*
*
* @return void
*/
protected function parseArgumentString($string)
{
/*
* Grammar:
*
*
* <arguments> := (<<\s+>>, <argument>)*,
* <argument> := <name>, <value>?
* <name> := <<[^\=\s]+>>
@ -349,7 +397,7 @@ class Request extends Message
* <quotedString> := <<">>, <<([^"]|\\"|\\\\)*>>, <<">>
* <unquotedString> := <<\S+>>
*/
$token = '';
$name = null;
while ($string = substr($string, strlen($token))) {
@ -394,10 +442,10 @@ class Request extends Message
);
}
}
if (null !== $name && ('' !== ($name = trim($name)))) {
$this->setArgument($name, '');
}
}
}

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -32,7 +33,7 @@ use Exception as E;
/**
* Represents a RouterOS response.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -41,22 +42,22 @@ use Exception as E;
*/
class Response extends Message
{
/**
* The last response for a request.
*/
const TYPE_FINAL = '!done';
/**
* A response with data.
*/
const TYPE_DATA = '!re';
/**
* A response signifying error.
*/
const TYPE_ERROR = '!trap';
/**
* A response signifying a fatal error, due to which the connection would be
* terminated.
@ -64,28 +65,32 @@ class Response extends Message
const TYPE_FATAL = '!fatal';
/**
* @var array An array of unrecognized words in network order.
* An array of unrecognized words in network order.
*
* @var string[]
*/
protected $unrecognizedWords = array();
/**
* @var string The response type.
* The response type.
*
* @var string
*/
private $_type;
/**
* Extracts a new response from a communicator.
*
* @param Communicator $com The communicator from which to extract
*
* @param Communicator $com The communicator from which to extract
* the new response.
* @param bool $asStream Whether to populate the argument values
* @param bool $asStream Whether to populate the argument values
* with streams instead of strings.
* @param int $sTimeout If a response is not immediatly
* available, wait this many seconds. If NULL, wait indefinetly.
* @param int $usTimeout Microseconds to add to the waiting time.
* @param Registry $reg An optional registry to sync the
* @param int $sTimeout If a response is not immediately
* available, wait this many seconds. If NULL, wait indefinitely.
* @param int|null $usTimeout Microseconds to add to the waiting time.
* @param Registry|null $reg An optional registry to sync the
* response with.
*
*
* @see getType()
* @see getArgument()
*/
@ -120,12 +125,12 @@ class Response extends Message
break;
}
}
$this->_type = $response->_type;
$this->attributes = $response->attributes;
$this->unrecognizedWords = $response->unrecognizedWords;
$this->setTag($response->getTag());
if (!$asStream) {
foreach ($this->attributes as $name => $value) {
$this->setAttribute(
@ -139,23 +144,23 @@ class Response extends Message
}
}
}
/**
* Extracts a new response from a communicator.
*
*
* This is the function that performs the actual receiving, while the
* constructor is also involved in locks and registry sync.
*
*
* @param Communicator $com The communicator from which to extract
* the new response.
* @param bool $asStream Whether to populate the argument values
* with streams instead of strings.
* @param int $sTimeout If a response is not immediatly
* available, wait this many seconds. If NULL, wait indefinetly.
* @param int $sTimeout If a response is not immediately
* available, wait this many seconds. If NULL, wait indefinitely.
* Note that if an empty sentence is received, the timeout will be
* reset for another sentence receiving.
* @param int $usTimeout Microseconds to add to the waiting time.
*
* @param int|null $usTimeout Microseconds to add to the waiting time.
*
* @return void
*/
private function _receive(
@ -228,12 +233,13 @@ class Response extends Message
/**
* Sets the response type.
*
*
* Sets the response type. Valid values are the TYPE_* constants.
*
*
* @param string $type The new response type.
*
*
* @return $this The response object.
*
* @see getType()
*/
protected function setType($type)
@ -257,8 +263,9 @@ class Response extends Message
/**
* Gets the response type.
*
*
* @return string The response type.
*
* @see setType()
*/
public function getType()
@ -268,12 +275,13 @@ class Response extends Message
/**
* Gets the value of an argument.
*
*
* @param string $name The name of the argument.
*
*
* @return string|resource|null The value of the specified argument.
* Returns NULL if such an argument is not set.
* @deprecated 1.0.0b5 Use {@link static::getProperty()} instead.
*
* @deprecated 1.0.0b5 Use {@link static::getProperty()} instead.
* This method will be removed upon final release, and is currently
* left standing merely because it can't be easily search&replaced in
* existing code, due to the fact the name "getArgument()" is shared
@ -293,9 +301,9 @@ class Response extends Message
/**
* Gets the value of a property.
*
*
* @param string $name The name of the property.
*
*
* @return string|resource|null The value of the specified property.
* Returns NULL if such a property is not set.
*/
@ -306,30 +314,11 @@ class Response extends Message
/**
* Gets a list of unrecognized words.
*
* @return array The list of unrecognized words.
*
* @return string[] The list of unrecognized words.
*/
public function getUnrecognizedWords()
{
return $this->unrecognizedWords;
}
/**
* Counts the number of arguments or words.
*
* @param int $mode The counter mode.
* Either COUNT_NORMAL or COUNT_RECURSIVE.
* When in normal mode, counts the number of arguments.
* When in recursive mode, counts the number of API words.
*
* @return int The number of arguments/words.
*/
public function count($mode = COUNT_NORMAL)
{
$result = parent::count($mode);
if ($mode !== COUNT_NORMAL) {
$result += count($this->unrecognizedWords);
}
return $result;
}
}

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -37,13 +38,13 @@ use SeekableIterator;
/**
* Represents a collection of RouterOS responses.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*
*
* @method string getType()
* Calls {@link Response::getType()}
* on the response pointed by the pointer.
@ -59,61 +60,88 @@ use SeekableIterator;
*/
class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
{
/**
* @var array An array with all {@link Response} objects.
* An array with all {@link Response} objects.
*
* An array with all Response objects.
*
* @var Response[]
*/
protected $responses = array();
/**
* @var array An array with each {@link Response} object's type.
* An array with each Response object's type.
*
* An array with each {@link Response} object's type.
*
* @var string[]
*/
protected $responseTypes = array();
/**
* @var array An array with each {@link Response} object's tag.
* An array with each Response object's tag.
*
* An array with each {@link Response} object's tag.
*
* @var string[]
*/
protected $responseTags = array();
/**
* @var array An array with positions of responses, based on an property
* name. The name of each property is the array key, and the array value
* is another array where the key is the value for that property, and
* the value is the posistion of the response. For performance reasons,
* each key is built only when {@link static::setIndex()} is called with
* that property, and remains available for the lifetime of this
* collection.
* An array with positions of responses, based on an property name.
*
* The name of each property is the array key, and the array value
* is another array where the key is the value for that property, and
* the value is the position of the response. For performance reasons,
* each key is built only when {@link static::setIndex()} is called with
* that property, and remains available for the lifetime of this collection.
*
* @var array<string,array<string,int>>
*/
protected $responsesIndex = array();
/**
* @var array An array with all distinct properties across all
* {@link Response} objects. Created at the first call of
* {@link static::getPropertyMap()}.
* An array with all distinct properties.
*
* An array with all distinct properties across all {@link Response}
* objects. Created at the first call of {@link static::getPropertyMap()}.
*
* @var array<string,int[]>
*/
protected $propertyMap = null;
/**
* @var int A pointer, as required by SeekableIterator.
* A pointer, as required by SeekableIterator.
*
* @var int
*/
protected $position = 0;
/**
* @var string|null Name of property to use as index. NULL when disabled.
* Name of property to use as index
*
* NULL when disabled.
*
* @var string|null
*/
protected $index = null;
/**
* @var array Criterias used by {@link compare()} to determine the order
* between two respones. See {@link orderBy()} for a detailed
* description of this array's format.
* Compare criteria.
*
* Used by {@link static::compare()} to determine the order between
* two responses. See {@link static::orderBy()} for a detailed description
* of this array's format.
*
* @var string[]|array<string,null|int|array<int|callable>>
*/
protected $compareBy = array();
/**
* Creates a new collection.
*
* @param array $responses An array of responses, in network order.
*
* @param Response[] $responses An array of responses, in network order.
*/
public function __construct(array $responses)
{
@ -129,16 +157,16 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* A shorthand gateway.
*
*
* This is a magic PHP method that allows you to call the object as a
* function. Depending on the argument given, one of the other functions in
* the class is invoked and its returned value is returned by this function.
*
*
* @param int|string|null $offset The offset of the response to seek to.
* If the offset is negative, seek to that relative to the end.
* If the collection is indexed, you can also supply a value to seek to.
* Setting NULL will get the current response's interator.
*
* Setting NULL will get the current response's iterator.
*
* @return Response|ArrayObject The {@link Response} at the specified
* offset, the current response's iterator (which is an ArrayObject)
* when NULL is given, or FALSE if the offset is invalid
@ -153,15 +181,15 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Sets a property to be usable as a key in the collection.
*
*
* @param string|null $name The name of the property to use. Future calls
* that accept a position will then also be able to search values of
* that property for a matching value.
* Specifying NULL will disable such lookups (as is by default).
* Note that in case this value occures multiple times within the
* Note that in case this value occurs multiple times within the
* collection, only the last matching response will be accessible by
* that value.
*
*
* @return $this The object itself.
*/
public function setIndex($name)
@ -184,7 +212,7 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Gets the name of the property used as an index.
*
*
* @return string|null Name of property used as index. NULL when disabled.
*/
public function getIndex()
@ -194,11 +222,11 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Gets the whole collection as an array.
*
*
* @param bool $useIndex Whether to use the index values as keys for the
* resulting array.
*
* @return array An array with all responses, in network order.
*
* @return Response[] An array with all responses, in network order.
*/
public function toArray($useIndex = false)
{
@ -215,35 +243,22 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
}
/**
* Counts the responses/words in the collection.
*
* @param int $mode The counter mode.
* Either COUNT_NORMAL or COUNT_RECURSIVE.
* When in normal mode, counts the number of responses.
* When in recursive mode, counts the total number of API words.
*
* Counts the responses in the collection.
*
* @return int The number of responses in the collection.
*/
public function count($mode = COUNT_NORMAL)
public function count()
{
if ($mode !== COUNT_NORMAL) {
$result = 0;
foreach ($this->responses as $response) {
$result += $response->count($mode);
}
return $result;
} else {
return count($this->responses);
}
return count($this->responses);
}
/**
* Checks if an offset exists.
*
*
* @param int|string $offset The offset to check. If the
* collection is indexed, you can also supply a value to check.
* Note that negative numeric offsets are NOT accepted.
*
*
* @return bool TRUE if the offset exists, FALSE otherwise.
*/
public function offsetExists($offset)
@ -255,10 +270,10 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Gets a {@link Response} from a specified offset.
*
*
* @param int|string $offset The offset of the desired response. If the
* collection is indexed, you can also supply the value to search for.
*
*
* @return Response The response at the specified offset.
*/
public function offsetGet($offset)
@ -272,42 +287,44 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* N/A
*
*
* This method exists only because it is required for ArrayAccess. The
* collection is read only.
*
*
* @param int|string $offset N/A
* @param Response $value N/A
*
*
* @return void
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function offsetSet($offset, $value)
{
}
/**
* N/A
*
*
* This method exists only because it is required for ArrayAccess. The
* collection is read only.
*
*
* @param int|string $offset N/A
*
*
* @return void
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function offsetUnset($offset)
{
}
/**
* Resets the pointer to 0, and returns the first response.
*
* @return Response The first response in the collection, or FALSE if the
* collection is empty.
*
* @return Response|false The first response in the collection,
* or FALSE if the collection is empty.
*/
public function rewind()
{
@ -316,13 +333,13 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Moves the position pointer to a specified position.
*
*
* @param int|string $position The position to move to. If the collection is
* indexed, you can also supply a value to move the pointer to.
* A non-existent index will move the pointer to "-1".
*
* @return Response The {@link Response} at the specified position, or FALSE
* if the specified position is not valid.
*
* @return Response|false The {@link Response} at the specified position,
* or FALSE if the specified position is not valid.
*/
public function seek($position)
{
@ -338,9 +355,9 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Moves the pointer forward by 1, and gets the next response.
*
* @return Response The next {@link Response} object, or FALSE if the
* position is not valid.
*
* @return Response|false The next {@link Response} object,
* or FALSE if the position is not valid.
*/
public function next()
{
@ -350,9 +367,9 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Gets the response at the current pointer position.
*
* @return Response The response at the current pointer position, or FALSE
* if the position is not valid.
*
* @return Response|false The response at the current pointer position,
* or FALSE if the position is not valid.
*/
public function current()
{
@ -361,9 +378,9 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Moves the pointer backwards by 1, and gets the previous response.
*
* @return Response The next {@link Response} object, or FALSE if the
* position is not valid.
*
* @return Response|false The next {@link Response} object,
* or FALSE if the position is not valid.
*/
public function prev()
{
@ -374,9 +391,9 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Moves the pointer to the last valid position, and returns the last
* response.
*
* @return Response The last response in the collection, or FALSE if the
* collection is empty.
*
* @return Response|false The last response in the collection,
* or FALSE if the collection is empty.
*/
public function end()
{
@ -386,9 +403,10 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Gets the key at the current pointer position.
*
* @return int The key at the current pointer position, i.e. the pointer
* position itself, or FALSE if the position is not valid.
*
* @return int|false The key at the current pointer position,
* i.e. the pointer position itself, or FALSE if the position
* is not valid.
*/
public function key()
{
@ -397,7 +415,7 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Checks if the pointer is still pointing to an existing offset.
*
*
* @return bool TRUE if the pointer is valid, FALSE otherwise.
*/
public function valid()
@ -407,11 +425,12 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Gets all distinct property names.
*
*
* Gets all distinct property names across all responses.
*
* @return array An array with all distinct property names as keys, and the
* indexes at which they occur as values.
*
* @return array<string,int[]> An array with
* all distinct property names as keys, and
* the indexes at which they occur as values.
*/
public function getPropertyMap()
{
@ -433,10 +452,10 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Gets all responses of a specified type.
*
*
* @param string $type The response type to filter by. Valid values are the
* Response::TYPE_* constants.
*
*
* @return static A new collection with responses of the
* specified type.
*/
@ -451,9 +470,9 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Gets all responses with a specified tag.
*
*
* @param string $tag The tag to filter by.
*
*
* @return static A new collection with responses having the
* specified tag.
*/
@ -468,8 +487,9 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Order resones by criteria.
*
* @param mixed[] $criteria The criteria to order respones by. It takes the
*
* @param string[]|array<string,null|int|array<int|callable>> $criteria The
* criteria to order responses by. It takes the
* form of an array where each key is the name of the property to use
* as (N+1)th sorting key. The value of each member can be either NULL
* (for that property, sort normally in ascending order), a single sort
@ -479,12 +499,12 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
* array functions) or a callback.
* If a callback is provided, it must accept two arguments
* (the two values to be compared), and return -1, 0 or 1 if the first
* value is respectively less than, equal to or greather than the second
* value is respectively less than, equal to or greater than the second
* one.
* Each key of $criteria can also be numeric, in which case the
* value is the name of the property, and sorting is done normally in
* ascending order.
*
*
* @return static A new collection with the responses sorted in the
* specified order.
*/
@ -498,14 +518,14 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
/**
* Calls a method of the response pointed by the pointer.
*
*
* Calls a method of the response pointed by the pointer. This is a magic
* PHP method, thanks to which any function you call on the collection that
* is not defined will be redirected to the response.
*
*
* @param string $method The name of the method to call.
* @param array $args The arguments to pass to the method.
*
*
* @return mixed Whatever the called function returns.
*/
public function __call($method, array $args)
@ -517,15 +537,15 @@ class ResponseCollection implements ArrayAccess, SeekableIterator, Countable
}
/**
* Compares two respones.
*
* Compares two respones, based on criteria defined in
* Compares two responses.
*
* Compares two responses, based on criteria defined in
* {@link static::$compareBy}.
*
*
* @param Response $itemA The response to compare.
* @param Response $itemB The response to compare $a against.
*
* @return int Returns 0 if the two respones are equal according to every
*
* @return int Returns 0 if the two responses are equal according to every
* criteria specified, -1 if $a should be placed before $b, and 1 if $b
* should be placed before $a.
*/

View File

@ -0,0 +1,127 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Base of this class.
*/
use RuntimeException;
/**
* Refered to in the constructor.
*/
use Exception as E;
/**
* Exception thrown by higher level classes (Util, etc.) when the router
* returns an error.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class RouterErrorException extends RuntimeException implements Exception
{
const CODE_ITEM_ERROR = 0x100000;
const CODE_SCRIPT_ERROR = 0x200000;
const CODE_READ_ERROR = 0x010000;
const CODE_WRITE_ERROR = 0x020000;
const CODE_EXEC_ERROR = 0x040000;
const CODE_CACHE_ERROR = 0x100001;
const CODE_GET_ERROR = 0x110001;
const CODE_GETALL_ERROR = 0x110002;
const CODE_ADD_ERROR = 0x120001;
const CODE_SET_ERROR = 0x120002;
const CODE_REMOVE_ERROR = 0x120004;
const CODE_ENABLE_ERROR = 0x120012;
const CODE_DISABLE_ERROR = 0x120022;
const CODE_COMMENT_ERROR = 0x120042;
const CODE_UNSET_ERROR = 0x120082;
const CODE_MOVE_ERROR = 0x120107;
const CODE_SCRIPT_ADD_ERROR = 0x220001;
const CODE_SCRIPT_REMOVE_ERROR = 0x220004;
const CODE_SCRIPT_RUN_ERROR = 0x240001;
const CODE_SCRIPT_FILE_ERROR = 0x240003;
/**
* The complete response returned by the router.
*
* NULL when the router was not contacted at all.
*
* @var ResponseCollection|null
*/
private $_responses = null;
/**
* Creates a new RouterErrorException.
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param E|null $previous The previous exception used for
* the exception chaining.
* @param ResponseCollection|null $responses The complete set responses
* returned by the router.
*/
public function __construct(
$message,
$code = 0,
E $previous = null,
ResponseCollection $responses = null
) {
parent::__construct($message, $code, $previous);
$this->_responses = $responses;
}
/**
* Gets the complete set responses returned by the router.
*
* @return ResponseCollection|null The complete set responses
* returned by the router.
*/
public function getResponses()
{
return $this->_responses;
}
// @codeCoverageIgnoreStart
// String representation is not reliable in testing
/**
* Returns a string representation of the exception.
*
* @return string The exception as a string.
*/
public function __toString()
{
$result = parent::__toString();
if ($this->_responses instanceof ResponseCollection) {
$result .= "\nResponse collection:\n" .
print_r($this->_responses->toArray(), true);
}
return $result;
}
// @codeCoverageIgnoreEnd
}

View File

@ -0,0 +1,642 @@
<?php
/**
* RouterOS API client implementation.
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
* PHP version 5
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Net\RouterOS;
/**
* Values at {@link Script::escapeValue()} can be casted from this type.
*/
use DateTime;
/**
* Values at {@link Script::escapeValue()} can be casted from this type.
*/
use DateInterval;
/**
* Used at {@link Script::escapeValue()} to get the proper time.
*/
use DateTimeZone;
/**
* Used to reliably write to streams at {@link Script::prepare()}.
*/
use PEAR2\Net\Transmitter\Stream;
/**
* Used to catch DateTime and DateInterval exceptions at
* {@link Script::parseValue()}.
*/
use Exception as E;
/**
* Scripting class.
*
* Provides functionality related to parsing and composing RouterOS scripts and
* values.
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
class Script
{
/**
* Parses a value from a RouterOS scripting context.
*
* Turns a value from RouterOS into an equivalent PHP value, based on
* determining the type in the same way RouterOS would determine it for a
* literal.
*
* This method is intended to be the very opposite of
* {@link static::escapeValue()}. That is, results from that method, if
* given to this method, should produce equivalent results.
*
* @param string $value The value to be parsed.
* Must be a literal of a value,
* e.g. what {@link static::escapeValue()} will give you.
* @param DateTimeZone|null $timezone The timezone which any resulting
* DateTime object (either the main value, or values within an array)
* will use. Defaults to UTC.
*
* @return mixed Depending on RouterOS type detected:
* - "nil" (the string "[]") or "nothing" (empty string) - NULL.
* - "num" - int or double for large values.
* - "bool" - a boolean.
* - "array" - an array, with the keys and values processed recursively.
* - "time" - a {@link DateInterval} object.
* - "date" (pseudo type; string in the form "M/j/Y") - a DateTime
* object with the specified date, at midnight.
* - "datetime" (pseudo type; string in the form "M/j/Y H:i:s") - a
* DateTime object with the specified date and time.
* - "str" (a quoted string) - a string, with the contents escaped.
* - Unrecognized type - casted to a string, unmodified.
*/
public static function parseValue($value, DateTimeZone $timezone = null)
{
$value = static::parseValueToSimple($value);
if (!is_string($value)) {
return $value;
}
try {
return static::parseValueToArray($value, $timezone);
} catch (ParserException $e) {
try {
return static::parseValueToDateInterval($value);
} catch (ParserException $e) {
try {
return static::parseValueToDateTime($value, $timezone);
} catch (ParserException $e) {
return static::parseValueToString($value);
}
}
}
}
/**
* Parses a RouterOS value into a PHP string.
*
* @param string $value The value to be parsed.
* Must be a literal of a value,
* e.g. what {@link static::escapeValue()} will give you.
*
* @return string If a quoted string is provided, it would be parsed.
* Otherwise, the value is casted to a string, and returned unmodified.
*/
public static function parseValueToString($value)
{
$value = (string)$value;
if ('"' === $value[0] && '"' === $value[strlen($value) - 1]) {
return str_replace(
array('\"', '\\\\', "\\\n", "\\\r\n", "\\\r"),
array('"', '\\'),
substr($value, 1, -1)
);
}
return $value;
}
/**
* Parses a RouterOS value into a PHP simple type.
*
* Parses a RouterOS value into a PHP simple type. "Simple" types being
* scalar types, plus NULL.
*
* @param string $value The value to be parsed. Must be a literal of a
* value, e.g. what {@link static::escapeValue()} will give you.
*
* @return string|bool|int|double|null Depending on RouterOS type detected:
* - "nil" (the string "[]") or "nothing" (empty string) - NULL.
* - "num" - int or double for large values.
* - "bool" - a boolean.
* - Unrecognized type - casted to a string, unmodified.
*/
public static function parseValueToSimple($value)
{
$value = (string)$value;
if (in_array($value, array('', '[]'), true)) {
return null;
} elseif (in_array($value, array('true', 'false', 'yes', 'no'), true)) {
return $value === 'true' || $value === 'yes';
} elseif ($value === (string)($num = (int)$value)
|| $value === (string)($num = (double)$value)
) {
return $num;
}
return $value;
}
/**
* Parses a RouterOS value into a PHP DateTime object
*
* Parses a RouterOS value into a PHP DateTime object.
*
* @param string $value The value to be parsed.
* Must be a literal of a value,
* e.g. what {@link static::escapeValue()} will give you.
* @param DateTimeZone|null $timezone The timezone which the resulting
* DateTime object will use. Defaults to UTC.
*
* @return DateTime Depending on RouterOS type detected:
* - "date" (pseudo type; string in the form "M/j/Y") - a DateTime
* object with the specified date, at midnight UTC time (regardless
* of timezone provided).
* - "datetime" (pseudo type; string in the form "M/j/Y H:i:s") - a
* DateTime object with the specified date and time,
* with the specified timezone.
*
* @throws ParserException When the value is not of a recognized type.
*/
public static function parseValueToDateTime(
$value,
DateTimeZone $timezone = null
) {
$previous = null;
$value = (string)$value;
if ('' !== $value && preg_match(
'#^
(?<mon>jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)
/
(?<day>\d\d?)
/
(?<year>\d{4})
(?:
\s+(?<time>\d{2}\:\d{2}:\d{2})
)?
$#uix',
$value,
$date
)) {
if (!isset($date['time'])) {
$date['time'] = '00:00:00';
$timezone = new DateTimeZone('UTC');
} elseif (null === $timezone) {
$timezone = new DateTimeZone('UTC');
}
try {
return new DateTime(
$date['year'] .
'-' . ucfirst($date['mon']) .
"-{$date['day']} {$date['time']}",
$timezone
);
} catch (E $e) {
$previous = $e;
}
}
throw new ParserException(
'The supplied value can not be converted to a DateTime',
ParserException::CODE_DATETIME,
$previous
);
}
/**
* Parses a RouterOS value into a PHP DateInterval.
*
* Parses a RouterOS value into a PHP DateInterval.
*
* @param string $value The value to be parsed. Must be a literal of a
* value, e.g. what {@link static::escapeValue()} will give you.
*
* @return DateInterval The value as a DateInterval object.
*
* @throws ParserException When the value is not of a recognized type.
*/
public static function parseValueToDateInterval($value)
{
$value = (string)$value;
if ('' !== $value && preg_match(
'/^
(?:(\d+)w)?
(?:(\d+)d)?
(?:(\d+)(?:\:|h))?
(?|
(\d+)\:
(\d*(?:\.\d{1,9})?)
|
(?:(\d+)m)?
(?:(\d+|\d*\.\d{1,9})s)?
(?:((?5))ms)?
(?:((?5))us)?
(?:((?5))ns)?
)
$/x',
$value,
$time
)) {
$days = isset($time[2]) ? (int)$time[2] : 0;
if (isset($time[1])) {
$days += 7 * (int)$time[1];
}
if (empty($time[3])) {
$time[3] = 0;
}
if (empty($time[4])) {
$time[4] = 0;
}
if (empty($time[5])) {
$time[5] = 0;
}
$subsecondTime = 0.0;
//@codeCoverageIgnoreStart
// No PHP version currently supports sub-second DateIntervals,
// meaning this section is untestable, since no version constraints
// can be specified for test inputs.
// All inputs currently use integer seconds only, making this
// section unreachable during tests.
// Nevertheless, this section exists right now, in order to provide
// such support as soon as PHP has it.
if (!empty($time[6])) {
$subsecondTime += ((double)$time[6]) / 1000;
}
if (!empty($time[7])) {
$subsecondTime += ((double)$time[7]) / 1000000;
}
if (!empty($time[8])) {
$subsecondTime += ((double)$time[8]) / 1000000000;
}
//@codeCoverageIgnoreEnd
$secondsSpec = $time[5] + $subsecondTime;
try {
return new DateInterval(
"P{$days}DT{$time[3]}H{$time[4]}M{$secondsSpec}S"
);
//@codeCoverageIgnoreStart
// See previous ignored section's note.
//
// This section is added for backwards compatibility with current
// PHP versions, when in the future sub-second support is added.
// In that event, the test inputs for older versions will be
// expected to get a rounded up result of the sub-second data.
} catch (E $e) {
$secondsSpec = (int)round($secondsSpec);
return new DateInterval(
"P{$days}DT{$time[3]}H{$time[4]}M{$secondsSpec}S"
);
}
//@codeCoverageIgnoreEnd
}
throw new ParserException(
'The supplied value can not be converted to DateInterval',
ParserException::CODE_DATEINTERVAL
);
}
/**
* Parses a RouterOS value into a PHP array.
*
* Parses a RouterOS value into a PHP array.
*
* @param string $value The value to be parsed.
* Must be a literal of a value,
* e.g. what {@link static::escapeValue()} will give you.
* @param DateTimeZone|null $timezone The timezone which any resulting
* DateTime object within the array will use. Defaults to UTC.
*
* @return array An array, with the keys and values processed recursively,
* the keys with {@link static::parseValueToSimple()},
* and the values with {@link static::parseValue()}.
*
* @throws ParserException When the value is not of a recognized type.
*/
public static function parseValueToArray(
$value,
DateTimeZone $timezone = null
) {
$value = (string)$value;
if ('{' === $value[0] && '}' === $value[strlen($value) - 1]) {
$value = substr($value, 1, -1);
if ('' === $value) {
return array();
}
$parsedValue = preg_split(
'/
(\"(?:\\\\\\\\|\\\\"|[^"])*\")
|
(\{[^{}]*(?2)?\})
|
([^;=]+)
/sx',
$value,
null,
PREG_SPLIT_DELIM_CAPTURE
);
$result = array();
$newVal = null;
$newKey = null;
for ($i = 0, $l = count($parsedValue); $i < $l; ++$i) {
switch ($parsedValue[$i]) {
case '':
break;
case ';':
if (null === $newKey) {
$result[] = $newVal;
} else {
$result[$newKey] = $newVal;
}
$newKey = $newVal = null;
break;
case '=':
$newKey = static::parseValueToSimple($parsedValue[$i - 1]);
$newVal = static::parseValue($parsedValue[++$i], $timezone);
break;
default:
$newVal = static::parseValue($parsedValue[$i], $timezone);
}
}
if (null === $newKey) {
$result[] = $newVal;
} else {
$result[$newKey] = $newVal;
}
return $result;
}
throw new ParserException(
'The supplied value can not be converted to an array',
ParserException::CODE_ARRAY
);
}
/**
* Prepares a script.
*
* Prepares a script for eventual execution by prepending parameters as
* variables to it.
*
* This is particularly useful when you're creating scripts that you don't
* want to execute right now (as with {@link Util::exec()}, but instead
* you want to store it for later execution, perhaps by supplying it to
* "/system scheduler".
*
* @param string|resource $source The source of the script,
* as a string or stream. If a stream is provided, reading starts from
* the current position to the end of the stream, and the pointer stays
* at the end after reading is done.
* @param array<string|int,mixed> $params An array of parameters to make
* available in the script as local variables.
* Variable names are array keys, and variable values are array values.
* Array values are automatically processed with
* {@link static::escapeValue()}. Streams are also supported, and are
* processed in chunks, each with
* {@link static::escapeString()} with all bytes being escaped.
* Processing starts from the current position to the end of the stream,
* and the stream's pointer is left untouched after the reading is done.
* Variables with a value of type "nothing" can be declared with a
* numeric array key and the variable name as the array value
* (that is casted to a string).
*
* @return resource A new PHP temporary stream with the script as contents,
* with the pointer back at the start.
*
* @see static::append()
*/
public static function prepare(
$source,
array $params = array()
) {
$resultStream = fopen('php://temp', 'r+b');
static::append($resultStream, $source, $params);
rewind($resultStream);
return $resultStream;
}
/**
* Appends a script.
*
* Appends a script to an existing stream.
*
* @param resource $stream An existing stream to write the
* resulting script to.
* @param string|resource $source The source of the script,
* as a string or stream. If a stream is provided, reading starts from
* the current position to the end of the stream, and the pointer stays
* at the end after reading is done.
* @param array<string|int,mixed> $params An array of parameters to make
* available in the script as local variables.
* Variable names are array keys, and variable values are array values.
* Array values are automatically processed with
* {@link static::escapeValue()}. Streams are also supported, and are
* processed in chunks, each with
* {@link static::escapeString()} with all bytes being escaped.
* Processing starts from the current position to the end of the stream,
* and the stream's pointer is left untouched after the reading is done.
* Variables with a value of type "nothing" can be declared with a
* numeric array key and the variable name as the array value
* (that is casted to a string).
*
* @return int The number of bytes written to $stream is returned,
* and the pointer remains where it was after the write
* (i.e. it is not seeked back, even if seeking is supported).
*/
public static function append(
$stream,
$source,
array $params = array()
) {
$writer = new Stream($stream, false);
$bytes = 0;
foreach ($params as $pname => $pvalue) {
if (is_int($pname)) {
$pvalue = static::escapeString((string)$pvalue);
$bytes += $writer->send(":local \"{$pvalue}\";\n");
continue;
}
$pname = static::escapeString($pname);
$bytes += $writer->send(":local \"{$pname}\" ");
if (Stream::isStream($pvalue)) {
$reader = new Stream($pvalue, false);
$chunkSize = $reader->getChunk(Stream::DIRECTION_RECEIVE);
$bytes += $writer->send('"');
while ($reader->isAvailable() && $reader->isDataAwaiting()) {
$bytes += $writer->send(
static::escapeString(fread($pvalue, $chunkSize), true)
);
}
$bytes += $writer->send("\";\n");
} else {
$bytes += $writer->send(static::escapeValue($pvalue) . ";\n");
}
}
$bytes += $writer->send($source);
return $bytes;
}
/**
* Escapes a value for a RouterOS scripting context.
*
* Turns any native PHP value into an equivalent whole value that can be
* inserted as part of a RouterOS script.
*
* DateInterval objects will be casted to RouterOS' "time" type.
*
* DateTime objects will be casted to a string following the "M/d/Y H:i:s"
* format. If the time is exactly midnight (including microseconds), and
* the timezone is UTC, the string will include only the "M/d/Y" date.
*
* Unrecognized types (i.e. resources and other objects) are casted to
* strings, and those strings are then escaped.
*
* @param mixed $value The value to be escaped.
*
* @return string A string representation that can be directly inserted in a
* script as a whole value.
*/
public static function escapeValue($value)
{
switch(gettype($value)) {
case 'NULL':
$value = '[]';
break;
case 'integer':
$value = (string)$value;
break;
case 'boolean':
$value = $value ? 'true' : 'false';
break;
case 'array':
if (0 === count($value)) {
$value = '({})';
break;
}
$result = '';
foreach ($value as $key => $val) {
$result .= ';';
if (!is_int($key)) {
$result .= static::escapeValue($key) . '=';
}
$result .= static::escapeValue($val);
}
$value = '{' . substr($result, 1) . '}';
break;
case 'object':
if ($value instanceof DateTime) {
$usec = $value->format('u');
$usec = '000000' === $usec ? '' : '.' . $usec;
$value = '00:00:00.000000 UTC' === $value->format('H:i:s.u e')
? $value->format('M/d/Y')
: $value->format('M/d/Y H:i:s') . $usec;
}
if ($value instanceof DateInterval) {
if (false === $value->days || $value->days < 0) {
$value = $value->format('%r%dd%H:%I:%S');
} else {
$value = $value->format('%r%ad%H:%I:%S');
}
break;
}
//break; intentionally omitted
default:
$value = '"' . static::escapeString((string)$value) . '"';
break;
}
return $value;
}
/**
* Escapes a string for a RouterOS scripting context.
*
* Escapes a string for a RouterOS scripting context. The value can then be
* surrounded with quotes at a RouterOS script (or concatenated onto a
* larger string first), and you can be sure there won't be any code
* injections coming from it.
*
* By default, for the sake of brevity of the output, ASCII alphanumeric
* characters and underscores are left untouched. And for the sake of
* character conversion, bytes above 0x7F are also left untouched.
*
* @param string $value Value to be escaped.
* @param bool $full Whether to escape all bytes in the string, including
* ASCII alphanumeric characters, underscores and bytes above 0x7F.
*
* @return string The escaped value.
*
* @internal Why leave ONLY those ASCII characters and not also others?
* Because those can't in any way be mistaken for language constructs,
* unlike many other "safe inside strings, but not outside" ASCII
* characters, like ",", ".", "+", "-", "~", etc.
*/
public static function escapeString($value, $full = false)
{
if ($full) {
return self::_escapeCharacters(array($value));
}
return preg_replace_callback(
'/[^\\_A-Za-z0-9\\x80-\\xFF]+/S',
array(__CLASS__, '_escapeCharacters'),
$value
);
}
/**
* Escapes a character for a RouterOS scripting context.
*
* Escapes a character for a RouterOS scripting context.
* Intended to only be called by {@link self::escapeString()} for the
* matching strings.
*
* @param array $chars The matches array, expected to contain exactly one
* member, in which is the whole string to be escaped.
*
* @return string The escaped characters.
*/
private static function _escapeCharacters(array $chars)
{
$result = '';
for ($i = 0, $l = strlen($chars[0]); $i < $l; ++$i) {
$result .= '\\' . str_pad(
strtoupper(dechex(ord($chars[0][$i]))),
2,
'0',
STR_PAD_LEFT
);
}
return $result;
}
}

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -27,7 +28,7 @@ use RuntimeException;
/**
* Exception thrown when something goes wrong with the connection.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>

View File

@ -2,17 +2,18 @@
/**
* RouterOS API client implementation.
*
*
* RouterOS is the flag product of the company MikroTik and is a powerful router software. One of its many abilities is to allow control over it via an API. This package provides a client for that API, in turn allowing you to use PHP to control RouterOS hosts.
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0b5
* @version 1.0.0b6
* @link http://pear2.php.net/PEAR2_Net_RouterOS
*/
/**
@ -20,11 +21,19 @@
*/
namespace PEAR2\Net\RouterOS;
/**
* The base for this exception.
*/
use UnexpectedValueException as U;
/**
* Used in $previous.
*/
use Exception as E;
/**
* Exception thrown when encountering an invalid value in a function argument.
*
*
* @category Net
* @package PEAR2_Net_RouterOS
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -38,23 +47,25 @@ class UnexpectedValueException extends U implements Exception
const CODE_RESPONSE_TYPE_UNKNOWN = 50100;
/**
* @var mixed The unexpected value.
* The unexpected value.
*
* @var mixed
*/
private $_value;
/**
* Creates a new UnexpectedValueException.
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param \Exception $previous The previous exception used for the exception
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param E|null $previous The previous exception used for the exception
* chaining.
* @param mixed $value The unexpected value.
* @param mixed $value The unexpected value.
*/
public function __construct(
$message,
$code = 0,
$previous = null,
E $previous = null,
$value = null
) {
parent::__construct($message, $code, $previous);
@ -63,7 +74,7 @@ class UnexpectedValueException extends U implements Exception
/**
* Gets the unexpected value.
*
*
* @return mixed The unexpected value.
*/
public function getValue()
@ -76,7 +87,7 @@ class UnexpectedValueException extends U implements Exception
/**
* Returns a string representation of the exception.
*
*
* @return string The exception as a string.
*/
public function __toString()

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
/**
* Wrapper for network stream functionality.
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
@ -14,7 +15,7 @@ This package abstracts this away, so that when you want to get exactly N amount
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @version 1.0.0b2
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**

View File

@ -2,19 +2,20 @@
/**
* Wrapper for network stream functionality.
*
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @version 1.0.0b2
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
@ -24,9 +25,9 @@ namespace PEAR2\Net\Transmitter;
/**
* A filter collection.
*
*
* Represents a collection of stream filters.
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -37,21 +38,25 @@ namespace PEAR2\Net\Transmitter;
class FilterCollection implements \SeekableIterator, \Countable
{
/**
* @var array The filter collection itself.
* The filter collection itself.
*
* @var array
*/
protected $filters = array();
/**
* @var int A pointer, as required by SeekableIterator.
* A pointer, as required by SeekableIterator.
*
* @var int
*/
protected $position = 0;
/**
* Appends a filter to the collection
*
*
* @param string $name The name of the filter.
* @param array $params An array of parameters for the filter.
*
*
* @return $this The collection itself.
*/
public function append($name, array $params = array())
@ -59,19 +64,19 @@ class FilterCollection implements \SeekableIterator, \Countable
$this->filters[] = array((string) $name, $params);
return $this;
}
/**
* Inserts the filter before a position.
*
*
* Inserts the specified filter before a filter at a specified position. The
* new filter takes the specified position, while previous filters are moved
* forward by one.
*
*
* @param int $position The position before which the filter will be
* inserted.
* @param string $name The name of the filter.
* @param array $params An array of parameters for the filter.
*
*
* @return $this The collection itself.
*/
public function insertBefore($position, $name, array $params = array())
@ -94,12 +99,12 @@ class FilterCollection implements \SeekableIterator, \Countable
);
return $this;
}
/**
* Removes a filter at a specified position.
*
*
* @param int $position The position from which to remove a filter.
*
*
* @return $this The collection itself.
*/
public function removeAt($position)
@ -108,10 +113,10 @@ class FilterCollection implements \SeekableIterator, \Countable
$this->filters = array_values($this->filters);
return $this;
}
/**
* Clears the collection
*
*
* @return $this The collection itself.
*/
public function clear()
@ -122,7 +127,7 @@ class FilterCollection implements \SeekableIterator, \Countable
/**
* Gets the number of filters in the collection.
*
*
* @return int The number of filters in the collection.
*/
public function count()
@ -132,7 +137,7 @@ class FilterCollection implements \SeekableIterator, \Countable
/**
* Resets the pointer to 0.
*
*
* @return bool TRUE if the collection is not empty, FALSE otherwise.
*/
public function rewind()
@ -142,9 +147,9 @@ class FilterCollection implements \SeekableIterator, \Countable
/**
* Moves the pointer to a specified position.
*
*
* @param int $position The position to move to.
*
*
* @return bool TRUE if the specified position is valid, FALSE otherwise.
*/
public function seek($position)
@ -152,10 +157,10 @@ class FilterCollection implements \SeekableIterator, \Countable
$this->position = $position;
return $this->valid();
}
/**
* Gets the current position.
*
*
* @return int The current position.
*/
public function getCurrentPosition()
@ -165,7 +170,7 @@ class FilterCollection implements \SeekableIterator, \Countable
/**
* Moves the pointer forward by 1.
*
*
* @return bool TRUE if the new position is valid, FALSE otherwise.
*/
public function next()
@ -176,8 +181,8 @@ class FilterCollection implements \SeekableIterator, \Countable
/**
* Gets the filter name at the current pointer position.
*
* @return string The name of the filter at the current position.
*
* @return string|false The name of the filter at the current position.
*/
public function key()
{
@ -186,9 +191,9 @@ class FilterCollection implements \SeekableIterator, \Countable
/**
* Gets the filter parameters at the current pointer position.
*
* @return array An array of parameters for the filter at the current
* position.
*
* @return array|false An array of parameters for the filter at the current
* position, or FALSE if the position is not valid.
*/
public function current()
{
@ -197,7 +202,7 @@ class FilterCollection implements \SeekableIterator, \Countable
/**
* Moves the pointer backwards by 1.
*
*
* @return bool TRUE if the new position is valid, FALSE otherwise.
*/
public function prev()
@ -208,7 +213,7 @@ class FilterCollection implements \SeekableIterator, \Countable
/**
* Moves the pointer to the last valid position.
*
*
* @return bool TRUE if the collection is not empty, FALSE otherwise.
*/
public function end()
@ -219,7 +224,7 @@ class FilterCollection implements \SeekableIterator, \Countable
/**
* Checks if the pointer is still pointing to an existing offset.
*
*
* @return bool TRUE if the pointer is valid, FALSE otherwise.
*/
public function valid()

View File

@ -2,6 +2,7 @@
/**
* Wrapper for network stream functionality.
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
@ -14,7 +15,7 @@ This package abstracts this away, so that when you want to get exactly N amount
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @version 1.0.0b2
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**

View File

@ -2,19 +2,20 @@
/**
* Wrapper for network stream functionality.
*
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @version 1.0.0b2
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
@ -24,10 +25,10 @@ namespace PEAR2\Net\Transmitter;
/**
* A network transmitter.
*
* This is a convinience wrapper for network streams. Used to ensure data
*
* This is a convenience wrapper for network streams. Used to ensure data
* integrity.
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -62,22 +63,27 @@ abstract class NetworkStream extends Stream
* negotiated between 1.0 and 1.2).
*/
const CRYPTO_TLS = 'TLS';
/**
* @var string The type of stream. Can be either "_CLIENT" or "_SERVER".
* Used to complement the encryption type. Must be set by child classes
* for {@link setCrypto()} to work properly.
* The type of stream. Can be either "_CLIENT" or "_SERVER".
*
* Used to complement the encryption type. Must be set by child classes
* for {@link setCrypto()} to work properly.
*
* @var string
*/
protected $streamType = '';
/**
* @var string The current cryptography setting.
* The current cryptography setting.
*
* @var string
*/
protected $crypto = '';
/**
* Wraps around the specified stream.
*
*
* @param resource $stream The stream to wrap around.
*/
public function __construct($stream)
@ -87,7 +93,7 @@ abstract class NetworkStream extends Stream
/**
* Gets the current cryptography setting.
*
*
* @return string One of this class' CRYPTO_* constants.
*/
public function getCrypto()
@ -97,10 +103,10 @@ abstract class NetworkStream extends Stream
/**
* Sets the current connection's cryptography setting.
*
*
* @param string $type The encryption type to set. Must be one of this
* class' CRYPTO_* constants.
*
*
* @return boolean TRUE on success, FALSE on failure.
*/
public function setCrypto($type)
@ -123,12 +129,12 @@ abstract class NetworkStream extends Stream
/**
* Checks whether the stream is available for operations.
*
*
* @return bool TRUE if the stream is available, FALSE otherwise.
*/
public function isAvailable()
{
if (parent::isStream($this->stream)) {
if ($this->isStream($this->stream)) {
if ($this->isBlocking && feof($this->stream)) {
return false;
}
@ -137,14 +143,14 @@ abstract class NetworkStream extends Stream
}
return false;
}
/**
* Sets the size of a stream's buffer.
*
* @param int $size The desired size of the buffer, in bytes.
* @param string $direction The buffer of which direction to set. Valid
*
* @param int $size The desired size of the buffer, in bytes.
* @param int $direction The buffer of which direction to set. Valid
* values are the DIRECTION_* constants.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function setBuffer($size, $direction = self::DIRECTION_ALL)
@ -157,15 +163,15 @@ abstract class NetworkStream extends Stream
}
return $result;
}
/**
* Shutdown a full-duplex connection
*
*
* Shutdowns (partially or not) a full-duplex connection.
*
* @param string $direction The direction for which to disable further
*
* @param int $direction The direction for which to disable further
* communications.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function shutdown($direction = self::DIRECTION_ALL)

View File

@ -2,19 +2,20 @@
/**
* Wrapper for network stream functionality.
*
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @version 1.0.0b2
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
@ -29,7 +30,7 @@ use Exception as E;
/**
* Exception thrown when something goes wrong with the connection.
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -40,18 +41,22 @@ class SocketException extends StreamException
{
/**
* @var int The system level error code.
* The system level error code.
*
* @var int
*/
protected $errorNo;
/**
* @var string The system level error message.
* The system level error message.
*
* @var string
*/
protected $errorStr;
/**
* Creates a new socket exception.
*
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param E|null $previous Previous exception thrown,
@ -62,7 +67,7 @@ class SocketException extends StreamException
* successfully before the failure.
* On failure when receiving, this is a string/stream holding
* the contents received successfully before the failure.
* NULL if the failure occured before the operation started.
* NULL if the failure occurred before the operation started.
* @param int $errorNo The system level error number.
* @param string $errorStr The system level
* error message.
@ -82,7 +87,7 @@ class SocketException extends StreamException
/**
* Gets the system level error code on the socket.
*
*
* @return int The system level error number.
*/
public function getSocketErrorNumber()
@ -95,7 +100,7 @@ class SocketException extends StreamException
/**
* Gets the system level error message on the socket.
*
*
* @return string The system level error message.
*/
public function getSocketErrorMessage()
@ -105,7 +110,7 @@ class SocketException extends StreamException
/**
* Returns a string representation of the exception.
*
*
* @return string The exception as a string.
*/
public function __toString()

View File

@ -2,19 +2,20 @@
/**
* Wrapper for network stream functionality.
*
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @version 1.0.0b2
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
@ -26,11 +27,11 @@ use Exception as E;
/**
* A stream transmitter.
*
* This is a convinience wrapper for stream functionality. Used to ensure data
*
* This is a convenience wrapper for stream functionality. Used to ensure data
* integrity. Designed for TCP sockets, but it has intentionally been made to
* accept any stream.
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -57,32 +58,44 @@ class Stream
const DIRECTION_ALL = 3;
/**
* @var resource The stream to wrap around.
* The stream to wrap around.
*
* @var resource
*/
protected $stream;
/**
* @var bool Whether to automaticaly close the stream on
* object destruction if it's not a persistent one. Setting this to
* FALSE may be useful if you're only using this class "part time",
* while setting it to TRUE might be useful if you're doing some
* "on offs".
* Whether to automatically close the stream on object destruction if
* it's not a persistent one.
*
* Setting this to FALSE may be useful if you're only using this class
* "part time", while setting it to TRUE might be useful if you're doing
* some "one offs".
*
* @var bool
*/
protected $autoClose = false;
/**
* @var bool A flag that tells whether or not the stream is persistent.
* A flag that tells whether or not the stream is persistent.
*
* @var bool
*/
protected $persist;
/**
* @var bool Whether the wrapped stream is in blocking mode or not.
* Whether the wrapped stream is in blocking mode or not.
*
* @var bool
*/
protected $isBlocking = true;
/**
* @var array An associative array with the chunk size of each direction.
* Key is the direction, value is the size in bytes as integer.
* An associative array with the chunk size of each direction.
*
* Key is the direction, value is the size in bytes as integer.
*
* @var array<int,int>
*/
protected $chunkSize = array(
self::DIRECTION_SEND => 0xFFFFF, self::DIRECTION_RECEIVE => 0xFFFFF
@ -90,14 +103,14 @@ class Stream
/**
* Wraps around the specified stream.
*
*
* @param resource $stream The stream to wrap around.
* @param bool $autoClose Whether to automaticaly close the stream on
* @param bool $autoClose Whether to automatically close the stream on
* object destruction if it's not a persistent one. Setting this to
* FALSE may be useful if you're only using this class "part time",
* while setting it to TRUE might be useful if you're doing some
* "on offs".
*
*
* @see static::isFresh()
*/
public function __construct($stream, $autoClose = false)
@ -117,12 +130,14 @@ class Stream
/**
* PHP error handler for connection errors.
*
*
* @param string $level Level of PHP error raised. Ignored.
* @param string $message Message raised by PHP.
*
*
* @return void
*
* @throws SocketException That's how the error is handled.
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
protected function handleError($level, $message)
@ -132,9 +147,9 @@ class Stream
/**
* Checks if a given variable is a stream resource.
*
*
* @param mixed $var The variable to check.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public static function isStream($var)
@ -145,11 +160,11 @@ class Stream
/**
* Checks whether the wrapped stream is fresh.
*
*
* Checks whether the wrapped stream is fresh. A stream is considered fresh
* if there hasn't been any activity on it. Particularly useful for
* detecting reused persistent connections.
*
*
* @return bool TRUE if the socket is fresh, FALSE otherwise.
*/
public function isFresh()
@ -159,8 +174,8 @@ class Stream
/**
* Checks whether the wrapped stream is a persistent one.
*
* @return bool TRUE if the stream is a persistent one, FALSE otherwise.
*
* @return bool TRUE if the stream is a persistent one, FALSE otherwise.
*/
public function isPersistent()
{
@ -169,8 +184,8 @@ class Stream
/**
* Checks whether the wrapped stream is a blocking one.
*
* @return bool TRUE if the stream is a blocking one, FALSE otherwise.
*
* @return bool TRUE if the stream is a blocking one, FALSE otherwise.
*/
public function isBlocking()
{
@ -179,9 +194,9 @@ class Stream
/**
* Sets blocking mode.
*
*
* @param bool $block Sets whether the stream is in blocking mode.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function setIsBlocking($block)
@ -193,28 +208,28 @@ class Stream
}
return false;
}
/**
* Sets the timeout for the stream.
*
*
* @param int $seconds Timeout in seconds.
* @param int $microseconds Timeout in microseconds to be added to the
* seconds.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function setTimeout($seconds, $microseconds = 0)
{
return stream_set_timeout($this->stream, $seconds, $microseconds);
}
/**
* Sets the size of a stream's buffer.
*
* @param int $size The desired size of the buffer, in bytes.
* @param string $direction The buffer of which direction to set. Valid
*
* @param int $size The desired size of the buffer, in bytes.
* @param int $direction The buffer of which direction to set. Valid
* values are the DIRECTION_* constants.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function setBuffer($size, $direction = self::DIRECTION_ALL)
@ -230,18 +245,18 @@ class Stream
}
return false;
}
/**
* Sets the size of the chunk.
*
*
* To ensure data integrity, as well as to allow for lower memory
* consumption, data is sent/received in chunks. This function
* allows you to set the size of each chunk. The default is 0xFFFFF.
*
* @param int $size The desired size of the chunk, in bytes.
* @param string $direction The chunk of which direction to set. Valid
*
* @param int $size The desired size of the chunk, in bytes.
* @param int $direction The chunk of which direction to set. Valid
* values are the DIRECTION_* constants.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function setChunk($size, $direction = self::DIRECTION_ALL)
@ -262,14 +277,14 @@ class Stream
}
return false;
}
/**
* Gets the size of the chunk.
*
* @param string $direction The chunk of which direction to get. Valid
*
* @param int $direction The chunk of which direction to get. Valid
* values are the DIRECTION_* constants.
*
* @return int|array|false The chunk size in bytes,
*
* @return int|array<int,int>|false The chunk size in bytes,
* or an array of chunk sizes with the directions as keys.
* FALSE on invalid direction.
*/
@ -287,18 +302,18 @@ class Stream
/**
* Sends a string or stream over the wrapped stream.
*
*
* Sends a string or stream over the wrapped stream. If a seekable stream is
* provided, it will be seeked back to the same position it was passed as,
* regardless of the $offset parameter.
*
*
* @param string|resource $contents The string or stream to send.
* @param int $offset The offset from which to start sending.
* If a stream is provided, and this is set to NULL, sending will start
* from the current stream position.
* @param int $length The maximum length to send. If omitted,
* the string/stream will be sent to its end.
*
*
* @return int The number of bytes sent.
*/
public function send($contents, $offset = null, $length = null)
@ -318,21 +333,22 @@ class Stream
) {
break;
}
$bytesNow = @fwrite(
$this->stream,
fread($contents, $chunkSize)
);
if (0 != $bytesNow) {
$bytes += $bytesNow;
} elseif ($this->isBlocking || false === $bytesNow) {
throw $this->createException(
'Failed while sending stream.',
2,
null,
$bytes
$contentsToSend = fread($contents, $chunkSize);
if ('' != $contentsToSend) {
$bytesNow = @fwrite(
$this->stream,
$contentsToSend
);
} else {
usleep(300000);
if (0 != $bytesNow) {
$bytes += $bytesNow;
} elseif ($this->isBlocking || false === $bytesNow) {
throw $this->createException(
'Failed while sending stream.',
2,
null,
$bytes
);
}
}
$this->isAcceptingData(null);
}
@ -364,8 +380,6 @@ class Stream
null,
$bytes
);
} else {
usleep(300000);
}
$this->isAcceptingData(null);
}
@ -375,13 +389,13 @@ class Stream
/**
* Reads from the wrapped stream to receive.
*
*
* Reads from the wrapped stream to receive content as a string.
*
*
* @param int $length The number of bytes to receive.
* @param string $what Descriptive string about what is being received
* (used in exception messages).
*
*
* @return string The received content.
*/
public function receive($length, $what = 'data')
@ -412,16 +426,16 @@ class Stream
/**
* Reads from the wrapped stream to receive.
*
*
* Reads from the wrapped stream to receive content as a stream.
*
*
* @param int $length The number of bytes to receive.
* @param FilterCollection $filters A collection of filters to apply to the
* stream while receiving. Note that the filters will not be present on
* the stream after receiving is done.
* @param string $what Descriptive string about what is being
* received (used in exception messages).
*
*
* @return resource The received content.
*/
public function receiveStream(
@ -432,16 +446,16 @@ class Stream
$result = fopen('php://temp', 'r+b');
$appliedFilters = array();
if (null !== $filters) {
foreach ($filters as $filtername => $params) {
foreach ($filters as $filterName => $params) {
$appliedFilters[] = stream_filter_append(
$result,
$filtername,
$filterName,
STREAM_FILTER_WRITE,
$params
);
}
}
$chunkSize = $this->chunkSize[self::DIRECTION_RECEIVE];
while ($length > 0) {
while ($this->isAvailable()) {
@ -477,10 +491,10 @@ class Stream
/**
* Checks whether the stream is available for operations.
*
*
* For network streams, this means whether the other end has closed the
* connection.
*
*
* @return bool TRUE if the stream is available, FALSE otherwise.
*/
public function isAvailable()
@ -490,13 +504,14 @@ class Stream
/**
* Checks whether there is data to be read from the wrapped stream.
*
* @param int|null $sTimeout If theere isn't data awaiting currently,
*
* @param int|null $sTimeout If there isn't data awaiting currently,
* wait for it this many seconds for data to arrive. If NULL is
* specified, wait indefinetly for that.
* specified, wait indefinitely for that.
* @param int $usTimeout Microseconds to add to the waiting time.
*
*
* @return bool TRUE if there is data to be read, FALSE otherwise.
*
* @SuppressWarnings(PHPMD.ShortVariable)
*/
public function isDataAwaiting($sTimeout = 0, $usTimeout = 0)
@ -522,14 +537,15 @@ class Stream
/**
* Checks whether the wrapped stream can be written to without a block.
*
*
* @param int|null $sTimeout If the stream isn't currently accepting data,
* wait for it this many seconds to start accepting data. If NULL is
* specified, wait indefinetly for that.
* specified, wait indefinitely for that.
* @param int $usTimeout Microseconds to add to the waiting time.
*
* @return bool TRUE if the wrapped stream would not block on a write, FALSE
* otherwise.
*
* @return bool TRUE if the wrapped stream would not block on a write,
* FALSE otherwise.
*
* @SuppressWarnings(PHPMD.ShortVariable)
*/
public function isAcceptingData($sTimeout = 0, $usTimeout = 0)
@ -567,7 +583,7 @@ class Stream
/**
* Closes the opened stream, even if it is a persistent one.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function close()
@ -577,10 +593,10 @@ class Stream
/**
* Creates a new exception.
*
*
* Creates a new exception. Used by the rest of the functions in this class.
* Override in derived classes for custom exception handling.
*
*
* @param string $message The exception message.
* @param int $code The exception code.
* @param E|null $previous Previous exception thrown,
@ -591,7 +607,7 @@ class Stream
* successfully before the failure.
* On failure when receiving, this is a string/stream holding
* the contents received successfully before the failure.
*
*
* @return StreamException The exception to then be thrown.
*/
protected function createException(

View File

@ -2,19 +2,20 @@
/**
* Wrapper for network stream functionality.
*
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @version 1.0.0b2
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
@ -34,7 +35,7 @@ use Exception as E;
/**
* Exception thrown when something goes wrong with the connection.
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -44,18 +45,21 @@ use Exception as E;
class StreamException extends RuntimeException implements Exception
{
/**
* @var int|string|resource|null The fragment up until the point of failure.
* On failure with sending, this is the number of bytes sent
* successfully before the failure.
* On failure when receiving, this is a string/stream holding
* the contents received successfully before the failure.
* NULL if the failure occured before the operation started.
* The fragment up until the point of failure.
*
* On failure with sending, this is the number of bytes sent successfully
* before the failure.
* On failure when receiving, this is a string/stream holding the contents
* received successfully before the failure.
* NULL if the failure occurred before the operation started.
*
* @var int|string|resource|null
*/
protected $fragment = null;
/**
* Creates a new stream exception.
*
*
* @param string $message The Exception message to throw.
* @param int $code The Exception code.
* @param E|null $previous Previous exception thrown,
@ -66,7 +70,7 @@ class StreamException extends RuntimeException implements Exception
* successfully before the failure.
* On failure when receiving, this is a string/stream holding
* the contents received successfully before the failure.
* NULL if the failure occured before the operation started.
* NULL if the failure occurred before the operation started.
*/
public function __construct(
$message,
@ -80,14 +84,14 @@ class StreamException extends RuntimeException implements Exception
/**
* Gets the stream fragment.
*
*
* @return int|string|resource|null The fragment up until the
* point of failure.
* On failure with sending, this is the number of bytes sent
* successfully before the failure.
* On failure when receiving, this is a string/stream holding
* the contents received successfully before the failure.
* NULL if the failure occured before the operation started.
* NULL if the failure occurred before the operation started.
*/
public function getFragment()
{
@ -99,7 +103,7 @@ class StreamException extends RuntimeException implements Exception
/**
* Returns a string representation of the exception.
*
*
* @return string The exception as a string.
*/
public function __toString()

View File

@ -2,19 +2,20 @@
/**
* Wrapper for network stream functionality.
*
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @version 1.0.0b2
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
@ -35,10 +36,10 @@ use Exception as E;
/**
* A socket transmitter.
*
* This is a convinience wrapper for socket functionality. Used to ensure data
*
* This is a convenience wrapper for socket functionality. Used to ensure data
* integrity.
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -49,27 +50,41 @@ class TcpClient extends NetworkStream
{
/**
* @var int The error code of the last error on the socket.
* The error code of the last error on the socket.
*
* @var int
*/
protected $errorNo = 0;
/**
* @var string The error message of the last error on the socket.
* The error message of the last error on the socket.
*
* @var string
*/
protected $errorStr = null;
/**
* @var SHM Persistent connection handler. Remains NULL for non-persistent
* connections.
* Persistent connection handler.
*
* Remains NULL for non-persistent connections.
*
* @var SHM
*/
protected $shmHandler = null;
/**
* @var array An array with all connections from this PHP request (as keys)
* and their lock state (as a value).
* An array with all connections from this PHP request (as keys)
* and their lock state (as a value).
*
* @var array
*/
protected static $lockState = array();
/**
* Mappings from a protocol name to an URI scheme.
*
* @var array<string,string>
*/
protected static $cryptoScheme = array(
parent::CRYPTO_OFF => 'tcp',
parent::CRYPTO_SSL2 => 'sslv2',
@ -77,27 +92,29 @@ class TcpClient extends NetworkStream
parent::CRYPTO_SSL => 'ssl',
parent::CRYPTO_TLS => 'tls'
);
/**
* @var string The URI of this connection.
* The URI of this connection.
*
* @var string
*/
protected $uri;
/**
* Creates a new connection with the specified options.
*
*
* @param string $host Hostname (IP or domain) of the server.
* @param int $port The port on the server.
* @param bool $persist Whether or not the connection should be a
* persistent one.
* @param float $timeout The timeout for the connection.
* @param string $key A string that uniquely identifies the
* connection.
* connection. Ignored for non-persistent connections.
* @param string $crypto Encryption setting. Must be one of the
* NetworkStream::CRYPTO_* constants. By default, encryption is
* disabled. If the setting has an associated scheme for it, it will be
* used, and if not, the setting will be adjusted right after the
* connection is estabilished.
* connection is established.
* @param resource $context A context for the socket.
*/
public function __construct(
@ -114,16 +131,10 @@ class TcpClient extends NetworkStream
if (strpos($host, ':') !== false) {
$host = "[{$host}]";
}
$flags = STREAM_CLIENT_CONNECT;
if ($persist) {
$flags |= STREAM_CLIENT_PERSISTENT;
}
$timeout
= null == $timeout ? ini_get('default_socket_timeout') : $timeout;
$key = rawurlencode($key);
if (null === $context) {
$context = stream_context_get_default();
} elseif ((!is_resource($context))
@ -133,7 +144,14 @@ class TcpClient extends NetworkStream
}
$hasCryptoScheme = array_key_exists($crypto, static::$cryptoScheme);
$scheme = $hasCryptoScheme ? static::$cryptoScheme[$crypto] : 'tcp';
$this->uri = "{$scheme}://{$host}:{$port}/{$key}";
$flags = STREAM_CLIENT_CONNECT;
if ($persist) {
$flags |= STREAM_CLIENT_PERSISTENT;
$key = rawurlencode($key);
$this->uri = "{$scheme}://{$host}:{$port}/{$key}";
} else {
$this->uri = "{$scheme}://{$host}:{$port}";
}
set_error_handler(array($this, 'handleError'));
try {
parent::__construct(
@ -168,7 +186,9 @@ class TcpClient extends NetworkStream
} elseif (parent::CRYPTO_OFF !== $crypto) {
$this->setCrypto($crypto);
}
$this->setIsBlocking(parent::CRYPTO_OFF === $crypto);
if (parent::CRYPTO_OFF !== $crypto) {
$this->setIsBlocking(false);
}
if ($persist) {
$this->shmHandler = SHM::factory(
@ -180,9 +200,9 @@ class TcpClient extends NetworkStream
/**
* Creates a new exception.
*
*
* Creates a new exception. Used by the rest of the functions in this class.
*
*
* @param string $message The exception message.
* @param int $code The exception code.
* @param E|null $previous Previous exception thrown,
@ -193,7 +213,7 @@ class TcpClient extends NetworkStream
* successfully before the failure.
* On failure when receiving, this is a string/stream holding
* the contents received successfully before the failure.
*
*
* @return SocketException The exception to then be thrown.
*/
protected function createException(
@ -211,26 +231,27 @@ class TcpClient extends NetworkStream
$this->errorStr
);
}
/**
* Locks transmission.
*
*
* Locks transmission in one or more directions. Useful when dealing with
* persistent connections. Note that every send/receive call implicitly
* calls this function and then restores it to the previous state. You only
* need to call this function if you need to do an uninterrputed sequence of
* need to call this function if you need to do an uninterrupted sequence of
* such calls.
*
*
* @param int $direction The direction(s) to have locked. Acceptable values
* are the DIRECTION_* constants. If a lock for a direction can't be
* obtained immediatly, the function will block until one is aquired.
* Note that if you specify {@link DIRECTION_ALL}, the sending lock will
* be obtained before the receiving one, and if obtaining the receiving
* lock afterwards fails, the sending lock will be released too.
* obtained immediately, the function will block until one is acquired.
* Note that if you specify {@link static::DIRECTION_ALL},
* the sending lock will be obtained before the receiving one,
* and if obtaining the receiving lock afterwards fails,
* the sending lock will be released too.
* @param bool $replace Whether to replace all locks with the specified
* ones. Setting this to FALSE will make the function only obtain the
* locks which are not already obtained.
*
*
* @return int|false The previous state or FALSE if the connection is not
* persistent or arguments are invalid.
*/
@ -256,7 +277,7 @@ class TcpClient extends NetworkStream
throw new LockException('Unable to release sending lock.');
}
}
try {
if ($direction & self::DIRECTION_RECEIVE) {
if (($old & self::DIRECTION_RECEIVE)
@ -292,23 +313,24 @@ class TcpClient extends NetworkStream
}
return false;
}
/**
* Sends a string or stream to the server.
*
*
* Sends a string or stream to the server. If a seekable stream is
* provided, it will be seeked back to the same position it was passed as,
* regardless of the $offset parameter.
*
*
* @param string|resource $contents The string or stream to send.
* @param int $offset The offset from which to start sending.
* If a stream is provided, and this is set to NULL, sending will start
* from the current stream position.
* @param int $length The maximum length to send. If omitted,
* the string/stream will be sent to its end.
*
*
* @return int The number of bytes sent.
* @throws E
*/
public function send($contents, $offset = null, $length = null)
{
@ -332,13 +354,13 @@ class TcpClient extends NetworkStream
/**
* Receives data from the server.
*
*
* Receives data from the server as a string.
*
*
* @param int $length The number of bytes to receive.
* @param string $what Descriptive string about what is being received
* (used in exception messages).
*
*
* @return string The received content.
*/
public function receive($length, $what = 'data')
@ -363,16 +385,16 @@ class TcpClient extends NetworkStream
/**
* Receives data from the server.
*
*
* Receives data from the server as a stream.
*
*
* @param int $length The number of bytes to receive.
* @param FilterCollection $filters A collection of filters to apply to the
* stream while receiving. Note that the filters will not be present on
* the stream after receiving is done.
* @param string $what Descriptive string about what is being
* received (used in exception messages).
*
*
* @return resource The received content.
*/
public function receiveStream(

View File

@ -2,19 +2,20 @@
/**
* Wrapper for network stream functionality.
*
*
* PHP has built in support for various types of network streams, such as HTTP and TCP sockets. One problem that arises with them is the fact that a single fread/fwrite call might not read/write all the data you intended, regardless of whether you're in blocking mode or not. While the PHP manual offers a workaround in the form of a loop with a few variables, using it every single time you want to read/write can be tedious.
This package abstracts this away, so that when you want to get exactly N amount of bytes, you can be sure the upper levels of your app will be dealing with N bytes. Oh, and the functionality is nicely wrapped in an object (but that's just the icing on the cake).
*
*
* PHP version 5
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 1.0.0a5
* @version 1.0.0b2
* @link http://pear2.php.net/PEAR2_Net_Transmitter
*/
/**
@ -26,12 +27,12 @@ use Exception as E;
/**
* A transmitter for connections to a socket server.
*
* This is a convinience wrapper for functionality of socket server connections.
*
* This is a convenience wrapper for functionality of socket server connections.
* Used to ensure data integrity. Server handling is not part of the class in
* order to allow its usage as part of various server implementations (e.g. fork
* and/or sequential).
*
*
* @category Net
* @package PEAR2_Net_Transmitter
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -42,21 +43,26 @@ class TcpServerConnection extends NetworkStream
{
/**
* @var string The IP address of the connected client.
* The IP address of the connected client.
*
* @var string
*/
protected $peerIP;
/**
* @var int The port of the connected client.
* The port of the connected client.
*
* @var int
*/
protected $peerPort;
/**
* Creates a new connection with the specified options.
*
* @param resource $server A socket server, created with
* {@link stream_socket_server()}.
* @param float $timeout The timeout for the connection.
*
* @param resource $server A socket server, created with
* {@link stream_socket_server()}.
* @param float|null $timeout The timeout for the connection. Leaving this
* to NULL uses the default socket timeout.
*/
public function __construct($server, $timeout = null)
{
@ -71,15 +77,15 @@ class TcpServerConnection extends NetworkStream
set_error_handler(array($this, 'handleError'));
try {
parent::__construct(
stream_socket_accept($server, $timeout, $peername)
stream_socket_accept($server, $timeout, $peerName)
);
restore_error_handler();
$portString = strrchr($peername, ':');
$portString = strrchr($peerName, ':');
$this->peerPort = (int) substr($portString, 1);
$ipString = substr(
$peername,
$peerName,
0,
strlen($peername) - strlen($portString)
strlen($peerName) - strlen($portString)
);
if (strpos($ipString, '[') === 0
&& strpos(strrev($ipString), ']') === 0
@ -96,20 +102,20 @@ class TcpServerConnection extends NetworkStream
);
}
}
/**
* Gets the IP address of the connected client.
*
*
* @return string The IP address of the connected client.
*/
public function getPeerIP()
{
return $this->peerIP;
}
/**
* Gets the port of the connected client.
*
*
* @return int The port of the connected client.
*/
public function getPeerPort()
@ -119,16 +125,16 @@ class TcpServerConnection extends NetworkStream
/**
* Creates a new exception.
*
*
* Creates a new exception. Used by the rest of the functions in this class.
*
*
* @param string $message The exception message.
* @param int $code The exception code.
* @param E|null $previous Previous exception thrown, or NULL if there
* is none.
* @param string|null $fragment The fragment up until the point of failure.
* NULL if the failure occured before the operation started.
*
* NULL if the failure occurred before the operation started.
*
* @return SocketException The exception to then be thrown.
*/
protected function createException(