update PEAR

This commit is contained in:
Ibnu Maksum 2023-10-05 16:55:44 +07:00
parent 1861358415
commit 071df91de0
No known key found for this signature in database
GPG Key ID: 7FC82848810579E5
64 changed files with 3872 additions and 2100 deletions

View File

@ -1,22 +1,87 @@
<?php
/**
* Standard Autoloader for PEAR2
*
* PEAR2_Autoload is the standard method of class loading for development and
* low-volume web sites using PEAR2 packages.
*
* PHP version 5
*
* @category PEAR2
* @package PEAR2_Autoload
* @author Gregory Beaver <cellog@php.net>
* @author Brett Bieber <saltybeagle@php.net>
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @version 0.3.0
* @link http://pear2.php.net/PEAR2_Autoload
*/
namespace PEAR2;
if (!class_exists('\PEAR2\Autoload', false)) {
/**
* Standard Autoloader for PEAR2
*
* PEAR2_Autoload is the standard method of class loading for development
* and low-volume web sites using PEAR2 packages.
*
* PHP version 5
*
* @category PEAR2
* @package PEAR2_Autoload
* @author Gregory Beaver <cellog@php.net>
* @author Brett Bieber <saltybeagle@php.net>
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* New BSDLicense
* @link http://pear2.php.net/PEAR2_Autoload
*/
class Autoload
{
/**
* Used at {@link initialize()} to specify that the load function, path
* and map should be appended to the respective lists.
*/
const APPEND = 0;
/**
* Used at {@link initialize()} to specify that the load function should
* be prepended on the autoload stack, instead of being appended.
*/
const PREPEND_LOAD = 1;
/**
* Used at {@link initialize()} to specify that the path should be
* prepended on the list of paths, instead of being appended.
*/
const PREPEND_PATH = 2;
/**
* Used at {@link initialize()} to specify that the map should be
* prepended on the list of maps, instead of being appended.
*/
const PREPEND_MAP = 4;
/**
* Used at {@link initialize()} to specify that the load function, path
* and map should be prepended on their respective lists, instead of
* being appended.
*/
const PREPEND = 7;
/**
* Whether the autoload class has been spl_autoload_register-ed
*
*
* @var bool
*/
protected static $registered = false;
/**
* Array of PEAR2 autoload paths registered
*
*
* @var array
*/
protected static $paths = array();
/**
* Array of classname-to-file mapping
*
@ -45,86 +110,124 @@ if (!class_exists('\PEAR2\Autoload', false)) {
*/
protected static $unmapped = array();
/**
* Array of functions to be checked in exception traces.
*
* @var array
*/
protected static $checkFunctions = array(
'class_exists', 'interface_exists'
);
/**
* Initialize the PEAR2 autoloader
*
* @param string $path Directory path to register
*
*
* @param string $path Directory path(s) to register.
* @param string $mapfile Path to a mapping file to register.
* @param int $flags A bitmaks with options for the autoloader.
* See the PREPEND(_*) constants for details.
*
* @return void
*/
static function initialize($path, $mapfile = null)
{
self::register();
self::addPath($path);
self::addMap($mapfile);
public static function initialize(
$path,
$mapfile = null,
$flags = self::APPEND
) {
self::register(0 !== $flags & self::PREPEND_LOAD);
self::addPath($path, 0 !== ($flags & self::PREPEND_PATH));
self::addMap($mapfile, 0 !== ($flags & self::PREPEND_MAP));
}
/**
* Register the PEAR2 autoload class with spl_autoload_register
*
*
* @param bool $prepend Whether to prepend the load function to the
* autoload stack instead of appending it.
*
* @return void
*/
protected static function register()
protected static function register($prepend = false)
{
if (!self::$registered) {
// set up __autoload
$autoload = spl_autoload_functions();
spl_autoload_register('PEAR2\Autoload::load');
spl_autoload_register('PEAR2\Autoload::load', true, $prepend);
if (function_exists('__autoload') && ($autoload === false)) {
// __autoload() was being used, but now would be ignored, add
// it to the autoload stack
// __autoload() was being used, but now would be ignored,
// add it to the autoload stack
spl_autoload_register('__autoload');
}
if (function_exists('trait_exists')) {
self::$checkFunctions[] = 'trait_exists';
}
self::$registered = true;
}
self::$registered = true;
}
/**
* Add a path
*
* @param string $path The directory to add to the set of PEAR2 paths
*
*
* @param string $paths The folder(s) to add to the set of paths.
* @param bool $prepend Whether to prepend the path to the list of
* paths instead of appending it.
*
* @return void
*/
protected static function addPath($path)
protected static function addPath($paths, $prepend = false)
{
if (!in_array($path, self::$paths)) {
self::$paths[] = $path;
foreach (explode(PATH_SEPARATOR, $paths) as $path) {
if (!in_array($path, self::$paths)) {
if ($prepend) {
self::$paths = array_merge(array($path), self::$paths);
} else {
self::$paths[] = $path;
}
}
}
}
/**
* Add a classname-to-file map
*
* @param string $mapfile The filename of the classmap
* @param string $mapfile The filename of the classmap.
* @param bool $prepend Whether to prepend the map to the list of maps
* instead of appending it.
*
* @return void
*/
protected static function addMap($mapfile)
protected static function addMap($mapfile, $prepend = false)
{
if (! in_array($mapfile, self::$maps)) {
if (!in_array($mapfile, self::$maps)) {
// keep track of specific map file loaded in this
// instance so we can update it if necessary
// instance so we can update it if necessary
self::$mapfile = $mapfile;
if (file_exists($mapfile)) {
if (is_file($mapfile)) {
$map = include $mapfile;
if (is_array($map)) {
// mapfile contains a valid map, so we'll keep it
self::$maps[] = $mapfile;
self::$map = array_merge(self::$map, $map);
if ($prepend) {
self::$maps = array_merge(
array($mapfile),
self::$maps
);
self::$map = array_merge($map, self::$map);
} else {
self::$maps[] = $mapfile;
self::$map = array_merge(self::$map, $map);
}
}
}
}
}
/**
* Check if the class is already defined in a classmap
*
*
* @param string $class The class to look for
*
*
* @return bool
*/
protected static function isMapped($class)
@ -141,18 +244,18 @@ if (!class_exists('\PEAR2\Autoload', false)) {
/**
* Load a PEAR2 class
*
*
* @param string $class The class to load
*
*
* @return bool
*/
static function load($class)
public static function load($class)
{
// need to check if there's a current map file specified ALSO.
// this could be the first time writing it.
$mapped = self::isMapped($class);
if ($mapped) {
require self::$map[$class];
if ($mapped && is_file(self::$map[$class])) {
include self::$map[$class];
if (!self::loadSuccessful($class)) {
// record this failure & keep going, we may still find it
self::$unmapped[] = $class;
@ -161,34 +264,59 @@ if (!class_exists('\PEAR2\Autoload', false)) {
}
}
$file = str_replace(array('_', '\\'), DIRECTORY_SEPARATOR, $class) . '.php';
$file = '';
$className = $class;
if (false !== $lastNsPos = strrpos($class, '\\')) {
$namespace = substr($class, 0, $lastNsPos);
$className = substr($class, $lastNsPos + 1);
$file = str_replace(
'\\',
DIRECTORY_SEPARATOR,
$namespace
) . DIRECTORY_SEPARATOR;
}
$file .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
foreach (self::$paths as $path) {
if (file_exists($path . DIRECTORY_SEPARATOR . $file)) {
require $path . DIRECTORY_SEPARATOR . $file;
if (is_file($path . DIRECTORY_SEPARATOR . $file)) {
include $path . DIRECTORY_SEPARATOR . $file;
if (!self::loadSuccessful($class)) {
throw new \Exception('Class ' . $class . ' was not present in ' .
if (count(spl_autoload_functions()) > 1) {
return false;
}
throw new \Exception(
'Class ' . $class . ' was not present in ' .
$path . DIRECTORY_SEPARATOR . $file .
'") [PEAR2_Autoload-0.2.4]');
'") [PEAR2_Autoload-@PACKAGE_VERSION@]'
);
}
if (in_array($class, self::$unmapped)) {
self::updateMap($class, $path . DIRECTORY_SEPARATOR . $file);
self::updateMap(
$class,
$path . DIRECTORY_SEPARATOR . $file
);
}
return true;
}
}
$e = new \Exception('Class ' . $class . ' could not be loaded from ' .
$file . ', file does not exist (registered paths="' .
implode(PATH_SEPARATOR, self::$paths) .
'") [PEAR2_Autoload-0.2.4]');
$trace = $e->getTrace();
if (isset($trace[2]) && isset($trace[2]['function']) &&
in_array($trace[2]['function'], array('class_exists', 'interface_exists'))) {
if (count(spl_autoload_functions()) > 1) {
return false;
}
if (isset($trace[1]) && isset($trace[1]['function']) &&
in_array($trace[1]['function'], array('class_exists', 'interface_exists'))) {
$e = new \Exception(
'Class ' . $class . ' could not be loaded from ' .
$file . ', file does not exist (registered paths="' .
implode(PATH_SEPARATOR, self::$paths) .
'") [PEAR2_Autoload-@PACKAGE_VERSION@]'
);
$trace = $e->getTrace();
if (isset($trace[2]) && isset($trace[2]['function'])
&& in_array($trace[2]['function'], self::$checkFunctions)
) {
return false;
}
if (isset($trace[1]) && isset($trace[1]['function'])
&& in_array($trace[1]['function'], self::$checkFunctions)
) {
return false;
}
throw $e;
@ -196,31 +324,36 @@ if (!class_exists('\PEAR2\Autoload', false)) {
/**
* Check if the requested class was loaded from the specified path
*
*
* @param string $class The name of the class to check.
*
* @return bool
*/
protected static function loadSuccessful($class)
{
if (!class_exists($class, false) && !interface_exists($class, false)) {
return false;
}
return true;
return class_exists($class, false)
|| interface_exists($class, false)
|| (in_array('trait_exists', self::$checkFunctions, true)
&& trait_exists($class, false));
}
/**
* If possible, update the classmap file with newly-discovered
* If possible, update the classmap file with newly-discovered
* mapping.
*
* @param string $class Class name discovered
*
*
* @param string $class Class name discovered
* @param string $origin File where class was found
*
*
* @return void
*/
protected static function updateMap($class, $origin)
{
if (is_writable(self::$mapfile) || is_writable(dirname(self::$mapfile))) {
if (is_writable(self::$mapfile)
|| is_writable(dirname(self::$mapfile))
) {
self::$map[$class] = $origin;
file_put_contents(self::$mapfile,
file_put_contents(
self::$mapfile,
'<'."?php\n"
. "// PEAR2\Autoload auto-generated classmap\n"
. "return " . var_export(self::$map, true) . ';',
@ -228,16 +361,16 @@ if (!class_exists('\PEAR2\Autoload', false)) {
);
}
}
/**
* return the array of paths PEAR2 autoload has registered
*
* Return the array of paths PEAR2 autoload has registered
*
* @return array
*/
static function getPaths()
public static function getPaths()
{
return self::$paths;
}
}
}
Autoload::initialize(dirname(__DIR__));
Autoload::initialize(dirname(__DIR__));

View File

@ -1,18 +1,19 @@
<?php
/**
* ~~summary~~
*
* ~~description~~
*
* Wrapper for shared memory and locking functionality across different extensions.
*
* Allows you to share data across requests as long as the PHP process is running. One of APC or WinCache is required to accomplish this, with other extensions being potentially pluggable as adapters.
*
* PHP version 5
*
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 0.1.3
* @version 0.2.0
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
@ -38,9 +39,9 @@ use PEAR2\Cache\SHM\InvalidArgumentException;
/**
* Main class for this package.
*
*
* Automatically chooses an adapter based on the available extensions.
*
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -50,18 +51,20 @@ use PEAR2\Cache\SHM\InvalidArgumentException;
abstract class SHM implements IteratorAggregate
{
/**
* @var array An array of adapter names that meet their requirements.
* An array of adapter names that meet their requirements.
*
* @var array
*/
private static $_adapters = array();
/**
* Creates a new shared memory storage.
*
* Estabilishes a separate persistent storage. Adapter is automatically
*
* Establishes a separate persistent storage. Adapter is automatically
* chosen based on the available extensions.
*
*
* @param string $persistentId The ID for the storage.
*
*
* @return static|SHM A new instance of an SHM adapter (child of this
* class).
*/
@ -79,28 +82,28 @@ abstract class SHM implements IteratorAggregate
1
);
}
/**
* Checks if the adapter meets its requirements.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public static function isMeetingRequirements()
{
return true;
}
/**
* Registers an adapter.
*
*
* Registers an SHM adapter, allowing you to call it with {@link factory()}.
*
*
* @param string $adapter FQCN of adapter. A valid adapter is one that
* extends this class. The class will be autoloaded if not already
* present.
* @param bool $prepend Whether to prepend this adapter into the list of
* possible adapters, instead of appending to it.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
final public static function registerAdapter($adapter, $prepend = false)
@ -121,244 +124,244 @@ abstract class SHM implements IteratorAggregate
}
return false;
}
/**
* Adds a value to the shared memory storage.
*
*
* Adds a value to the storage if it doesn't exist, or fails if it does.
*
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function __invoke($key, $value, $ttl = 0)
{
return $this->add($key, $value, $ttl);
}
/**
* Gets a value from the shared memory storage.
*
*
* This is a magic method, thanks to which any property you attempt to get
* the value of will be fetched from the adapter, treating the property name
* as the key of the value to get.
*
*
* @param string $key Name of key to get.
*
*
* @return mixed The current value of the specified key.
*/
public function __get($key)
{
return $this->get($key);
}
/**
* Sets a value in the shared memory storage.
*
*
* This is a magic method, thanks to which any property you attempt to set
* the value of will be set by the adapter, treating the property name as
* the key of the value to set. The value is set without a TTL.
*
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function __set($key, $value)
{
return $this->set($key, $value);
}
/**
* Checks if a specified key is in the storage.
*
*
* This is a magic method, thanks to which any property you call isset() on
* will be checked by the adapter, treating the property name as the key
* of the value to check.
*
*
* @param string $key Name of key to check.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*/
public function __isset($key)
{
return $this->exists($key);
}
/**
* Deletes a value from the shared memory storage.
*
*
* This is a magic method, thanks to which any property you attempt to unset
* the value of will be unset by the adapter, treating the property name as
* the key of the value to delete.
*
*
* @param string $key Name of key to delete.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function __unset($key)
{
return $this->delete($key);
}
/**
* Creates a new shared memory storage.
*
* Estabilishes a separate persistent storage.
*
*
* Establishes a separate persistent storage.
*
* @param string $persistentId The ID for the storage. The storage will be
* reused if it exists, or created if it doesn't exist. Data and locks
* are namespaced by this ID.
*/
abstract public function __construct($persistentId);
/**
* Obtains a named lock.
*
*
* @param string $key Name of the key to obtain. Note that $key may
* repeat for each distinct $persistentId.
* @param double $timeout If the lock can't be immediatly obtained, the
* @param double $timeout If the lock can't be immediately obtained, the
* script will block for at most the specified amount of seconds.
* Setting this to 0 makes lock obtaining non blocking, and setting it
* to NULL makes it block without a time limit.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
abstract public function lock($key, $timeout = null);
/**
* Releases a named lock.
*
*
* @param string $key Name of the key to release. Note that $key may
* repeat for each distinct $persistentId.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
abstract public function unlock($key);
/**
* Checks if a specified key is in the storage.
*
*
* @param string $key Name of key to check.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*/
abstract public function exists($key);
/**
* Adds a value to the shared memory storage.
*
*
* Adds a value to the storage if it doesn't exist, or fails if it does.
*
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
abstract public function add($key, $value, $ttl = 0);
/**
* Sets a value in the shared memory storage.
*
*
* Adds a value to the storage if it doesn't exist, overwrites it otherwise.
*
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
abstract public function set($key, $value, $ttl = 0);
/**
* Gets a value from the shared memory storage.
*
*
* Gets the current value, or throws an exception if it's not stored.
*
*
* @param string $key Name of key to get the value of.
*
*
* @return mixed The current value of the specified key.
*/
abstract public function get($key);
/**
* Deletes a value from the shared memory storage.
*
*
* @param string $key Name of key to delete.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
abstract public function delete($key);
/**
* Increases a value from the shared memory storage.
*
*
* Increases a value from the shared memory storage. Unlike a plain
* set($key, get($key)+$step) combination, this function also implicitly
* performs locking.
*
*
* @param string $key Name of key to increase.
* @param int $step Value to increase the key by.
*
*
* @return int The new value.
*/
abstract public function inc($key, $step = 1);
/**
* Decreases a value from the shared memory storage.
*
*
* Decreases a value from the shared memory storage. Unlike a plain
* set($key, get($key)-$step) combination, this function also implicitly
* performs locking.
*
*
* @param string $key Name of key to decrease.
* @param int $step Value to decrease the key by.
*
*
* @return int The new value.
*/
abstract public function dec($key, $step = 1);
/**
* Sets a new value if a key has a certain value.
*
*
* Sets a new value if a key has a certain value. This function only works
* when $old and $new are longs.
*
*
* @param string $key Key of the value to compare and set.
* @param int $old The value to compare the key against.
* @param int $new The value to set the key to.
*
* @return bool TRUE on success, FALSE on failure.
*
* @return bool TRUE on success, FALSE on failure.
*/
abstract public function cas($key, $old, $new);
/**
* Clears the persistent storage.
*
*
* Clears the persistent storage, i.e. removes all keys. Locks are left
* intact.
*
*
* @return void
*/
abstract public function clear();
/**
* Retrieve an external iterator
*
*
* Returns an external iterator.
*
*
* @param string|null $filter A PCRE regular expression.
* Only matching keys will be iterated over.
* Setting this to NULL matches all keys of this instance.
* @param bool $keysOnly Whether to return only the keys,
* or return both the keys and values.
*
*
* @return \Traversable An array with all matching keys as array keys,
* and values as array values. If $keysOnly is TRUE, the array keys are
* numeric, and the array values are key names.
@ -368,4 +371,5 @@ abstract class SHM implements IteratorAggregate
SHM::registerAdapter('\\' . __NAMESPACE__ . '\SHM\Adapter\Placebo');
SHM::registerAdapter('\\' . __NAMESPACE__ . '\SHM\Adapter\Wincache');
SHM::registerAdapter('\\' . __NAMESPACE__ . '\SHM\Adapter\APCu');
SHM::registerAdapter('\\' . __NAMESPACE__ . '\SHM\Adapter\APC');

View File

@ -1,18 +1,19 @@
<?php
/**
* ~~summary~~
*
* ~~description~~
*
* Wrapper for shared memory and locking functionality across different extensions.
*
* Allows you to share data across requests as long as the PHP process is running. One of APC or WinCache is required to accomplish this, with other extensions being potentially pluggable as adapters.
*
* PHP version 5
*
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 0.1.3
* @version 0.2.0
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
/**
@ -32,7 +33,7 @@ use ArrayObject;
/**
* Shared memory adapter for the APC extension.
*
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -42,32 +43,39 @@ use ArrayObject;
class APC extends SHM
{
/**
* @var string ID of the current storage.
* ID of the current storage.
*
* @var string
*/
protected $persistentId;
/**
* List of persistent IDs.
*
*
* A list of persistent IDs within the current request (as keys) with an int
* (as a value) specifying the number of instances in the current request.
* Used as an attempt to ensure implicit lock releases even on errors in the
* critical sections, since APC doesn't have an actual locking function.
* @var array
*
* @var array
*/
protected static $requestInstances = array();
/**
* @var array Array of lock names (as values) for each persistent ID (as
* key) obtained during the current request.
* Array of lock names for each persistent ID.
*
* Array of lock names (as values) for each persistent ID (as key) obtained
* during the current request.
*
* @var array
*/
protected static $locksBackup = array();
/**
* Creates a new shared memory storage.
*
* Estabilishes a separate persistent storage.
*
*
* Establishes a separate persistent storage.
*
* @param string $persistentId The ID for the storage. The storage will be
* reused if it exists, or created if it doesn't exist. Data and locks
* are namespaced by this ID.
@ -87,35 +95,36 @@ class APC extends SHM
true
);
}
/**
* Checks if the adapter meets its requirements.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public static function isMeetingRequirements()
{
return extension_loaded('apc')
&& version_compare(phpversion('apc'), '3.0.13', '>=')
&& version_compare(phpversion('apc'), '3.1.1', '>=')
&& ini_get('apc.enabled')
&& ('cli' !== PHP_SAPI || ini_get('apc.enable_cli'));
}
/**
* Releases all locks in a storage.
*
*
* This function is not meant to be used directly. It is implicitly called
* by the the destructor and as a shutdown function when the request ends.
* One of these calls ends up releasing any unreleased locks obtained
* during the request. A lock is also implicitly released as soon as there
* are no objects left in the current request using the same persistent ID.
*
*
* @param string $internalPersistentId The internal persistent ID, the locks
* of which are being released.
* @param bool $isAtShutdown Whether the function was executed at
* shutdown.
*
*
* @return void
*
* @internal
*/
public static function releaseLocks($internalPersistentId, $isAtShutdown)
@ -127,7 +136,7 @@ class APC extends SHM
}
}
}
/**
* Releases any locks obtained by this instance as soon as there are no more
* references to the object's persistent ID.
@ -137,18 +146,18 @@ class APC extends SHM
static::$requestInstances[$this->persistentId]--;
static::releaseLocks($this->persistentId, false);
}
/**
* Obtains a named lock.
*
*
* @param string $key Name of the key to obtain. Note that $key may
* repeat for each distinct $persistentId.
* @param double $timeout If the lock can't be immediatly obtained, the
* @param double $timeout If the lock can't be immediately obtained, the
* script will block for at most the specified amount of seconds.
* Setting this to 0 makes lock obtaining non blocking, and setting it
* to NULL makes it block without a time limit.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function lock($key, $timeout = null)
@ -164,13 +173,13 @@ class APC extends SHM
static::$locksBackup[$this->persistentId] = $key;
return true;
}
/**
* Releases a named lock.
*
*
* @param string $key Name of the key to release. Note that $key may
* repeat for each distinct $persistentId.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function unlock($key)
@ -178,69 +187,71 @@ class APC extends SHM
$lock = $this->persistentId . 'l ' . $key;
$success = apc_delete($lock);
if ($success) {
unset(static::$locksBackup[$this->persistentId][array_search(
$key,
static::$locksBackup[$this->persistentId],
true
)]);
unset(
static::$locksBackup[$this->persistentId][array_search(
$key,
static::$locksBackup[$this->persistentId],
true
)]
);
return true;
}
return false;
}
/**
* Checks if a specified key is in the storage.
*
*
* @param string $key Name of key to check.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*/
public function exists($key)
{
return apc_exists($this->persistentId . 'd ' . $key);
}
/**
* Adds a value to the shared memory storage.
*
*
* Adds a value to the storage if it doesn't exist, or fails if it does.
*
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function add($key, $value, $ttl = 0)
{
return apc_add($this->persistentId . 'd ' . $key, $value, $ttl);
}
/**
* Sets a value in the shared memory storage.
*
*
* Adds a value to the storage if it doesn't exist, overwrites it otherwise.
*
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function set($key, $value, $ttl = 0)
{
return apc_store($this->persistentId . 'd ' . $key, $value, $ttl);
}
/**
* Gets a value from the shared memory storage.
*
*
* Gets the current value, or throws an exception if it's not stored.
*
*
* @param string $key Name of key to get the value of.
*
*
* @return mixed The current value of the specified key.
*/
public function get($key)
@ -260,29 +271,29 @@ class APC extends SHM
}
throw new SHM\InvalidArgumentException('No such key in cache', 101);
}
/**
* Deletes a value from the shared memory storage.
*
*
* @param string $key Name of key to delete.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function delete($key)
{
return apc_delete($this->persistentId . 'd ' . $key);
}
/**
* Increases a value from the shared memory storage.
*
*
* Increases a value from the shared memory storage. Unlike a plain
* set($key, get($key)+$step) combination, this function also implicitly
* performs locking.
*
*
* @param string $key Name of key to increase.
* @param int $step Value to increase the key by.
*
*
* @return int The new value.
*/
public function inc($key, $step = 1)
@ -300,17 +311,17 @@ class APC extends SHM
}
return $newValue;
}
/**
* Decreases a value from the shared memory storage.
*
*
* Decreases a value from the shared memory storage. Unlike a plain
* set($key, get($key)-$step) combination, this function also implicitly
* performs locking.
*
*
* @param string $key Name of key to decrease.
* @param int $step Value to decrease the key by.
*
*
* @return int The new value.
*/
public function dec($key, $step = 1)
@ -331,27 +342,27 @@ class APC extends SHM
/**
* Sets a new value if a key has a certain value.
*
*
* Sets a new value if a key has a certain value. This function only works
* when $old and $new are longs.
*
*
* @param string $key Key of the value to compare and set.
* @param int $old The value to compare the key against.
* @param int $new The value to set the key to.
*
* @return bool TRUE on success, FALSE on failure.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function cas($key, $old, $new)
{
return apc_cas($this->persistentId . 'd ' . $key, $old, $new);
}
/**
* Clears the persistent storage.
*
*
* Clears the persistent storage, i.e. removes all keys. Locks are left
* intact.
*
*
* @return void
*/
public function clear()
@ -366,18 +377,18 @@ class APC extends SHM
apc_delete($key);
}
}
/**
* Retrieve an external iterator
*
*
* Returns an external iterator.
*
*
* @param string|null $filter A PCRE regular expression.
* Only matching keys will be iterated over.
* Setting this to NULL matches all keys of this instance.
* @param bool $keysOnly Whether to return only the keys,
* or return both the keys and values.
*
*
* @return ArrayObject An array with all matching keys as array keys,
* and values as array values. If $keysOnly is TRUE, the array keys are
* numeric, and the array values are key names.

View File

@ -0,0 +1,416 @@
<?php
/**
* Wrapper for shared memory and locking functionality across different extensions.
*
* Allows you to share data across requests as long as the PHP process is running. One of APC or WinCache is required to accomplish this, with other extensions being potentially pluggable as adapters.
*
* PHP version 5
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 0.2.0
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
/**
* The namespace declaration.
*/
namespace PEAR2\Cache\SHM\Adapter;
/**
* Throws exceptions from this namespace, and extends from this class.
*/
use PEAR2\Cache\SHM;
/**
* {@link APC::getIterator()} returns this object.
*/
use ArrayObject;
/**
* Shared memory adapter for the APC extension.
*
* @category Caching
* @package PEAR2_Cache_SHM
* @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_Cache_SHM
*/
class APCu extends SHM
{
/**
* ID of the current storage.
*
* @var string
*/
protected $persistentId;
/**
* List of persistent IDs.
*
* A list of persistent IDs within the current request (as keys) with an int
* (as a value) specifying the number of instances in the current request.
* Used as an attempt to ensure implicit lock releases even on errors in the
* critical sections, since APC doesn't have an actual locking function.
*
* @var array
*/
protected static $requestInstances = array();
/**
* Array of lock names for each persistent ID.
*
* Array of lock names (as values) for each persistent ID (as key) obtained
* during the current request.
*
* @var array
*/
protected static $locksBackup = array();
/**
* Creates a new shared memory storage.
*
* Establishes a separate persistent storage.
*
* @param string $persistentId The ID for the storage. The storage will be
* reused if it exists, or created if it doesn't exist. Data and locks
* are namespaced by this ID.
*/
public function __construct($persistentId)
{
$this->persistentId = __CLASS__ . ' ' . $persistentId;
if (isset(static::$requestInstances[$this->persistentId])) {
static::$requestInstances[$this->persistentId]++;
} else {
static::$requestInstances[$this->persistentId] = 1;
static::$locksBackup[$this->persistentId] = array();
}
register_shutdown_function(
get_called_class() . '::releaseLocks',
$this->persistentId,
true
);
}
/**
* Checks if the adapter meets its requirements.
*
* @return bool TRUE on success, FALSE on failure.
*/
public static function isMeetingRequirements()
{
return extension_loaded('apcu')
&& version_compare(phpversion('apcu'), '5.0.0', '>=')
&& ini_get('apc.enabled')
&& ('cli' !== PHP_SAPI || ini_get('apc.enable_cli'));
}
/**
* Releases all locks in a storage.
*
* This function is not meant to be used directly. It is implicitly called
* by the the destructor and as a shutdown function when the request ends.
* One of these calls ends up releasing any unreleased locks obtained
* during the request. A lock is also implicitly released as soon as there
* are no objects left in the current request using the same persistent ID.
*
* @param string $internalPersistentId The internal persistent ID, the locks
* of which are being released.
* @param bool $isAtShutdown Whether the function was executed at
* shutdown.
*
* @return void
*
* @internal
*/
public static function releaseLocks($internalPersistentId, $isAtShutdown)
{
$hasInstances = 0 !== static::$requestInstances[$internalPersistentId];
if ($isAtShutdown === $hasInstances) {
foreach (static::$locksBackup[$internalPersistentId] as $key) {
apcu_delete($internalPersistentId . 'l ' . $key);
}
}
}
/**
* Releases any locks obtained by this instance as soon as there are no more
* references to the object's persistent ID.
*/
public function __destruct()
{
static::$requestInstances[$this->persistentId]--;
static::releaseLocks($this->persistentId, false);
}
/**
* Obtains a named lock.
*
* @param string $key Name of the key to obtain. Note that $key may
* repeat for each distinct $persistentId.
* @param double $timeout If the lock can't be immediately obtained, the
* script will block for at most the specified amount of seconds.
* Setting this to 0 makes lock obtaining non blocking, and setting it
* to NULL makes it block without a time limit.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function lock($key, $timeout = null)
{
$lock = $this->persistentId . 'l ' . $key;
$hasTimeout = $timeout !== null;
$start = microtime(true);
while (!apcu_add($lock, 1)) {
if ($hasTimeout && (microtime(true) - $start) > $timeout) {
return false;
}
}
static::$locksBackup[$this->persistentId] = $key;
return true;
}
/**
* Releases a named lock.
*
* @param string $key Name of the key to release. Note that $key may
* repeat for each distinct $persistentId.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function unlock($key)
{
$lock = $this->persistentId . 'l ' . $key;
$success = apcu_delete($lock);
if ($success) {
unset(
static::$locksBackup[$this->persistentId][array_search(
$key,
static::$locksBackup[$this->persistentId],
true
)]
);
return true;
}
return false;
}
/**
* Checks if a specified key is in the storage.
*
* @param string $key Name of key to check.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*/
public function exists($key)
{
return apcu_exists($this->persistentId . 'd ' . $key);
}
/**
* Adds a value to the shared memory storage.
*
* Adds a value to the storage if it doesn't exist, or fails if it does.
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function add($key, $value, $ttl = 0)
{
return apcu_add($this->persistentId . 'd ' . $key, $value, $ttl);
}
/**
* Sets a value in the shared memory storage.
*
* Adds a value to the storage if it doesn't exist, overwrites it otherwise.
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function set($key, $value, $ttl = 0)
{
return apcu_store($this->persistentId . 'd ' . $key, $value, $ttl);
}
/**
* Gets a value from the shared memory storage.
*
* Gets the current value, or throws an exception if it's not stored.
*
* @param string $key Name of key to get the value of.
*
* @return mixed The current value of the specified key.
*/
public function get($key)
{
$fullKey = $this->persistentId . 'd ' . $key;
if (apcu_exists($fullKey)) {
$value = apcu_fetch($fullKey, $success);
if (!$success) {
throw new SHM\InvalidArgumentException(
'Unable to fetch key. ' .
'Key has either just now expired or (if no TTL was set) ' .
'is possibly in a race condition with another request.',
100
);
}
return $value;
}
throw new SHM\InvalidArgumentException('No such key in cache', 101);
}
/**
* Deletes a value from the shared memory storage.
*
* @param string $key Name of key to delete.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function delete($key)
{
return apcu_delete($this->persistentId . 'd ' . $key);
}
/**
* Increases a value from the shared memory storage.
*
* Increases a value from the shared memory storage. Unlike a plain
* set($key, get($key)+$step) combination, this function also implicitly
* performs locking.
*
* @param string $key Name of key to increase.
* @param int $step Value to increase the key by.
*
* @return int The new value.
*/
public function inc($key, $step = 1)
{
$newValue = apcu_inc(
$this->persistentId . 'd ' . $key,
(int) $step,
$success
);
if (!$success) {
throw new SHM\InvalidArgumentException(
'Unable to increase the value. Are you sure the value is int?',
102
);
}
return $newValue;
}
/**
* Decreases a value from the shared memory storage.
*
* Decreases a value from the shared memory storage. Unlike a plain
* set($key, get($key)-$step) combination, this function also implicitly
* performs locking.
*
* @param string $key Name of key to decrease.
* @param int $step Value to decrease the key by.
*
* @return int The new value.
*/
public function dec($key, $step = 1)
{
$newValue = apcu_dec(
$this->persistentId . 'd ' . $key,
(int) $step,
$success
);
if (!$success) {
throw new SHM\InvalidArgumentException(
'Unable to decrease the value. Are you sure the value is int?',
103
);
}
return $newValue;
}
/**
* Sets a new value if a key has a certain value.
*
* Sets a new value if a key has a certain value. This function only works
* when $old and $new are longs.
*
* @param string $key Key of the value to compare and set.
* @param int $old The value to compare the key against.
* @param int $new The value to set the key to.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function cas($key, $old, $new)
{
return apcu_cas($this->persistentId . 'd ' . $key, $old, $new);
}
/**
* Clears the persistent storage.
*
* Clears the persistent storage, i.e. removes all keys. Locks are left
* intact.
*
* @return void
*/
public function clear()
{
foreach (new APCIterator(
'user',
'/^' . preg_quote($this->persistentId, '/') . 'd /',
APC_ITER_KEY,
100,
APC_LIST_ACTIVE
) as $key) {
apcu_delete($key);
}
}
/**
* Retrieve an external iterator
*
* Returns an external iterator.
*
* @param string|null $filter A PCRE regular expression.
* Only matching keys will be iterated over.
* Setting this to NULL matches all keys of this instance.
* @param bool $keysOnly Whether to return only the keys,
* or return both the keys and values.
*
* @return ArrayObject An array with all matching keys as array keys,
* and values as array values. If $keysOnly is TRUE, the array keys are
* numeric, and the array values are key names.
*/
public function getIterator($filter = null, $keysOnly = false)
{
$result = array();
foreach (new APCUIterator(
'/^' . preg_quote($this->persistentId, '/') . 'd /',
APC_ITER_KEY,
100,
APC_LIST_ACTIVE
) as $key) {
$localKey = strstr($key, $this->persistentId . 'd ');
if (null === $filter || preg_match($filter, $localKey)) {
if ($keysOnly) {
$result[] = $localKey;
} else {
$result[$localKey] = apcu_fetch($key);
}
}
}
return new ArrayObject($result);
}
}

View File

@ -1,18 +1,19 @@
<?php
/**
* ~~summary~~
*
* ~~description~~
*
* Wrapper for shared memory and locking functionality across different extensions.
*
* Allows you to share data across requests as long as the PHP process is running. One of APC or WinCache is required to accomplish this, with other extensions being potentially pluggable as adapters.
*
* PHP version 5
*
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 0.1.3
* @version 0.2.0
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
/**
@ -31,10 +32,10 @@ use PEAR2\Cache\SHM;
use ArrayObject;
/**
* This adapter is not truly persistent. It is intended to emulate persistency
* This adapter is not truly persistent. It is intended to emulate persistence
* in non persistent environments, so that upper level applications can use a
* single code path for persistent and non persistent code.
*
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -44,42 +45,50 @@ use ArrayObject;
class Placebo extends SHM
{
/**
* @var string ID of the current storage.
* ID of the current storage.
*
* @var string
*/
protected $persistentId;
/**
* List of persistent IDs.
*
*
* A list of persistent IDs within the current request (as keys) with an int
* (as a value) specifying the number of instances in the current request.
* Used as an attempt to ensure implicit lock releases on destruction.
* @var array
*
* @var array
*/
protected static $requestInstances = array();
/**
* @var array Array of lock names (as values) for each persistent ID (as
* Array of lock names for each persistent ID.
*
* Array of lock names (as values) for each persistent ID (as
* key) obtained during the current request.
*
* @var array
*/
protected static $locksBackup = array();
/**
* The data storage.
*
*
* Each persistent ID is a key, and the value is an array.
* Each such array has data keys as its keys, and an array as a value.
* Each such array has as its elements the value, the timeout and the time
* the data was set.
* @var array
*
* @var array
*/
protected static $data = array();
/**
* Creates a new shared memory storage.
*
* Estabilishes a separate persistent storage.
*
*
* Establishes a separate persistent storage.
*
* @param string $persistentId The ID for the storage. The storage will be
* reused if it exists, or created if it doesn't exist. Data and locks
* are namespaced by this ID.
@ -95,9 +104,9 @@ class Placebo extends SHM
}
$this->persistentId = $persistentId;
}
/**
* Releases any unreleased locks.
* Releases any unreleased locks.
*/
public function __destruct()
{
@ -105,23 +114,23 @@ class Placebo extends SHM
static::$locksBackup[$this->persistentId] = array();
}
}
/**
* Checks if the adapter meets its requirements.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public static function isMeetingRequirements()
{
return 'cli' === PHP_SAPI;
}
/**
* Pretends to obtain a lock.
*
*
* @param string $key Ignored.
* @param double $timeout Ignored.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function lock($key, $timeout = null)
@ -133,12 +142,12 @@ class Placebo extends SHM
static::$locksBackup[$this->persistentId][] = $key;
return true;
}
/**
* Pretends to release a lock.
*
*
* @param string $key Ignored
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function unlock($key)
@ -147,36 +156,38 @@ class Placebo extends SHM
if (!in_array($key, static::$locksBackup[$this->persistentId], true)) {
return false;
}
unset(static::$locksBackup[$this->persistentId][array_search(
$key,
static::$locksBackup[$this->persistentId],
true
)]);
unset(
static::$locksBackup[$this->persistentId][array_search(
$key,
static::$locksBackup[$this->persistentId],
true
)]
);
return true;
}
/**
* Checks if a specified key is in the storage.
*
*
* @param string $key Name of key to check.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*/
public function exists($key)
{
return array_key_exists($key, static::$data[$this->persistentId]);
}
/**
* Adds a value to the shared memory storage.
*
*
* Adds a value to the storage if it doesn't exist, or fails if it does.
*
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Because "true" adapters purge the cache at the next
* request, this setting is ignored.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function add($key, $value, $ttl = 0)
@ -186,17 +197,17 @@ class Placebo extends SHM
}
return $this->set($key, $value, $ttl);
}
/**
* Sets a value in the shared memory storage.
*
*
* Adds a value to the storage if it doesn't exist, overwrites it otherwise.
*
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Because "true" adapters purge the cache at the next
* request, this setting is ignored.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function set($key, $value, $ttl = 0)
@ -204,14 +215,14 @@ class Placebo extends SHM
static::$data[$this->persistentId][$key] = $value;
return true;
}
/**
* Gets a value from the shared memory storage.
*
*
* Gets the current value, or throws an exception if it's not stored.
*
*
* @param string $key Name of key to get the value of.
*
*
* @return mixed The current value of the specified key.
*/
public function get($key)
@ -224,12 +235,12 @@ class Placebo extends SHM
200
);
}
/**
* Deletes a value from the shared memory storage.
*
*
* @param string $key Name of key to delete.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function delete($key)
@ -240,17 +251,17 @@ class Placebo extends SHM
}
return false;
}
/**
* Increases a value from the shared memory storage.
*
*
* Increases a value from the shared memory storage. Unlike a plain
* set($key, get($key)+$step) combination, this function also implicitly
* performs locking.
*
*
* @param string $key Name of key to increase.
* @param int $step Value to increase the key by.
*
*
* @return int The new value.
*/
public function inc($key, $step = 1)
@ -265,17 +276,17 @@ class Placebo extends SHM
}
return $this->get($key);
}
/**
* Decreases a value from the shared memory storage.
*
*
* Decreases a value from the shared memory storage. Unlike a plain
* set($key, get($key)-$step) combination, this function also implicitly
* performs locking.
*
*
* @param string $key Name of key to decrease.
* @param int $step Value to decrease the key by.
*
*
* @return int The new value.
*/
public function dec($key, $step = 1)
@ -293,46 +304,46 @@ class Placebo extends SHM
/**
* Sets a new value if a key has a certain value.
*
*
* Sets a new value if a key has a certain value. This function only works
* when $old and $new are longs.
*
*
* @param string $key Key of the value to compare and set.
* @param int $old The value to compare the key against.
* @param int $new The value to set the key to.
*
* @return bool TRUE on success, FALSE on failure.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function cas($key, $old, $new)
{
return $this->exists($key) && ($this->get($key) === $old)
&& is_int($new) && $this->set($key, $new);
}
/**
* Clears the persistent storage.
*
*
* Clears the persistent storage, i.e. removes all keys. Locks are left
* intact.
*
*
* @return void
*/
public function clear()
{
static::$data[$this->persistentId] = array();
}
/**
* Retrieve an external iterator
*
*
* Returns an external iterator.
*
*
* @param string|null $filter A PCRE regular expression.
* Only matching keys will be iterated over.
* Setting this to NULL matches all keys of this instance.
* @param bool $keysOnly Whether to return only the keys,
* or return both the keys and values.
*
*
* @return ArrayObject An array with all matching keys as array keys,
* and values as array values. If $keysOnly is TRUE, the array keys are
* numeric, and the array values are key names.
@ -346,7 +357,7 @@ class Placebo extends SHM
: static::$data[$this->persistentId]
);
}
$result = array();
foreach (static::$data[$this->persistentId] as $key => $value) {
if (preg_match($filter, $key)) {

View File

@ -1,18 +1,19 @@
<?php
/**
* ~~summary~~
*
* ~~description~~
*
* Wrapper for shared memory and locking functionality across different extensions.
*
* Allows you to share data across requests as long as the PHP process is running. One of APC or WinCache is required to accomplish this, with other extensions being potentially pluggable as adapters.
*
* PHP version 5
*
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
* @copyright 2011 Vasil Rangelov
* @license http://www.gnu.org/copyleft/lesser.html LGPL License 2.1
* @version 0.1.3
* @version 0.2.0
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
/**
@ -32,7 +33,7 @@ use ArrayObject;
/**
* Shared memory adapter for the WinCache extension.
*
*
* @category Caching
* @package PEAR2_Cache_SHM
* @author Vasil Rangelov <boen.robot@gmail.com>
@ -42,30 +43,35 @@ use ArrayObject;
class Wincache extends SHM
{
/**
* @var string ID of the current storage.
* ID of the current storage.
*
* @var string
*/
protected $persistentId;
/**
* List of persistent IDs.
*
*
* A list of persistent IDs within the current request (as keys) with an int
* (as a value) specifying the number of instances in the current request.
* Used as an attempt to ensure implicit lock releases on destruction.
* @var array
*
* @var array
*/
protected static $requestInstances = array();
/**
* @var array Array of lock names obtained during the current request.
* Array of lock names obtained during the current request.
*
* @var array
*/
protected static $locksBackup = array();
/**
* Creates a new shared memory storage.
*
* Estabilishes a separate persistent storage.
*
*
* Establishes a separate persistent storage.
*
* @param string $persistentId The ID for the storage. The storage will be
* reused if it exists, or created if it doesn't exist. Data and locks
* are namespaced by this ID.
@ -81,28 +87,29 @@ class Wincache extends SHM
static::$locksBackup[$this->persistentId] = array();
}
}
/**
* Encodes a lock name
*
*
* Encodes a lock name, so that it can be properly obtained. The scheme used
* is a subset of URL encoding, with only the "%" and "\" characters being
* escaped. The encoding itself is necessary, since lock names can't contain
* the "\" character.
*
*
* @param string $name The lock name to encode.
*
*
* @return string The encoded name.
*
* @link http://msdn.microsoft.com/en-us/library/ms682411(VS.85).aspx
*/
protected static function encodeLockName($name)
{
return str_replace(array('%', '\\'), array('%25', '%5C'), $name);
}
/**
* Checks if the adapter meets its requirements.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public static function isMeetingRequirements()
@ -112,7 +119,7 @@ class Wincache extends SHM
&& ini_get('wincache.ucenabled')
&& ('cli' !== PHP_SAPI || ini_get('wincache.enablecli'));
}
/**
* Releases any locks obtained by this instance as soon as there are no more
* references to the object's persistent ID.
@ -128,15 +135,15 @@ class Wincache extends SHM
}
}
/**
* Obtains a named lock.
*
*
* @param string $key Name of the key to obtain. Note that $key may
* repeat for each distinct $persistentId.
* @param double $timeout Ignored with WinCache. Script will always block if
* the lock can't be immediatly obtained.
*
* the lock can't be immediately obtained.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function lock($key, $timeout = null)
@ -149,13 +156,13 @@ class Wincache extends SHM
}
return $result;
}
/**
* Releases a named lock.
*
*
* @param string $key Name of the key to release. Note that $key may
* repeat for each distinct $persistentId.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function unlock($key)
@ -164,68 +171,70 @@ class Wincache extends SHM
$this->persistentId . static::encodeLockName($key)
);
if ($result) {
unset(static::$locksBackup[$this->persistentId][array_search(
$key,
static::$locksBackup[$this->persistentId],
true
)]);
unset(
static::$locksBackup[$this->persistentId][array_search(
$key,
static::$locksBackup[$this->persistentId],
true
)]
);
}
return $result;
}
/**
* Checks if a specified key is in the storage.
*
*
* @param string $key Name of key to check.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*
* @return bool TRUE if the key is in the storage, FALSE otherwise.
*/
public function exists($key)
{
return wincache_ucache_exists($this->persistentId . $key);
}
/**
* Adds a value to the shared memory storage.
*
*
* Sets a value to the storage if it doesn't exist, or fails if it does.
*
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function add($key, $value, $ttl = 0)
{
return wincache_ucache_add($this->persistentId . $key, $value, $ttl);
}
/**
* Sets a value in the shared memory storage.
*
*
* Adds a value to the storage if it doesn't exist, overwrites it otherwise.
*
*
* @param string $key Name of key to associate the value with.
* @param mixed $value Value for the specified key.
* @param int $ttl Seconds to store the value. If set to 0 indicates no
* time limit.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function set($key, $value, $ttl = 0)
{
return wincache_ucache_set($this->persistentId . $key, $value, $ttl);
}
/**
* Gets a value from the shared memory storage.
*
*
* Gets the current value, or throws an exception if it's not stored.
*
*
* @param string $key Name of key to get the value of.
*
*
* @return mixed The current value of the specified key.
*/
public function get($key)
@ -239,29 +248,29 @@ class Wincache extends SHM
}
return $value;
}
/**
* Deletes a value from the shared memory storage.
*
*
* @param string $key Name of key to delete.
*
*
* @return bool TRUE on success, FALSE on failure.
*/
public function delete($key)
{
return wincache_ucache_delete($this->persistentId . $key);
}
/**
* Increases a value from the shared memory storage.
*
*
* Increases a value from the shared memory storage. Unlike a plain
* set($key, get($key)+$step) combination, this function also implicitly
* performs locking.
*
*
* @param string $key Name of key to increase.
* @param int $step Value to increase the key by.
*
*
* @return int The new value.
*/
public function inc($key, $step = 1)
@ -279,17 +288,17 @@ class Wincache extends SHM
}
return $newValue;
}
/**
* Decreases a value from the shared memory storage.
*
*
* Decreases a value from the shared memory storage. Unlike a plain
* set($key, get($key)-$step) combination, this function also implicitly
* performs locking.
*
*
* @param string $key Name of key to decrease.
* @param int $step Value to decrease the key by.
*
*
* @return int The new value.
*/
public function dec($key, $step = 1)
@ -310,27 +319,27 @@ class Wincache extends SHM
/**
* Sets a new value if a key has a certain value.
*
*
* Sets a new value if a key has a certain value. This function only works
* when $old and $new are longs.
*
*
* @param string $key Key of the value to compare and set.
* @param int $old The value to compare the key against.
* @param int $new The value to set the key to.
*
* @return bool TRUE on success, FALSE on failure.
*
* @return bool TRUE on success, FALSE on failure.
*/
public function cas($key, $old, $new)
{
return wincache_ucache_cas($this->persistentId . $key, $old, $new);
}
/**
* Clears the persistent storage.
*
*
* Clears the persistent storage, i.e. removes all keys. Locks are left
* intact.
*
*
* @return void
*/
public function clear()
@ -344,18 +353,18 @@ class Wincache extends SHM
}
}
}
/**
* Retrieve an external iterator
*
*
* Returns an external iterator.
*
*
* @param string|null $filter A PCRE regular expression.
* Only matching keys will be iterated over.
* Setting this to NULL matches all keys of this instance.
* @param bool $keysOnly Whether to return only the keys,
* or return both the keys and values.
*
*
* @return ArrayObject An array with all matching keys as array keys,
* and values as array values. If $keysOnly is TRUE, the array keys are
* numeric, and the array values are key names.

View File

@ -1,9 +1,10 @@
<?php
/**
* ~~summary~~
* Wrapper for shared memory and locking functionality across different extensions.
*
* ~~description~~
* Allows you to share data across requests as long as the PHP process is running. One of APC or WinCache is required to accomplish this, with other extensions being potentially pluggable as adapters.
*
* PHP version 5
*
@ -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 0.1.3
* @version 0.2.0
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
/**

View File

@ -1,9 +1,10 @@
<?php
/**
* ~~summary~~
* Wrapper for shared memory and locking functionality across different extensions.
*
* ~~description~~
* Allows you to share data across requests as long as the PHP process is running. One of APC or WinCache is required to accomplish this, with other extensions being potentially pluggable as adapters.
*
* PHP version 5
*
@ -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 0.1.3
* @version 0.2.0
* @link http://pear2.php.net/PEAR2_Cache_SHM
*/
/**

View File

@ -59,6 +59,7 @@ class CommandLine
* Error messages.
*
* @var array $errors Error messages
*
* @todo move this to PEAR2\Console\CommandLine\MessageProvider
*/
public static $errors = array(
@ -130,7 +131,7 @@ class CommandLine
/**
* The command line parser renderer instance.
*
* @var object that implements PEAR2\Console\CommandLine\Renderer interface
* @var PEAR2\Console\CommandLine\Renderer a renderer
*/
public $renderer = false;
@ -144,7 +145,7 @@ class CommandLine
/**
* The command line message provider instance.
*
* @var PEAR2\Console\CommandLine\MessageProvider A message provider instance
* @var PEAR2\Console\CommandLine\MessageProvider A message provider
*/
public $message_provider = false;
@ -191,6 +192,7 @@ class CommandLine
* convenience.
*
* @var PEAR2\Console\CommandLine The parent instance
*
* @todo move CommandLine::parent to CommandLine\Command
*/
public $parent = false;
@ -272,7 +274,7 @@ class CommandLine
* </code>
*
* @var array
* @see PEAR2\Console\CommandLine\MessageProvider_Default
* @see PEAR2\Console\CommandLine\MessageProvider\DefaultProvider
*/
public $messages = array();
@ -286,6 +288,9 @@ class CommandLine
*/
private $_dispatchLater = array();
private $_lastopt = false;
private $_stopflag = false;
// }}}
// __construct() {{{
@ -345,7 +350,7 @@ class CommandLine
// set default instances
$this->renderer = new CommandLine\Renderer_Default($this);
$this->outputter = new CommandLine\Outputter_Default();
$this->message_provider = new CommandLine\MessageProvider_Default();
$this->message_provider = new CommandLine\MessageProvider\DefaultProvider();
}
// }}}
@ -481,6 +486,7 @@ class CommandLine
* @param array $params An array containing the argument attributes
*
* @return PEAR2\Console\CommandLine\Argument the added argument
*
* @see PEAR2\Console\CommandLine\Argument
*/
public function addArgument($name, $params = array())
@ -842,6 +848,7 @@ class CommandLine
* @param array $params An array of search=>replaces entries
*
* @return void
*
* @todo remove Console::triggerError() and use exceptions only
*/
public static function triggerError($msgId, $level, $params=array())
@ -912,7 +919,7 @@ class CommandLine
// Check if an invalid subcommand was specified. If there are
// subcommands and no arguments, but an argument was provided, it is
// an invalid subcommand.
if ( count($this->commands) > 0
if (count($this->commands) > 0
&& count($this->args) === 0
&& count($args) > 0
) {
@ -925,7 +932,7 @@ class CommandLine
}
// if subcommand_required is set to true we must check that we have a
// subcommand.
if ( count($this->commands)
if (count($this->commands)
&& $this->subcommand_required
&& !$result->command_name
) {
@ -989,23 +996,21 @@ class CommandLine
*/
protected function parseToken($token, $result, &$args, $argc)
{
static $lastopt = false;
static $stopflag = false;
$last = $argc === 0;
if (!$stopflag && $lastopt) {
if (!$this->_stopflag && $this->_lastopt) {
if (substr($token, 0, 1) == '-') {
if ($lastopt->argument_optional) {
$this->_dispatchAction($lastopt, '', $result);
if ($lastopt->action != 'StoreArray') {
$lastopt = false;
if ($this->_lastopt->argument_optional) {
$this->_dispatchAction($this->_lastopt, '', $result);
if ($this->_lastopt->action != 'StoreArray') {
$this->_lastopt = false;
}
} else if (isset($result->options[$lastopt->name])) {
} else if (isset($result->options[$this->_lastopt->name])) {
// case of an option that expect a list of args
$lastopt = false;
$this->_lastopt = false;
} else {
throw CommandLine\Exception::factory(
'OPTION_VALUE_REQUIRED',
array('name' => $lastopt->name),
array('name' => $this->_lastopt->name),
$this,
$this->messages
);
@ -1015,8 +1020,8 @@ class CommandLine
// is to consider that if there's already an element in the
// array, and the commandline expects one or more args, we
// leave last tokens to arguments
if ($lastopt->action == 'StoreArray'
&& !empty($result->options[$lastopt->name])
if ($this->_lastopt->action == 'StoreArray'
&& !empty($result->options[$this->_lastopt->name])
&& count($this->args) > ($argc + count($args))
) {
if (!is_null($token)) {
@ -1024,22 +1029,22 @@ class CommandLine
}
return;
}
if (!is_null($token) || $lastopt->action == 'Password') {
$this->_dispatchAction($lastopt, $token, $result);
if (!is_null($token) || $this->_lastopt->action == 'Password') {
$this->_dispatchAction($this->_lastopt, $token, $result);
}
if ($lastopt->action != 'StoreArray') {
$lastopt = false;
if ($this->_lastopt->action != 'StoreArray') {
$this->_lastopt = false;
}
return;
}
}
if (!$stopflag && substr($token, 0, 2) == '--') {
if (!$this->_stopflag && substr($token, 0, 2) == '--') {
// a long option
$optkv = explode('=', $token, 2);
if (trim($optkv[0]) == '--') {
// the special argument "--" forces in all cases the end of
// option scanning.
$stopflag = true;
$this->_stopflag = true;
return;
}
$opt = $this->findOption($optkv[0]);
@ -1072,14 +1077,14 @@ class CommandLine
);
}
// we will have a value next time
$lastopt = $opt;
$this->_lastopt = $opt;
return;
}
if ($opt->action == 'StoreArray') {
$lastopt = $opt;
$this->_lastopt = $opt;
}
$this->_dispatchAction($opt, $value, $result);
} else if (!$stopflag && substr($token, 0, 1) == '-') {
} else if (!$this->_stopflag && substr($token, 0, 1) == '-') {
// a short option
$optname = substr($token, 0, 2);
if ($optname == '-') {
@ -1100,7 +1105,7 @@ class CommandLine
// in short: handle -f<value> and -f <value>
$next = substr($token, 2, 1);
// check if we must wait for a value
if ($next === false) {
if (!$next) {
if ($opt->expectsArgument()) {
if ($last && !$opt->argument_optional) {
throw CommandLine\Exception::factory(
@ -1111,7 +1116,7 @@ class CommandLine
);
}
// we will have a value next time
$lastopt = $opt;
$this->_lastopt = $opt;
return;
}
$value = false;
@ -1136,7 +1141,7 @@ class CommandLine
}
}
if ($opt->action == 'StoreArray') {
$lastopt = $opt;
$this->_lastopt = $opt;
}
$value = substr($token, 2);
}
@ -1145,8 +1150,8 @@ class CommandLine
// We have an argument.
// if we are in POSIX compliant mode, we must set the stop flag to
// true in order to stop option parsing.
if (!$stopflag && $this->force_posix) {
$stopflag = true;
if (!$this->_stopflag && $this->force_posix) {
$this->_stopflag = true;
}
if (!is_null($token)) {
$args[] = $token;

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
namespace PEAR2\Console\CommandLine;

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
namespace PEAR2\Console\CommandLine\Action;

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
@ -46,7 +47,7 @@ use PEAR2\Console\CommandLine;
* <code>
* $ script.php -v -v -v
* </code>
* or:
* or:
* <code>
* $ script.php -vvv
* </code>

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/

View File

@ -11,21 +11,22 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version CVS: $Id: List.php,v 1.2 2009/02/27 08:03:17 izi Exp $
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
namespace PEAR2\Console\CommandLine;
/**
* Class that represent the List action, a special action that simply output an
* Class that represent the List action, a special action that simply output an
* array as a list.
*
* @category Console
@ -43,10 +44,10 @@ class Action_List extends Action
/**
* Executes the action with the value entered by the user.
* Possible parameters are:
* - message: an alternative message to display instead of the default
* - message: an alternative message to display instead of the default
* message,
* - delimiter: an alternative delimiter instead of the comma,
* - post: a string to append after the message (default is the new line
* - post: a string to append after the message (default is the new line
* char).
*
* @param mixed $value The option value
@ -57,8 +58,8 @@ class Action_List extends Action
public function execute($value = false, $params = array())
{
$list = isset($params['list']) ? $params['list'] : array();
$msg = isset($params['message'])
? $params['message']
$msg = isset($params['message'])
? $params['message']
: $this->parser->message_provider->get('LIST_DISPLAYED_MESSAGE');
$del = isset($params['delimiter']) ? $params['delimiter'] : ', ';
$post = isset($params['post']) ? $params['post'] : "\n";

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
@ -27,8 +28,8 @@ namespace PEAR2\Console\CommandLine\Action;
use PEAR2\Console\CommandLine;
/**
* Class that represent the Password action, a special action that allow the
* user to specify the password on the commandline or to be prompted for
* Class that represent the Password action, a special action that allow the
* user to specify the password on the commandline or to be prompted for
* entering it.
*
* @category Console
@ -62,7 +63,8 @@ class Password extends CommandLine\Action
* Prompts the password to the user without echoing it.
*
* @return string
* @todo not echo-ing the password does not work on windows is there a way
*
* @todo not echo-ing the password does not work on windows is there a way
* to make this work ?
*/
private function _promptPassword()

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
@ -29,7 +30,7 @@ use PEAR2\Console\CommandLine;
/**
* Class that represent the StoreArray action.
*
* The execute method appends the value of the option entered by the user to
* The execute method appends the value of the option entered by the user to
* the result option array entry.
*
* @category Console

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
@ -30,7 +31,7 @@ use PEAR2\Console\CommandLine;
* Class that represent the StoreFalse action.
*
* The execute method store the boolean 'false' in the corrsponding result
* option array entry (the value is true if the option is not present in the
* option array entry (the value is true if the option is not present in the
* command line entered by the user).
*
* @category Console

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
@ -30,7 +31,7 @@ use PEAR2\Console\CommandLine;
* Class that represent the StoreInt action.
*
* The execute method store the value of the option entered by the user as an
* integer in the result option array entry, if the value passed is not an
* integer in the result option array entry, if the value passed is not an
* integer an Exception is raised.
*
* @category Console

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
@ -29,7 +30,7 @@ use PEAR2\Console\CommandLine;
/**
* Class that represent the StoreString action.
*
* The execute method store the value of the option entered by the user as a
* The execute method store the value of the option entered by the user as a
* string in the result option array entry.
*
* @category Console

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
@ -30,7 +31,7 @@ use PEAR2\Console\CommandLine;
* Class that represent the StoreTrue action.
*
* The execute method store the boolean 'true' in the corrsponding result
* option array entry (the value is false if the option is not present in the
* option array entry (the value is false if the option is not present in the
* command line entered by the user).
*
* @category Console

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/

View File

@ -16,9 +16,10 @@
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
@ -65,6 +66,7 @@ class Argument extends Element
*
* @return void
* @throws PEAR2\Console\CommandLine\Exception
*
* @todo use exceptions
*/
public function validate()

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
@ -27,7 +28,7 @@ namespace PEAR2\Console\CommandLine;
/**
* Class that represent a command with option and arguments.
*
* This class exist just to clarify the interface but at the moment it is
* This class exist just to clarify the interface but at the moment it is
* strictly identical to PEAR2\Console\CommandLine class, it could change in the
* future though.
*
@ -60,7 +61,7 @@ class Command extends \PEAR2\Console\CommandLine
*
* @return void
*/
public function __construct($params = array())
public function __construct($params = array())
{
if (isset($params['aliases'])) {
$this->aliases = $params['aliases'];

View File

@ -20,6 +20,7 @@
* @version CVS: $Id: CustomMessageProvider.php 282427 2009-06-19 10:22:48Z izi $
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 1.1.0
*
* @filesource
*/
@ -56,8 +57,9 @@ interface CustomMessageProvider
* indexes are message codes.
*
* @return string
*
* @see PEAR2\Console\CommandLine_MessageProvider
* @see PEAR2\Console\CommandLine_MessageProvider_Default
* @see PEAR2\Console\CommandLine_MessageProvider\DefaultProvider
*/
public function getWithCustomMessages(
$code, $vars = array(), $messages = array()

View File

@ -16,9 +16,10 @@
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
@ -92,7 +93,7 @@ abstract class Element
* </code>
*
* @var array
* @see PEAR2\Console\CommandLine_MessageProvider_Default
* @see PEAR2\Console\CommandLine_MessageProvider\DefaultProvider
*/
public $messages = array();
@ -124,6 +125,7 @@ abstract class Element
* Returns the string representation of the element.
*
* @return string The string representation of the element
*
* @todo use __toString() instead
*/
public function toString()

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
@ -42,14 +43,15 @@ interface MessageProvider
/**
* Retrieves the given string identifier corresponding message.
* For a list of identifiers please see the provided default message
* For a list of identifiers please see the provided default message
* provider.
*
* @param string $code The string identifier of the message
* @param array $vars An array of template variables
*
* @return string
* @see PEAR2\Console\CommandLine_MessageProvider_Default
*
* @see PEAR2\Console\CommandLine\MessageProvider\DefaultProvider
*/
public function get($code, $vars=array());

View File

@ -16,13 +16,17 @@
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
namespace PEAR2\Console\CommandLine;
namespace PEAR2\Console\CommandLine\MessageProvider;
use PEAR2\Console\CommandLine\MessageProvider;
use PEAR2\Console\CommandLine\CustomMessageProvider;
/**
* Lightweight class that manages messages used by PEAR2\Console\CommandLine package,
@ -37,7 +41,7 @@ namespace PEAR2\Console\CommandLine;
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since Class available since release 0.1.0
*/
class MessageProvider_Default
class DefaultProvider
implements MessageProvider,
CustomMessageProvider
{

View File

@ -16,9 +16,10 @@
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
@ -173,6 +174,7 @@ class Option extends Element
* @param string $delim Delimiter to use between short and long option
*
* @return string The string representation of the option
*
* @todo use __toString() instead
*/
public function toString($delim = ", ")
@ -269,6 +271,7 @@ class Option extends Element
*
* @return void
* @throws PEAR2\Console\CommandLine\Exception
*
* @todo use exceptions instead
*/
public function validate()

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/

View File

@ -16,7 +16,7 @@
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*/

View File

@ -11,14 +11,15 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/

View File

@ -11,20 +11,24 @@
* through the world-wide-web at the following URI:
* http://opensource.org/licenses/mit-license.php
*
* @category Console
* @category Console
* @package PEAR2\Console\CommandLine
* @author David JEAN LOUIS <izimobil@gmail.com>
* @copyright 2007-2009 David JEAN LOUIS
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.1
* @license http://opensource.org/licenses/mit-license.php MIT License
* @version 0.2.3
* @link http://pear2.php.net/PEAR2_Console_CommandLine
* @since File available since release 0.1.0
*
* @filesource
*/
namespace PEAR2\Console\CommandLine;
use PEAR2\Console\CommandLine;
use DOMDocument;
use DOMNode;
use Phar;
/**
* Parser for command line xml definitions.
@ -49,7 +53,7 @@ class XmlParser
*
* @return PEAR2\Console\CommandLine A parser instance
*/
public static function parse($xmlfile)
public static function parse($xmlfile)
{
if (!is_readable($xmlfile)) {
CommandLine::triggerError(
@ -58,7 +62,7 @@ class XmlParser
array('{$file}' => $xmlfile)
);
}
$doc = new \DomDocument();
$doc = new DOMDocument();
$doc->load($xmlfile);
self::validate($doc);
$nodes = $doc->getElementsByTagName('command');
@ -77,9 +81,9 @@ class XmlParser
*
* @return PEAR2\Console\CommandLine A parser instance
*/
public static function parseString($xmlstr)
public static function parseString($xmlstr)
{
$doc = new \DomDocument();
$doc = new DOMDocument();
$doc->loadXml($xmlstr);
self::validate($doc);
$nodes = $doc->getElementsByTagName('command');
@ -93,27 +97,48 @@ class XmlParser
/**
* Validates the xml definition using Relax NG.
*
* @param DomDocument $doc The document to validate
* @param DOMDocument $doc The document to validate
*
* @return boolean Whether the xml data is valid or not.
* @throws PEAR2\Console\CommandLine\Exception
*
* @todo use exceptions only
*/
public static function validate($doc)
public static function validate(DOMDocument $doc)
{
$rngfile = __DIR__
. '/../../../../data/pear2.php.net/PEAR2_Console_CommandLine/xmlschema.rng';
if (!is_file($rngfile)) {
$rngfile = __DIR__ . '/../../../../data/xmlschema.rng';
$paths = array();
if (!class_exists('Phar', false) || !Phar::running()) {
// Pyrus
$paths[]
= 'D:\Vasko\WEB\PHP\_shared\PEAR2\data/pear2.php.net/PEAR2_Console_CommandLine/xmlschema.rng';
// PEAR
$pearDataDirEnv = getenv('PHP_PEAR_DATA_DIR');
if ($pearDataDirEnv) {
$paths[] = $pearDataDirEnv .
'/PEAR2_Console_CommandLine/xmlschema.rng';
}
$paths[] = 'D:\Vasko\WEB\PHP\_shared\PEAR2\data/PEAR2_Console_CommandLine/xmlschema.rng';
}
if (!is_readable($rngfile)) {
CommandLine::triggerError(
'invalid_xml_file',
E_USER_ERROR,
array('{$file}' => $rngfile)
);
$pkgData = __DIR__ . '/../../../../data/';
// PHAR dep
$paths[] = $pkgData .
'pear2.php.net/PEAR2_Console_CommandLine/xmlschema.rng';
$paths[] = $pkgData . 'PEAR2_Console_CommandLine/xmlschema.rng';
$paths[] = $pkgData . 'pear2/console_commandline/xmlschema.rng';
// Git/Composer
$paths[] = $pkgData . 'xmlschema.rng';
$paths[] = 'xmlschema.rng';
foreach ($paths as $path) {
if (is_readable($path)) {
return $doc->relaxNGValidate($path);
}
}
return $doc->relaxNGValidate($rngfile);
CommandLine::triggerError(
'invalid_xml_file',
E_USER_ERROR,
array('{$file}' => $path)
);
}
// }}}
@ -124,14 +149,15 @@ class XmlParser
* constructed PEAR2\Console\CommandLine or PEAR2\Console\CommandLine_Command
* instance.
*
* @param DomDocumentNode $node The node to parse
* @param bool $isRootNode Whether it is a root node or not
* @param DOMNode $node The node to parse
* @param bool $isRootNode Whether it is a root node or not
*
* @return mixed PEAR2\Console\CommandLine or PEAR2\Console\CommandLine_Command
* @return CommandLine|CommandLine\Command An instance of CommandLine for
* root node, CommandLine\Command otherwise.
*/
private static function _parseCommandNode($node, $isRootNode = false)
private static function _parseCommandNode(DOMNode $node, $isRootNode = false)
{
if ($isRootNode) {
if ($isRootNode) {
$obj = new CommandLine();
} else {
$obj = new CommandLine\Command();
@ -184,11 +210,11 @@ class XmlParser
* Parses an option node and returns the constructed
* PEAR2\Console\CommandLine_Option instance.
*
* @param DomDocumentNode $node The node to parse
* @param DOMNode $node The node to parse
*
* @return PEAR2\Console\CommandLine\Option The built option
*/
private static function _parseOptionNode($node)
private static function _parseOptionNode(DOMNode $node)
{
$obj = new CommandLine\Option($node->getAttribute('name'));
foreach ($node->childNodes as $cNode) {
@ -221,14 +247,14 @@ class XmlParser
// _parseArgumentNode() {{{
/**
* Parses an argument node and returns the constructed
* Parses an argument node and returns the constructed
* PEAR2\Console\CommandLine_Argument instance.
*
* @param DomDocumentNode $node The node to parse
* @param DOMNode $node The node to parse
*
* @return PEAR2\Console\CommandLine\Argument The built argument
*/
private static function _parseArgumentNode($node)
private static function _parseArgumentNode(DOMNode $node)
{
$obj = new CommandLine\Argument($node->getAttribute('name'));
foreach ($node->childNodes as $cNode) {
@ -260,7 +286,7 @@ class XmlParser
/**
* Returns a boolean according to true/false possible strings.
*
*
* @param string $str The string to process
*
* @return boolean

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(