refactor: use Composer to manage php dependencies (#5216)

This commit is contained in:
Tony Murray
2017-01-01 03:37:15 -06:00
committed by Neil Lathwood
parent 74a4371fb4
commit e20a242785
2425 changed files with 278875 additions and 47258 deletions

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,419 +0,0 @@
<?php
namespace PhpAmqpLib\Channel;
use PhpAmqpLib\Connection\AbstractConnection;
use PhpAmqpLib\Exception\AMQPOutOfBoundsException;
use PhpAmqpLib\Exception\AMQPOutOfRangeException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Helper\MiscHelper;
use PhpAmqpLib\Helper\Protocol\MethodMap080;
use PhpAmqpLib\Helper\Protocol\MethodMap091;
use PhpAmqpLib\Helper\Protocol\Protocol080;
use PhpAmqpLib\Helper\Protocol\Protocol091;
use PhpAmqpLib\Helper\Protocol\Wait080;
use PhpAmqpLib\Helper\Protocol\Wait091;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Wire\AMQPReader;
class AbstractChannel
{
const PROTOCOL_080 = '0.8';
const PROTOCOL_091 = '0.9.1';
public static $PROTOCOL_CONSTANTS_CLASS;
/** @var array */
protected $frame_queue;
/** @var array */
protected $method_queue;
/** @var bool */
protected $auto_decode;
/** @var string */
protected $amqp_protocol_header;
/** @var bool */
protected $debug;
/** @var \PhpAmqpLib\Connection\AbstractConnection */
protected $connection;
/** @var string */
protected $protocolVersion;
/**
* @var int
*/
protected $body_size_max = null;
/** @var \PhpAmqpLib\Helper\Protocol\Protocol080|\PhpAmqpLib\Helper\Protocol\Protocol091 */
protected $protocolWriter;
/** @var \PhpAmqpLib\Helper\Protocol\Wait080|\PhpAmqpLib\Helper\Protocol\Wait091 */
protected $waitHelper;
/** @var \PhpAmqpLib\Helper\Protocol\MethodMap080|\PhpAmqpLib\Helper\Protocol\MethodMap091 */
protected $methodMap;
/** @var string */
protected $channel_id;
/** @var \PhpAmqpLib\Wire\AMQPReader */
protected $msg_property_reader;
/** @var \PhpAmqpLib\Wire\AMQPReader */
protected $wait_content_reader;
/** @var \PhpAmqpLib\Wire\AMQPReader */
protected $dispatch_reader;
/**
* @param AbstractConnection $connection
* @param $channel_id
* @throws \PhpAmqpLib\Exception\AMQPRuntimeException
*/
public function __construct(AbstractConnection $connection, $channel_id)
{
$this->connection = $connection;
$this->channel_id = $channel_id;
$connection->channels[$channel_id] = $this;
$this->frame_queue = array(); // Lower level queue for frames
$this->method_queue = array(); // Higher level queue for methods
$this->auto_decode = false;
$this->debug = defined('AMQP_DEBUG') ? AMQP_DEBUG : false;
$this->msg_property_reader = new AMQPReader(null);
$this->wait_content_reader = new AMQPReader(null);
$this->dispatch_reader = new AMQPReader(null);
$this->protocolVersion = self::getProtocolVersion();
switch ($this->protocolVersion) {
case self::PROTOCOL_091:
self::$PROTOCOL_CONSTANTS_CLASS = 'PhpAmqpLib\Wire\Constants091';
$c = self::$PROTOCOL_CONSTANTS_CLASS;
$this->amqp_protocol_header = $c::$AMQP_PROTOCOL_HEADER;
$this->protocolWriter = new Protocol091();
$this->waitHelper = new Wait091();
$this->methodMap = new MethodMap091();
break;
case self::PROTOCOL_080:
self::$PROTOCOL_CONSTANTS_CLASS = 'PhpAmqpLib\Wire\Constants080';
$c = self::$PROTOCOL_CONSTANTS_CLASS;
$this->amqp_protocol_header = $c::$AMQP_PROTOCOL_HEADER;
$this->protocolWriter = new Protocol080();
$this->waitHelper = new Wait080();
$this->methodMap = new MethodMap080();
break;
default:
//this is logic exception (requires code changes to fix), so OutOfRange, not OutOfBounds or Runtime
throw new AMQPOutOfRangeException(sprintf('Protocol version %s not implemented.', $this->protocolVersion));
}
}
/**
* @return string
* @throws AMQPOutOfRangeException
*/
public static function getProtocolVersion()
{
$protocol = defined('AMQP_PROTOCOL') ? AMQP_PROTOCOL : self::PROTOCOL_091;
//adding check here to catch unknown protocol ASAP, as this method may be called from the outside
if (!in_array($protocol, array(self::PROTOCOL_080, self::PROTOCOL_091), TRUE)) {
throw new AMQPOutOfRangeException(sprintf('Protocol version %s not implemented.', $protocol));
}
return $protocol;
}
/**
* @return string
*/
public function getChannelId()
{
return $this->channel_id;
}
public function setBodySizeLimit($max_bytes)
{
$max_bytes = intval($max_bytes);
if ( $max_bytes > 0 ) {
$this->body_size_max = $max_bytes;
} else {
$this->body_size_max = null;
}
}
/**
* @return AbstractConnection
*/
public function getConnection()
{
return $this->connection;
}
/**
* @return array
*/
public function getMethodQueue()
{
return $this->method_queue;
}
/**
* @param string $method_sig
* @param string $args
* @param $content
* @return mixed
* @throws \PhpAmqpLib\Exception\AMQPRuntimeException
*/
public function dispatch($method_sig, $args, $content)
{
if (!$this->methodMap->valid_method($method_sig)) {
throw new AMQPRuntimeException(sprintf(
'Unknown AMQP method "%s"',
$method_sig
));
}
$amqp_method = $this->methodMap->get_method($method_sig);
if (!method_exists($this, $amqp_method)) {
throw new AMQPRuntimeException(sprintf(
'Method: "%s" not implemented by class: %s',
$amqp_method,
get_class($this)
));
}
$this->dispatch_reader->reuse($args);
if ($content == null) {
return call_user_func(array($this, $amqp_method), $this->dispatch_reader);
}
return call_user_func(array($this, $amqp_method), $this->dispatch_reader, $content);
}
/**
* @param int $timeout
* @return array|mixed
*/
public function next_frame($timeout = 0)
{
if ($this->debug) {
MiscHelper::debug_msg('waiting for a new frame');
}
if (!empty($this->frame_queue)) {
return array_shift($this->frame_queue);
}
return $this->connection->wait_channel($this->channel_id, $timeout);
}
/**
* @param $method_sig
* @param string $args
*/
protected function send_method_frame($method_sig, $args = '')
{
$this->connection->send_channel_method_frame($this->channel_id, $method_sig, $args);
}
/**
* This is here for performance reasons to batch calls to fwrite from basic.publish
*
* @param $method_sig
* @param string $args
* @param null $pkt
* @return null|\PhpAmqpLib\Wire\AMQPWriter
*/
protected function prepare_method_frame($method_sig, $args = '', $pkt = null)
{
return $this->connection->prepare_channel_method_frame($this->channel_id, $method_sig, $args, $pkt);
}
/**
* @return AMQPMessage
* @throws \PhpAmqpLib\Exception\AMQPRuntimeException
*/
public function wait_content()
{
$frm = $this->next_frame();
$frame_type = $frm[0];
$payload = $frm[1];
if ($frame_type != 2) {
throw new AMQPRuntimeException('Expecting Content header');
}
$this->wait_content_reader->reuse(mb_substr($payload, 0, 12, 'ASCII'));
// $payload_reader = new AMQPReader(substr($payload,0,12));
$class_id = $this->wait_content_reader->read_short();
$weight = $this->wait_content_reader->read_short();
$body_size = $this->wait_content_reader->read_longlong();
//hack to avoid creating new instances of AMQPReader;
$this->msg_property_reader->reuse(mb_substr($payload, 12, mb_strlen($payload, 'ASCII') - 12, 'ASCII'));
$msg = new AMQPMessage();
$msg->load_properties($this->msg_property_reader);
$msg->body_size = $body_size;
$body_parts = array();
$body_received = 0;
while (bccomp($body_size, $body_received, 0) == 1) {
$frm = $this->next_frame();
$frame_type = $frm[0];
$payload = $frm[1];
if ($frame_type != 3) {
$PROTOCOL_CONSTANTS_CLASS = self::$PROTOCOL_CONSTANTS_CLASS;
throw new AMQPRuntimeException(sprintf(
'Expecting Content body, received frame type %s (%s)',
$frame_type,
$PROTOCOL_CONSTANTS_CLASS::$FRAME_TYPES[$frame_type]
));
}
$body_received = bcadd($body_received, mb_strlen($payload, 'ASCII'), 0);
if ( ! is_null($this->body_size_max) && $body_received > $this->body_size_max ) {
$msg->is_truncated = true;
continue;
}
$body_parts[] = $payload;
}
$msg->body = implode('', $body_parts);
if ($this->auto_decode && isset($msg->content_encoding)) {
try {
$msg->body = $msg->body->decode($msg->content_encoding);
} catch (\Exception $e) {
if ($this->debug) {
MiscHelper::debug_msg('Ignoring body decoding exception: ' . $e->getMessage());
}
}
}
return $msg;
}
/**
* Wait for some expected AMQP methods and dispatch to them.
* Unexpected methods are queued up for later calls to this PHP
* method.
*
* @param array $allowed_methods
* @param bool $non_blocking
* @param int $timeout
* @throws \PhpAmqpLib\Exception\AMQPOutOfBoundsException
* @throws \PhpAmqpLib\Exception\AMQPRuntimeException
* @return mixed
*/
public function wait($allowed_methods = null, $non_blocking = false, $timeout = 0)
{
$PROTOCOL_CONSTANTS_CLASS = self::$PROTOCOL_CONSTANTS_CLASS;
if ($allowed_methods && $this->debug) {
MiscHelper::debug_msg('waiting for ' . implode(', ', $allowed_methods));
} elseif ($this->debug) {
MiscHelper::debug_msg('waiting for any method');
}
//Process deferred methods
foreach ($this->method_queue as $qk => $queued_method) {
if ($this->debug) {
MiscHelper::debug_msg('checking queue method ' . $qk);
}
$method_sig = $queued_method[0];
if ($allowed_methods == null || in_array($method_sig, $allowed_methods)) {
unset($this->method_queue[$qk]);
if ($this->debug) {
MiscHelper::debug_msg(sprintf(
'Executing queued method: %s: %s',
$method_sig,
$PROTOCOL_CONSTANTS_CLASS::$GLOBAL_METHOD_NAMES[MiscHelper::methodSig($method_sig)]
));
}
return $this->dispatch($queued_method[0], $queued_method[1], $queued_method[2]);
}
}
// No deferred methods? wait for new ones
while (true) {
$frm = $this->next_frame($timeout);
$frame_type = $frm[0];
$payload = $frm[1];
if ($frame_type != 1) {
throw new AMQPRuntimeException(sprintf(
'Expecting AMQP method, received frame type: %s (%s)',
$frame_type,
$PROTOCOL_CONSTANTS_CLASS::$FRAME_TYPES[$frame_type]
));
}
if (mb_strlen($payload, 'ASCII') < 4) {
throw new AMQPOutOfBoundsException('Method frame too short');
}
$method_sig_array = unpack('n2', mb_substr($payload, 0, 4, 'ASCII'));
$method_sig = '' . $method_sig_array[1] . ',' . $method_sig_array[2];
$args = mb_substr($payload, 4, mb_strlen($payload, 'ASCII') - 4, 'ASCII');
if ($this->debug) {
MiscHelper::debug_msg(sprintf(
'> %s: %s',
$method_sig,
$PROTOCOL_CONSTANTS_CLASS::$GLOBAL_METHOD_NAMES[MiscHelper::methodSig($method_sig)]
));
}
if (in_array($method_sig, $PROTOCOL_CONSTANTS_CLASS::$CONTENT_METHODS)) {
$content = $this->wait_content();
} else {
$content = null;
}
if ($allowed_methods == null ||
in_array($method_sig, $allowed_methods) ||
in_array($method_sig, $PROTOCOL_CONSTANTS_CLASS::$CLOSE_METHODS)
) {
return $this->dispatch($method_sig, $args, $content);
}
// Wasn't what we were looking for? save it for later
if ($this->debug) {
MiscHelper::debug_msg('Queueing for later: $method_sig: '
. $PROTOCOL_CONSTANTS_CLASS::$GLOBAL_METHOD_NAMES[MiscHelper::methodSig($method_sig)]);
}
$this->method_queue[] = array($method_sig, $args, $content);
if ($non_blocking) {
break;
}
}
}
/**
* @param $handler
* @param array $arguments
*/
protected function dispatch_to_handler($handler, array $arguments)
{
if (is_callable($handler)) {
call_user_func_array($handler, $arguments);
}
}
}

View File

@@ -1,13 +0,0 @@
<?php
namespace PhpAmqpLib\Connection;
/**
* Class AMQPConnection
*
* Kept for BC
*
* @deprecated
*/
class AMQPConnection extends AMQPStreamConnection
{
}

View File

@@ -1,49 +0,0 @@
<?php
namespace PhpAmqpLib\Connection;
class AMQPLazyConnection extends AMQPConnection
{
/**
* Gets socket from current connection
*
* @deprecated
*/
public function getSocket()
{
$this->connect();
return parent::getSocket();
}
/**
* {@inheritdoc}
*/
public function channel($channel_id = null)
{
$this->connect();
return parent::channel($channel_id);
}
/**
* @return null|\PhpAmqpLib\Wire\IO\AbstractIO
*/
protected function getIO()
{
if (!$this->io) {
$this->connect();
}
return $this->io;
}
/**
* Should the connection be attempted during construction?
*
* @return bool
*/
public function connectOnConstruct()
{
return false;
}
}

View File

@@ -1,56 +0,0 @@
<?php
namespace PhpAmqpLib\Connection;
class AMQPSSLConnection extends AMQPStreamConnection
{
/**
* @param AbstractConnection $host
* @param int $port
* @param string $user
* @param bool $password
* @param string $vhost
* @param array $ssl_options
* @param array $options
*/
public function __construct(
$host,
$port,
$user,
$password,
$vhost = '/',
$ssl_options = array(),
$options = array()
) {
$ssl_context = empty($ssl_options) ? null : $this->create_ssl_context($ssl_options);
parent::__construct(
$host,
$port,
$user,
$password,
$vhost,
isset($options['insist']) ? $options['insist'] : false,
isset($options['login_method']) ? $options['login_method'] : 'AMQPLAIN',
isset($options['login_response']) ? $options['login_response'] : null,
isset($options['locale']) ? $options['locale'] : 'en_US',
isset($options['connection_timeout']) ? $options['connection_timeout'] : 3,
isset($options['read_write_timeout']) ? $options['read_write_timeout'] : 3,
$ssl_context,
isset($options['keepalive']) ? $options['keepalive'] : false,
isset($options['heartbeat']) ? $options['heartbeat'] : 0
);
}
/**
* @param $options
* @return resource
*/
private function create_ssl_context($options)
{
$ssl_context = stream_context_create();
foreach ($options as $k => $v) {
stream_context_set_option($ssl_context, 'ssl', $k, $v);
}
return $ssl_context;
}
}

View File

@@ -1,38 +0,0 @@
<?php
namespace PhpAmqpLib\Connection;
use PhpAmqpLib\Wire\IO\SocketIO;
class AMQPSocketConnection extends AbstractConnection
{
/**
* @param AbstractConnection $host
* @param int $port
* @param string $user
* @param bool $password
* @param string $vhost
* @param bool $insist
* @param string $login_method
* @param null $login_response
* @param string $locale
* @param int $timeout
* @param bool $keepalive
*/
public function __construct(
$host,
$port,
$user,
$password,
$vhost = '/',
$insist = false,
$login_method = 'AMQPLAIN',
$login_response = null,
$locale = 'en_US',
$timeout = 3,
$keepalive = false
) {
$io = new SocketIO($host, $port, $timeout, $keepalive);
parent::__construct($user, $password, $vhost, $insist, $login_method, $login_response, $locale, $io);
}
}

View File

@@ -1,46 +0,0 @@
<?php
namespace PhpAmqpLib\Connection;
use PhpAmqpLib\Wire\IO\StreamIO;
class AMQPStreamConnection extends AbstractConnection
{
/**
* @param AbstractConnection $host
* @param string $port
* @param string $user
* @param bool $password
* @param string $vhost
* @param bool $insist
* @param string $login_method
* @param null $login_response
* @param string $locale
* @param int $connection_timeout
* @param int $read_write_timeout
* @param null $context
* @param bool $keepalive
*/
public function __construct(
$host,
$port,
$user,
$password,
$vhost = '/',
$insist = false,
$login_method = 'AMQPLAIN',
$login_response = null,
$locale = 'en_US',
$connection_timeout = 3,
$read_write_timeout = 3,
$context = null,
$keepalive = false,
$heartbeat = 0
) {
$io = new StreamIO($host, $port, $connection_timeout, $read_write_timeout, $context, $keepalive, $heartbeat);
parent::__construct($user, $password, $vhost, $insist, $login_method, $login_response, $locale, $io, $heartbeat);
// save the params for the use of __clone, this will overwrite the parent
$this->construct_params = func_get_args();
}
}

View File

@@ -1,972 +0,0 @@
<?php
namespace PhpAmqpLib\Connection;
use PhpAmqpLib\Channel\AbstractChannel;
use PhpAmqpLib\Channel\AMQPChannel;
use PhpAmqpLib\Exception\AMQPProtocolConnectionException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Helper\MiscHelper;
use PhpAmqpLib\Wire\AMQPReader;
use PhpAmqpLib\Wire\AMQPWriter;
use PhpAmqpLib\Wire\IO\AbstractIO;
use PhpAmqpLib\Wire\IO\SocketIO;
class AbstractConnection extends AbstractChannel
{
/** @var array */
public static $LIBRARY_PROPERTIES = array(
'product' => array('S', 'AMQPLib'),
'platform' => array('S', 'PHP'),
'version' => array('S', '2.4'),
'information' => array('S', ''),
'copyright' => array('S', ''),
'capabilities' => array(
'F',
array(
'authentication_failure_close' => array('t', true),
'publisher_confirms' => array('t', true),
'consumer_cancel_notify' => array('t', true),
'exchange_exchange_bindings' => array('t', true),
'basic.nack' => array('t', true),
'connection.blocked' => array('t', true)
)
)
);
/** @var AMQPChannel[] */
public $channels = array();
/** @var int */
protected $version_major;
/** @var int */
protected $version_minor;
/** @var array */
protected $server_properties;
/** @var array */
protected $mechanisms;
/** @var array */
protected $locales;
/** @var bool */
protected $wait_tune_ok;
/** @var string */
protected $known_hosts;
/** @var AMQPReader */
protected $input;
/** @var string */
protected $vhost;
/** @var bool */
protected $insist;
/** @var string */
protected $login_method;
/** @var AMQPWriter */
protected $login_response;
/** @var string */
protected $locale;
/** @var int */
protected $heartbeat;
/** @var SocketIO */
protected $sock;
/** @var int */
protected $channel_max = 65535;
/** @var int */
protected $frame_max = 131072;
/** @var array Constructor parameters for clone */
protected $construct_params;
/** @var bool Close the connection in destructor */
protected $close_on_destruct = true;
/** @var bool Maintain connection status */
protected $is_connected = false;
/** @var \PhpAmqpLib\Wire\IO\AbstractIO */
protected $io;
/** @var \PhpAmqpLib\Wire\AMQPReader */
protected $wait_frame_reader;
/** @var callable Handles connection blocking from the server */
private $connection_block_handler;
/** @var callable Handles connection unblocking from the server */
private $connection_unblock_handler;
/**
* Circular buffer to speed up prepare_content().
* Max size limited by $prepare_content_cache_max_size.
*
* @var array
* @see prepare_content()
*/
private $prepare_content_cache;
/** @var int Maximal size of $prepare_content_cache */
private $prepare_content_cache_max_size;
/**
* @param AbstractConnection $user
* @param string $password
* @param string $vhost
* @param bool $insist
* @param string $login_method
* @param null $login_response
* @param string $locale
* @param AbstractIO $io
* @param int $heartbeat
* @throws \Exception
*/
public function __construct(
$user,
$password,
$vhost = '/',
$insist = false,
$login_method = 'AMQPLAIN',
$login_response = null,
$locale = 'en_US',
AbstractIO $io,
$heartbeat = 0
) {
// save the params for the use of __clone
$this->construct_params = func_get_args();
$this->wait_frame_reader = new AMQPReader(null);
$this->vhost = $vhost;
$this->insist = $insist;
$this->login_method = $login_method;
$this->login_response = $login_response;
$this->locale = $locale;
$this->io = $io;
$this->heartbeat = $heartbeat;
if ($user && $password) {
$this->login_response = new AMQPWriter();
$this->login_response->write_table(array(
'LOGIN' => array('S', $user),
'PASSWORD' => array('S', $password)
));
// Skip the length
$responseValue = $this->login_response->getvalue();
$this->login_response = mb_substr($responseValue, 4, mb_strlen($responseValue, 'ASCII') - 4, 'ASCII');
} else {
$this->login_response = null;
}
$this->prepare_content_cache = array();
$this->prepare_content_cache_max_size = 100;
// Lazy Connection waits on connecting
if ($this->connectOnConstruct()) {
$this->connect();
}
}
/**
* Connects to the AMQP server
*/
protected function connect()
{
try {
// Loop until we connect
while (!$this->isConnected()) {
// Assume we will connect, until we dont
$this->setIsConnected(true);
// Connect the socket
$this->getIO()->connect();
$this->channels = array();
// The connection object itself is treated as channel 0
parent::__construct($this, 0);
$this->input = new AMQPReader(null, $this->getIO());
$this->write($this->amqp_protocol_header);
$this->wait(array($this->waitHelper->get_wait('connection.start')));
$this->x_start_ok(self::$LIBRARY_PROPERTIES, $this->login_method, $this->login_response, $this->locale);
$this->wait_tune_ok = true;
while ($this->wait_tune_ok) {
$this->wait(array(
$this->waitHelper->get_wait('connection.secure'),
$this->waitHelper->get_wait('connection.tune')
));
}
$host = $this->x_open($this->vhost, '', $this->insist);
if (!$host) {
return; // we weren't redirected
}
$this->setIsConnected(false);
$this->closeChannels();
// we were redirected, close the socket, loop and try again
$this->close_socket();
}
} catch (\Exception $e) {
// Something went wrong, set the connection status
$this->setIsConnected(false);
$this->closeChannels();
throw $e; // Rethrow exception
}
}
/**
* Reconnects using the original connection settings.
* This will not recreate any channels that were established previously
*/
public function reconnect()
{
// Try to close the AMQP connection
$this->safeClose();
// Reconnect the socket/stream then AMQP
$this->getIO()->reconnect();
$this->setIsConnected(false); // getIO can initiate the connection setting via LazyConnection, set it here to be sure
$this->connect();
}
/**
* Cloning will use the old properties to make a new connection to the same server
*/
public function __clone()
{
call_user_func_array(array($this, '__construct'), $this->construct_params);
}
public function __destruct()
{
if ($this->close_on_destruct) {
$this->safeClose();
}
}
/**
* Attempts to close the connection safely
*/
protected function safeClose()
{
try {
if (isset($this->input) && $this->input) {
$this->close();
}
} catch (\Exception $e) {
// Nothing here
}
}
/**
* @param int $sec
* @param int $usec
* @return mixed
*/
public function select($sec, $usec = 0)
{
return $this->getIO()->select($sec, $usec);
}
/**
* Allows to not close the connection
* it's useful after the fork when you don't want to close parent process connection
*
* @param bool $close
*/
public function set_close_on_destruct($close = true)
{
$this->close_on_destruct = (bool) $close;
}
protected function close_input()
{
if ($this->debug) {
MiscHelper::debug_msg('closing input');
}
if (!is_null($this->input)) {
$this->input->close();
$this->input = null;
}
}
protected function close_socket()
{
if ($this->debug) {
MiscHelper::debug_msg('closing socket');
}
if (!is_null($this->getIO())) {
$this->getIO()->close();
}
}
/**
* @param $data
*/
public function write($data)
{
if ($this->debug) {
MiscHelper::debug_msg(sprintf(
'< [hex]: %s%s',
PHP_EOL,
MiscHelper::hexdump($data, $htmloutput = false, $uppercase = true, $return = true)
));
}
try {
$this->getIO()->write($data);
} catch (AMQPRuntimeException $e) {
$this->setIsConnected(false);
throw $e;
}
}
protected function do_close()
{
$this->setIsConnected(false);
$this->close_input();
$this->close_socket();
}
/**
* @return int
* @throws \PhpAmqpLib\Exception\AMQPRuntimeException
*/
public function get_free_channel_id()
{
for ($i = 1; $i <= $this->channel_max; $i++) {
if (!isset($this->channels[$i])) {
return $i;
}
}
throw new AMQPRuntimeException('No free channel ids');
}
/**
* @param string $channel
* @param int $class_id
* @param int $weight
* @param int $body_size
* @param string $packed_properties
* @param string $body
* @param AMQPWriter $pkt
*/
public function send_content($channel, $class_id, $weight, $body_size, $packed_properties, $body, $pkt = null)
{
$this->prepare_content($channel, $class_id, $weight, $body_size, $packed_properties, $body, $pkt);
$this->write($pkt->getvalue());
}
/**
* Returns a new AMQPWriter or mutates the provided $pkt
*
* @param string $channel
* @param int $class_id
* @param int $weight
* @param int $body_size
* @param string $packed_properties
* @param string $body
* @param AMQPWriter $pkt
* @return AMQPWriter
*/
public function prepare_content($channel, $class_id, $weight, $body_size, $packed_properties, $body, $pkt = null)
{
if (empty($pkt)) {
$pkt = new AMQPWriter();
}
// Content already prepared ?
$key_cache = sprintf(
'%s|%s|%s|%s',
$channel,
$packed_properties,
$class_id,
$weight
);
if (!isset($this->prepare_content_cache[$key_cache])) {
$w = new AMQPWriter();
$w->write_octet(2);
$w->write_short($channel);
$w->write_long(mb_strlen($packed_properties, 'ASCII') + 12);
$w->write_short($class_id);
$w->write_short($weight);
$this->prepare_content_cache[$key_cache] = $w->getvalue();
if (count($this->prepare_content_cache) > $this->prepare_content_cache_max_size) {
reset($this->prepare_content_cache);
$old_key = key($this->prepare_content_cache);
unset($this->prepare_content_cache[$old_key]);
}
}
$pkt->write($this->prepare_content_cache[$key_cache]);
$pkt->write_longlong($body_size);
$pkt->write($packed_properties);
$pkt->write_octet(0xCE);
// memory efficiency: walk the string instead of biting it. good for very large packets (close in size to memory_limit setting)
$position = 0;
$bodyLength = mb_strlen($body,'ASCII');
while ($position <= $bodyLength) {
$payload = mb_substr($body, $position, $this->frame_max - 8, 'ASCII');
$position += $this->frame_max - 8;
$pkt->write_octet(3);
$pkt->write_short($channel);
$pkt->write_long(mb_strlen($payload, 'ASCII'));
$pkt->write($payload);
$pkt->write_octet(0xCE);
}
return $pkt;
}
/**
* @param $channel
* @param $method_sig
* @param string $args
* @param null $pkt
*/
protected function send_channel_method_frame($channel, $method_sig, $args = '', $pkt = null)
{
$pkt = $this->prepare_channel_method_frame($channel, $method_sig, $args, $pkt);
$this->write($pkt->getvalue());
if ($this->debug) {
$PROTOCOL_CONSTANTS_CLASS = self::$PROTOCOL_CONSTANTS_CLASS;
MiscHelper::debug_msg(sprintf(
'< %s: %s',
MiscHelper::methodSig($method_sig),
$PROTOCOL_CONSTANTS_CLASS::$GLOBAL_METHOD_NAMES[MiscHelper::methodSig($method_sig)]
));
}
}
/**
* Returns a new AMQPWriter or mutates the provided $pkt
*
* @param $channel
* @param $method_sig
* @param string $args
* @param AMQPWriter $pkt
* @return null|AMQPWriter
*/
protected function prepare_channel_method_frame($channel, $method_sig, $args = '', $pkt = null)
{
if ($args instanceof AMQPWriter) {
$args = $args->getvalue();
}
if (empty($pkt)) {
$pkt = new AMQPWriter();
}
$pkt->write_octet(1);
$pkt->write_short($channel);
$pkt->write_long(mb_strlen($args, 'ASCII') + 4); // 4 = length of class_id and method_id
// in payload
$pkt->write_short($method_sig[0]); // class_id
$pkt->write_short($method_sig[1]); // method_id
$pkt->write($args);
$pkt->write_octet(0xCE);
if ($this->debug) {
$PROTOCOL_CONSTANTS_CLASS = self::$PROTOCOL_CONSTANTS_CLASS;
MiscHelper::debug_msg(sprintf(
'< %s: %s',
MiscHelper::methodSig($method_sig),
$PROTOCOL_CONSTANTS_CLASS::$GLOBAL_METHOD_NAMES[MiscHelper::methodSig($method_sig)]
));
}
return $pkt;
}
/**
* Waits for a frame from the server
*
* @param int $timeout
* @return array
* @throws \Exception
* @throws \PhpAmqpLib\Exception\AMQPTimeoutException
* @throws \PhpAmqpLib\Exception\AMQPRuntimeException
*/
protected function wait_frame($timeout = 0)
{
$currentTimeout = $this->input->getTimeout();
$this->input->setTimeout($timeout);
try {
// frame_type + channel_id + size
$this->wait_frame_reader->reuse(
$this->input->read(AMQPReader::OCTET + AMQPReader::SHORT + AMQPReader::LONG)
);
$frame_type = $this->wait_frame_reader->read_octet();
$channel = $this->wait_frame_reader->read_short();
$size = $this->wait_frame_reader->read_long();
// payload + ch
$this->wait_frame_reader->reuse($this->input->read(AMQPReader::OCTET + (int) $size));
$payload = $this->wait_frame_reader->read($size);
$ch = $this->wait_frame_reader->read_octet();
} catch (AMQPTimeoutException $e) {
$this->input->setTimeout($currentTimeout);
throw $e;
}
$this->input->setTimeout($currentTimeout);
if ($ch != 0xCE) {
throw new AMQPRuntimeException(sprintf(
'Framing error, unexpected byte: %x',
$ch
));
}
return array($frame_type, $channel, $payload);
}
/**
* Waits for a frame from the server destined for a particular channel.
*
* @param string $channel_id
* @param int $timeout
* @return array
*/
protected function wait_channel($channel_id, $timeout = 0)
{
while (true) {
list($frame_type, $frame_channel, $payload) = $this->wait_frame($timeout);
if ($frame_channel === 0 && $frame_type === 8) {
// skip heartbeat frames
continue;
} else {
if ($frame_channel == $channel_id) {
return array($frame_type, $payload);
}
// Not the channel we were looking for. Queue this frame
//for later, when the other channel is looking for frames.
array_push($this->channels[$frame_channel]->frame_queue, array($frame_type, $payload));
// If we just queued up a method for channel 0 (the Connection
// itself) it's probably a close method in reaction to some
// error, so deal with it right away.
if (($frame_type == 1) && ($frame_channel == 0)) {
$this->wait();
}
}
}
}
/**
* Fetches a channel object identified by the numeric channel_id, or
* create that object if it doesn't already exist.
*
* @param string $channel_id
* @return AMQPChannel
*/
public function channel($channel_id = null)
{
if (isset($this->channels[$channel_id])) {
return $this->channels[$channel_id];
} else {
$channel_id = $channel_id ? $channel_id : $this->get_free_channel_id();
$ch = new AMQPChannel($this->connection, $channel_id);
$this->channels[$channel_id] = $ch;
return $ch;
}
}
/**
* Requests a connection close
*
* @param int $reply_code
* @param string $reply_text
* @param array $method_sig
* @return mixed|null
*/
public function close($reply_code = 0, $reply_text = '', $method_sig = array(0, 0))
{
if (!$this->protocolWriter || !$this->isConnected()) {
return null;
}
$this->closeChannels();
list($class_id, $method_id, $args) = $this->protocolWriter->connectionClose(
$reply_code,
$reply_text,
$method_sig[0],
$method_sig[1]
);
$this->send_method_frame(array($class_id, $method_id), $args);
$this->setIsConnected(false);
return $this->wait(array(
$this->waitHelper->get_wait('connection.close_ok')
));
}
/**
* @param $table
* @return string
*/
public static function dump_table($table)
{
$tokens = array();
foreach ($table as $name => $value) {
switch ($value[0]) {
case 'D':
$val = $value[1]->n . 'E' . $value[1]->e;
break;
case 'F':
$val = '(' . self::dump_table($value[1]) . ')';
break;
case 'T':
$val = date('Y-m-d H:i:s', $value[1]);
break;
default:
$val = $value[1];
}
$tokens[] = $name . '=' . $val;
}
return implode(', ', $tokens);
}
/**
* @param AMQPReader $args
* @throws \PhpAmqpLib\Exception\AMQPProtocolConnectionException
*/
protected function connection_close($args)
{
$reply_code = $args->read_short();
$reply_text = $args->read_shortstr();
$class_id = $args->read_short();
$method_id = $args->read_short();
$this->x_close_ok();
throw new AMQPProtocolConnectionException($reply_code, $reply_text, array($class_id, $method_id));
}
/**
* Confirms a connection close
*/
protected function x_close_ok()
{
$this->send_method_frame(
explode(',', $this->waitHelper->get_wait('connection.close_ok'))
);
$this->do_close();
}
/**
* Confirm a connection close
*/
protected function connection_close_ok($args)
{
$this->do_close();
}
/**
* @param string $virtual_host
* @param string $capabilities
* @param bool $insist
* @return mixed
*/
protected function x_open($virtual_host, $capabilities = '', $insist = false)
{
$args = new AMQPWriter();
$args->write_shortstr($virtual_host);
$args->write_shortstr($capabilities);
$args->write_bits(array($insist));
$this->send_method_frame(array(10, 40), $args);
$wait = array(
$this->waitHelper->get_wait('connection.open_ok')
);
if ($this->protocolVersion == '0.8') {
$wait[] = $this->waitHelper->get_wait('connection.redirect');
}
return $this->wait($wait);
}
/**
* Signals that the connection is ready
*
* @param AMQPReader $args
*/
protected function connection_open_ok($args)
{
$this->known_hosts = $args->read_shortstr();
if ($this->debug) {
MiscHelper::debug_msg('Open OK! known_hosts: ' . $this->known_hosts);
}
}
/**
* Asks the client to use a different server
*
* @param AMQPReader $args
* @return string
*/
protected function connection_redirect($args)
{
$host = $args->read_shortstr();
$this->known_hosts = $args->read_shortstr();
if ($this->debug) {
MiscHelper::debug_msg(sprintf(
'Redirected to [%s], known_hosts [%s]',
$host,
$this->known_hosts
));
}
return $host;
}
/**
* Security mechanism challenge
*
* @param AMQPReader $args
*/
protected function connection_secure($args)
{
$challenge = $args->read_longstr();
}
/**
* Security mechanism response
*/
protected function x_secure_ok($response)
{
$args = new AMQPWriter();
$args->write_longstr($response);
$this->send_method_frame(array(10, 21), $args);
}
/**
* Starts connection negotiation
*
* @param AMQPReader $args
*/
protected function connection_start($args)
{
$this->version_major = $args->read_octet();
$this->version_minor = $args->read_octet();
$this->server_properties = $args->read_table();
$this->mechanisms = explode(' ', $args->read_longstr());
$this->locales = explode(' ', $args->read_longstr());
if ($this->debug) {
MiscHelper::debug_msg(sprintf(
'Start from server, version: %d.%d, properties: %s, mechanisms: %s, locales: %s',
$this->version_major,
$this->version_minor,
self::dump_table($this->server_properties),
implode(', ', $this->mechanisms),
implode(', ', $this->locales)
));
}
}
/**
* @param $client_properties
* @param $mechanism
* @param $response
* @param $locale
*/
protected function x_start_ok($client_properties, $mechanism, $response, $locale)
{
$args = new AMQPWriter();
$args->write_table($client_properties);
$args->write_shortstr($mechanism);
$args->write_longstr($response);
$args->write_shortstr($locale);
$this->send_method_frame(array(10, 11), $args);
}
/**
* Proposes connection tuning parameters
*
* @param AMQPReader $args
*/
protected function connection_tune($args)
{
$v = $args->read_short();
if ($v) {
$this->channel_max = $v;
}
$v = $args->read_long();
if ($v) {
$this->frame_max = $v;
}
// use server proposed value if not set
if ($this->heartbeat === null) {
$this->heartbeat = $args->read_short();
}
$this->x_tune_ok($this->channel_max, $this->frame_max, $this->heartbeat);
}
/**
* Negotiates connection tuning parameters
*
* @param $channel_max
* @param $frame_max
* @param $heartbeat
*/
protected function x_tune_ok($channel_max, $frame_max, $heartbeat)
{
$args = new AMQPWriter();
$args->write_short($channel_max);
$args->write_long($frame_max);
$args->write_short($heartbeat);
$this->send_method_frame(array(10, 31), $args);
$this->wait_tune_ok = false;
}
/**
* @return SocketIO
*/
public function getSocket()
{
return $this->io->getSocket();
}
/**
* @return \PhpAmqpLib\Wire\IO\AbstractIO
*/
protected function getIO()
{
return $this->io;
}
/**
* Handles connection blocked notifications
*
* @param AMQPReader $args
*/
protected function connection_blocked(AMQPReader $args)
{
// Call the block handler and pass in the reason
$this->dispatch_to_handler($this->connection_block_handler, array($args->read_shortstr()));
}
/**
* Handles connection unblocked notifications
*/
protected function connection_unblocked(AMQPReader $args)
{
// No args to an unblock event
$this->dispatch_to_handler($this->connection_unblock_handler, array());
}
/**
* Sets a handler which is called whenever a connection.block is sent from the server
*
* @param callable $callback
*/
public function set_connection_block_handler($callback)
{
$this->connection_block_handler = $callback;
}
/**
* Sets a handler which is called whenever a connection.block is sent from the server
*
* @param callable $callback
*/
public function set_connection_unblock_handler($callback)
{
$this->connection_unblock_handler = $callback;
}
/**
* Gets the connection status
*
* @return bool
*/
public function isConnected()
{
return $this->is_connected;
}
/**
* Set the connection status
*
* @param bool $is_connected
*/
protected function setIsConnected($is_connected)
{
$this->is_connected = $is_connected;
}
/**
* Closes all available channels
*/
protected function closeChannels()
{
foreach ($this->channels as $key => $channel) {
// channels[0] is this connection object, so don't close it yet
if ($key === 0) {
continue;
}
try {
$channel->close();
} catch (\Exception $e) {
/* Ignore closing errors */
}
}
}
/**
* Should the connection be attempted during construction?
*
* @return bool
*/
public function connectOnConstruct()
{
return true;
}
}

View File

@@ -1,16 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
class AMQPBasicCancelException extends \Exception implements AMQPExceptionInterface
{
/** @var string */
public $consumerTag;
/**
* @param string $consumerTag
*/
public function __construct($consumerTag)
{
$this->consumerTag = $consumerTag;
}
}

View File

@@ -1,9 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
/**
* @deprecated use AMQPProtocolChannelException instead
*/
class AMQPChannelException extends AMQPException
{
}

View File

@@ -1,9 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
/**
* @deprecated use AMQPProtocolConnectionException instead
*/
class AMQPConnectionException extends AMQPException
{
}

View File

@@ -1,46 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
//TODO refactor usage of static methods
use PhpAmqpLib\Channel\AbstractChannel;
use PhpAmqpLib\Helper\MiscHelper;
/**
* @deprecated use AMQPProtocolException instead
*/
class AMQPException extends \Exception
{
/** @var string */
public $amqp_reply_code;
/** @var int */
public $amqp_reply_text;
/** @var \Exception */
public $amqp_method_sig;
/** @var array */
public $args;
/**
* @param string $reply_code
* @param int $reply_text
* @param \Exception $method_sig
*/
public function __construct($reply_code, $reply_text, $method_sig)
{
parent::__construct($reply_text, $reply_code);
$this->amqp_reply_code = $reply_code; // redundant, but kept for BC
$this->amqp_reply_text = $reply_text; // redundant, but kept for BC
$this->amqp_method_sig = $method_sig;
$ms = MiscHelper::methodSig($method_sig);
$PROTOCOL_CONSTANTS_CLASS = AbstractChannel::$PROTOCOL_CONSTANTS_CLASS;
$mn = isset($PROTOCOL_CONSTANTS_CLASS::$GLOBAL_METHOD_NAMES[$ms])
? $PROTOCOL_CONSTANTS_CLASS::$GLOBAL_METHOD_NAMES[$ms]
: $mn = '';
$this->args = array($reply_code, $reply_text, $method_sig, $mn);
}
}

View File

@@ -1,6 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
interface AMQPExceptionInterface
{
}

View File

@@ -1,6 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
class AMQPIOException extends \Exception implements AMQPExceptionInterface
{
}

View File

@@ -1,6 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
class AMQPInvalidArgumentException extends \RuntimeException implements AMQPExceptionInterface
{
}

View File

@@ -1,7 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
class AMQPLogicException extends \LogicException implements AMQPExceptionInterface
{
}

View File

@@ -1,6 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
class AMQPOutOfBoundsException extends \OutOfBoundsException implements AMQPExceptionInterface
{
}

View File

@@ -1,7 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
class AMQPOutOfRangeException extends \OutOfRangeException implements AMQPExceptionInterface
{
}

View File

@@ -1,6 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
class AMQPProtocolChannelException extends AMQPProtocolException
{
}

View File

@@ -1,6 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
class AMQPProtocolConnectionException extends AMQPProtocolException
{
}

View File

@@ -1,44 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
//TODO refactor usage of static methods
use PhpAmqpLib\Channel\AbstractChannel;
use PhpAmqpLib\Helper\MiscHelper;
class AMQPProtocolException extends \Exception implements AMQPExceptionInterface
{
/** @var string */
public $amqp_reply_code;
/** @var int */
public $amqp_reply_text;
/** @var \Exception */
public $amqp_method_sig;
/** @var array */
public $args;
/**
* @param string $reply_code
* @param int $reply_text
* @param \Exception $method_sig
*/
public function __construct($reply_code, $reply_text, $method_sig)
{
parent::__construct($reply_text, $reply_code);
$this->amqp_reply_code = $reply_code; // redundant, but kept for BC
$this->amqp_reply_text = $reply_text; // redundant, but kept for BC
$this->amqp_method_sig = $method_sig;
$ms = MiscHelper::methodSig($method_sig);
$PROTOCOL_CONSTANTS_CLASS = AbstractChannel::$PROTOCOL_CONSTANTS_CLASS;
$mn = isset($PROTOCOL_CONSTANTS_CLASS::$GLOBAL_METHOD_NAMES[$ms])
? $PROTOCOL_CONSTANTS_CLASS::$GLOBAL_METHOD_NAMES[$ms]
: $mn = '';
$this->args = array($reply_code, $reply_text, $method_sig, $mn);
}
}

View File

@@ -1,6 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
class AMQPRuntimeException extends \RuntimeException implements AMQPExceptionInterface
{
}

View File

@@ -1,6 +0,0 @@
<?php
namespace PhpAmqpLib\Exception;
class AMQPTimeoutException extends \RuntimeException implements AMQPExceptionInterface
{
}

View File

@@ -1,126 +0,0 @@
<?php
namespace PhpAmqpLib\Helper;
class MiscHelper
{
public static function debug_msg($s)
{
echo $s . PHP_EOL;
}
/**
* @param $a
* @return string
*/
public static function methodSig($a)
{
if (is_string($a)) {
return $a;
} else {
return sprintf('%d,%d', $a[0], $a[1]);
}
}
/**
* @param $bytes
*/
public static function saveBytes($bytes)
{
$fh = fopen('/tmp/bytes', 'wb');
fwrite($fh, $bytes);
fclose($fh);
}
/**
* Gets a number (either int or float) and returns an array containing its integer part as first element and its
* decimal part mutliplied by 10^6. Useful for some PHP stream functions that need seconds and microseconds as
* different arguments
*
* @param $number
* @return array
*/
public static function splitSecondsMicroseconds($number)
{
return array(floor($number), ($number - floor($number)) * 1000000);
}
/**
* View any string as a hexdump.
*
* This is most commonly used to view binary data from streams
* or sockets while debugging, but can be used to view any string
* with non-viewable characters.
*
* @version 1.3.2
* @author Aidan Lister <aidan@php.net>
* @author Peter Waller <iridum@php.net>
* @link http://aidanlister.com/repos/v/function.hexdump.php
*
* @param string $data The string to be dumped
* @param bool $htmloutput Set to false for non-HTML output
* @param bool $uppercase Set to true for uppercase hex
* @param bool $return Set to true to return the dump
* @return string
*/
public static function hexdump($data, $htmloutput = true, $uppercase = false, $return = false)
{
// Init
$hexi = '';
$ascii = '';
$dump = $htmloutput ? '<pre>' : '';
$offset = 0;
$len = mb_strlen($data, 'ASCII');
// Upper or lower case hexidecimal
$hexFormat = $uppercase ? 'X' : 'x';
// Iterate string
for ($i = $j = 0; $i < $len; $i++) {
// Convert to hexidecimal
// We must use concatenation here because the $hexFormat value
// is needed for sprintf() to parse the format
$hexi .= sprintf('%02' . $hexFormat . ' ', ord($data[$i]));
// Replace non-viewable bytes with '.'
if (ord($data[$i]) >= 32) {
$ascii .= $htmloutput ? htmlentities($data[$i]) : $data[$i];
} else {
$ascii .= '.';
}
// Add extra column spacing
if ($j === 7) {
$hexi .= ' ';
$ascii .= ' ';
}
// Add row
if (++$j === 16 || $i === $len - 1) {
// Join the hexi / ascii output
// We must use concatenation here because the $hexFormat value
// is needed for sprintf() to parse the format
$dump .= sprintf('%04' . $hexFormat . ' %-49s %s', $offset, $hexi, $ascii);
// Reset vars
$hexi = $ascii = '';
$offset += 16;
$j = 0;
// Add newline
if ($i !== $len - 1) {
$dump .= PHP_EOL;
}
}
}
// Finish dump
$dump .= $htmloutput ? '</pre>' : '';
$dump .= PHP_EOL;
if ($return) {
return $dump;
}
echo $dump;
}
}

View File

@@ -1,120 +0,0 @@
<?php
/* This file was autogenerated by spec/parser.php - Do not modify */
namespace PhpAmqpLib\Helper\Protocol;
class MethodMap080
{
protected $method_map = array(
'10,10' => 'connection_start',
'10,11' => 'connection_start_ok',
'10,20' => 'connection_secure',
'10,21' => 'connection_secure_ok',
'10,30' => 'connection_tune',
'10,31' => 'connection_tune_ok',
'10,40' => 'connection_open',
'10,41' => 'connection_open_ok',
'10,50' => 'connection_redirect',
'10,60' => 'connection_close',
'10,61' => 'connection_close_ok',
'20,10' => 'channel_open',
'20,11' => 'channel_open_ok',
'20,20' => 'channel_flow',
'20,21' => 'channel_flow_ok',
'20,30' => 'channel_alert',
'20,40' => 'channel_close',
'20,41' => 'channel_close_ok',
'30,10' => 'access_request',
'30,11' => 'access_request_ok',
'40,10' => 'exchange_declare',
'40,11' => 'exchange_declare_ok',
'40,20' => 'exchange_delete',
'40,21' => 'exchange_delete_ok',
'50,10' => 'queue_declare',
'50,11' => 'queue_declare_ok',
'50,20' => 'queue_bind',
'50,21' => 'queue_bind_ok',
'50,30' => 'queue_purge',
'50,31' => 'queue_purge_ok',
'50,40' => 'queue_delete',
'50,41' => 'queue_delete_ok',
'50,50' => 'queue_unbind',
'50,51' => 'queue_unbind_ok',
'60,10' => 'basic_qos',
'60,11' => 'basic_qos_ok',
'60,20' => 'basic_consume',
'60,21' => 'basic_consume_ok',
'60,30' => 'basic_cancel',
'60,31' => 'basic_cancel_ok',
'60,40' => 'basic_publish',
'60,50' => 'basic_return',
'60,60' => 'basic_deliver',
'60,70' => 'basic_get',
'60,71' => 'basic_get_ok',
'60,72' => 'basic_get_empty',
'60,80' => 'basic_ack',
'60,90' => 'basic_reject',
'60,100' => 'basic_recover_async',
'60,110' => 'basic_recover',
'60,111' => 'basic_recover_ok',
'70,10' => 'file_qos',
'70,11' => 'file_qos_ok',
'70,20' => 'file_consume',
'70,21' => 'file_consume_ok',
'70,30' => 'file_cancel',
'70,31' => 'file_cancel_ok',
'70,40' => 'file_open',
'70,41' => 'file_open_ok',
'70,50' => 'file_stage',
'70,60' => 'file_publish',
'70,70' => 'file_return',
'70,80' => 'file_deliver',
'70,90' => 'file_ack',
'70,100' => 'file_reject',
'80,10' => 'stream_qos',
'80,11' => 'stream_qos_ok',
'80,20' => 'stream_consume',
'80,21' => 'stream_consume_ok',
'80,30' => 'stream_cancel',
'80,31' => 'stream_cancel_ok',
'80,40' => 'stream_publish',
'80,50' => 'stream_return',
'80,60' => 'stream_deliver',
'90,10' => 'tx_select',
'90,11' => 'tx_select_ok',
'90,20' => 'tx_commit',
'90,21' => 'tx_commit_ok',
'90,30' => 'tx_rollback',
'90,31' => 'tx_rollback_ok',
'100,10' => 'dtx_select',
'100,11' => 'dtx_select_ok',
'100,20' => 'dtx_start',
'100,21' => 'dtx_start_ok',
'110,10' => 'tunnel_request',
'120,10' => 'test_integer',
'120,11' => 'test_integer_ok',
'120,20' => 'test_string',
'120,21' => 'test_string_ok',
'120,30' => 'test_table',
'120,31' => 'test_table_ok',
'120,40' => 'test_content',
'120,41' => 'test_content_ok',
);
public function get_method($method_sig)
{
return $this->method_map[$method_sig];
}
public function valid_method($method_sig)
{
return array_key_exists($method_sig, $this->method_map);
}
}

View File

@@ -1,91 +0,0 @@
<?php
/* This file was autogenerated by spec/parser.php - Do not modify */
namespace PhpAmqpLib\Helper\Protocol;
class MethodMap091
{
protected $method_map = array(
'10,10' => 'connection_start',
'10,11' => 'connection_start_ok',
'10,20' => 'connection_secure',
'10,21' => 'connection_secure_ok',
'10,30' => 'connection_tune',
'10,31' => 'connection_tune_ok',
'10,40' => 'connection_open',
'10,41' => 'connection_open_ok',
'10,50' => 'connection_close',
'10,51' => 'connection_close_ok',
'10,60' => 'connection_blocked',
'10,61' => 'connection_unblocked',
'20,10' => 'channel_open',
'20,11' => 'channel_open_ok',
'20,20' => 'channel_flow',
'20,21' => 'channel_flow_ok',
'20,40' => 'channel_close',
'20,41' => 'channel_close_ok',
'30,10' => 'access_request',
'30,11' => 'access_request_ok',
'40,10' => 'exchange_declare',
'40,11' => 'exchange_declare_ok',
'40,20' => 'exchange_delete',
'40,21' => 'exchange_delete_ok',
'40,30' => 'exchange_bind',
'40,31' => 'exchange_bind_ok',
'40,40' => 'exchange_unbind',
'40,51' => 'exchange_unbind_ok',
'50,10' => 'queue_declare',
'50,11' => 'queue_declare_ok',
'50,20' => 'queue_bind',
'50,21' => 'queue_bind_ok',
'50,30' => 'queue_purge',
'50,31' => 'queue_purge_ok',
'50,40' => 'queue_delete',
'50,41' => 'queue_delete_ok',
'50,50' => 'queue_unbind',
'50,51' => 'queue_unbind_ok',
'60,10' => 'basic_qos',
'60,11' => 'basic_qos_ok',
'60,20' => 'basic_consume',
'60,21' => 'basic_consume_ok',
'60,30' => 'basic_cancel_from_server',
'60,31' => 'basic_cancel_ok',
'60,40' => 'basic_publish',
'60,50' => 'basic_return',
'60,60' => 'basic_deliver',
'60,70' => 'basic_get',
'60,71' => 'basic_get_ok',
'60,72' => 'basic_get_empty',
'60,80' => 'basic_ack_from_server',
'60,90' => 'basic_reject',
'60,100' => 'basic_recover_async',
'60,110' => 'basic_recover',
'60,111' => 'basic_recover_ok',
'60,120' => 'basic_nack_from_server',
'90,10' => 'tx_select',
'90,11' => 'tx_select_ok',
'90,20' => 'tx_commit',
'90,21' => 'tx_commit_ok',
'90,30' => 'tx_rollback',
'90,31' => 'tx_rollback_ok',
'85,10' => 'confirm_select',
'85,11' => 'confirm_select_ok',
);
public function get_method($method_sig)
{
return $this->method_map[$method_sig];
}
public function valid_method($method_sig)
{
return array_key_exists($method_sig, $this->method_map);
}
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,870 +0,0 @@
<?php
/* This file was autogenerated by spec/parser.php - Do not modify */
namespace PhpAmqpLib\Helper\Protocol;
use PhpAmqpLib\Wire\AMQPWriter;
use PhpAmqpLib\Wire\AMQPReader;
class Protocol091
{
/**
* @return array
*/
public function connectionStart($version_major = 0, $version_minor = 9, $server_properties, $mechanisms = 'PLAIN', $locales = 'en_US')
{
$args = new AMQPWriter();
$args->write_octet($version_major);
$args->write_octet($version_minor);
$args->write_table(empty($server_properties) ? array() : $server_properties);
$args->write_longstr($mechanisms);
$args->write_longstr($locales);
return array(10, 10, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function connectionStartOk($args)
{
$ret = array();
$ret[] = $args->read_table();
$ret[] = $args->read_shortstr();
$ret[] = $args->read_longstr();
$ret[] = $args->read_shortstr();
return $ret;
}
/**
* @return array
*/
public function connectionSecure($challenge)
{
$args = new AMQPWriter();
$args->write_longstr($challenge);
return array(10, 20, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function connectionSecureOk($args)
{
$ret = array();
$ret[] = $args->read_longstr();
return $ret;
}
/**
* @return array
*/
public function connectionTune($channel_max = 0, $frame_max = 0, $heartbeat = 0)
{
$args = new AMQPWriter();
$args->write_short($channel_max);
$args->write_long($frame_max);
$args->write_short($heartbeat);
return array(10, 30, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function connectionTuneOk($args)
{
$ret = array();
$ret[] = $args->read_short();
$ret[] = $args->read_long();
$ret[] = $args->read_short();
return $ret;
}
/**
* @return array
*/
public function connectionOpen($virtual_host = '/', $capabilities = '', $insist = false)
{
$args = new AMQPWriter();
$args->write_shortstr($virtual_host);
$args->write_shortstr($capabilities);
$args->write_bits(array($insist));
return array(10, 40, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function connectionOpenOk($args)
{
$ret = array();
$ret[] = $args->read_shortstr();
return $ret;
}
/**
* @return array
*/
public function connectionClose($reply_code, $reply_text = '', $class_id, $method_id)
{
$args = new AMQPWriter();
$args->write_short($reply_code);
$args->write_shortstr($reply_text);
$args->write_short($class_id);
$args->write_short($method_id);
return array(10, 50, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function connectionCloseOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function connectionBlocked($reason = '')
{
$args = new AMQPWriter();
$args->write_shortstr($reason);
return array(10, 60, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function connectionUnblocked($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function channelOpen($out_of_band = '')
{
$args = new AMQPWriter();
$args->write_shortstr($out_of_band);
return array(20, 10, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function channelOpenOk($args)
{
$ret = array();
$ret[] = $args->read_longstr();
return $ret;
}
/**
* @return array
*/
public function channelFlow($active)
{
$args = new AMQPWriter();
$args->write_bits(array($active));
return array(20, 20, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function channelFlowOk($args)
{
$ret = array();
$ret[] = $args->read_bit();
return $ret;
}
/**
* @return array
*/
public function channelClose($reply_code, $reply_text = '', $class_id, $method_id)
{
$args = new AMQPWriter();
$args->write_short($reply_code);
$args->write_shortstr($reply_text);
$args->write_short($class_id);
$args->write_short($method_id);
return array(20, 40, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function channelCloseOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function accessRequest($realm = '/data', $exclusive = false, $passive = true, $active = true, $write = true, $read = true)
{
$args = new AMQPWriter();
$args->write_shortstr($realm);
$args->write_bits(array($exclusive, $passive, $active, $write, $read));
return array(30, 10, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function accessRequestOk($args)
{
$ret = array();
$ret[] = $args->read_short();
return $ret;
}
/**
* @return array
*/
public function exchangeDeclare($ticket = 0, $exchange, $type = 'direct', $passive = false, $durable = false, $auto_delete = false, $internal = false, $nowait = false, $arguments = array())
{
$args = new AMQPWriter();
$args->write_short($ticket);
$args->write_shortstr($exchange);
$args->write_shortstr($type);
$args->write_bits(array($passive, $durable, $auto_delete, $internal, $nowait));
$args->write_table(empty($arguments) ? array() : $arguments);
return array(40, 10, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function exchangeDeclareOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function exchangeDelete($ticket = 0, $exchange, $if_unused = false, $nowait = false)
{
$args = new AMQPWriter();
$args->write_short($ticket);
$args->write_shortstr($exchange);
$args->write_bits(array($if_unused, $nowait));
return array(40, 20, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function exchangeDeleteOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function exchangeBind($ticket = 0, $destination, $source, $routing_key = '', $nowait = false, $arguments = array())
{
$args = new AMQPWriter();
$args->write_short($ticket);
$args->write_shortstr($destination);
$args->write_shortstr($source);
$args->write_shortstr($routing_key);
$args->write_bits(array($nowait));
$args->write_table(empty($arguments) ? array() : $arguments);
return array(40, 30, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function exchangeBindOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function exchangeUnbind($ticket = 0, $destination, $source, $routing_key = '', $nowait = false, $arguments = array())
{
$args = new AMQPWriter();
$args->write_short($ticket);
$args->write_shortstr($destination);
$args->write_shortstr($source);
$args->write_shortstr($routing_key);
$args->write_bits(array($nowait));
$args->write_table(empty($arguments) ? array() : $arguments);
return array(40, 40, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function exchangeUnbindOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function queueDeclare($ticket = 0, $queue = '', $passive = false, $durable = false, $exclusive = false, $auto_delete = false, $nowait = false, $arguments = array())
{
$args = new AMQPWriter();
$args->write_short($ticket);
$args->write_shortstr($queue);
$args->write_bits(array($passive, $durable, $exclusive, $auto_delete, $nowait));
$args->write_table(empty($arguments) ? array() : $arguments);
return array(50, 10, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function queueDeclareOk($args)
{
$ret = array();
$ret[] = $args->read_shortstr();
$ret[] = $args->read_long();
$ret[] = $args->read_long();
return $ret;
}
/**
* @return array
*/
public function queueBind($ticket = 0, $queue = '', $exchange, $routing_key = '', $nowait = false, $arguments = array())
{
$args = new AMQPWriter();
$args->write_short($ticket);
$args->write_shortstr($queue);
$args->write_shortstr($exchange);
$args->write_shortstr($routing_key);
$args->write_bits(array($nowait));
$args->write_table(empty($arguments) ? array() : $arguments);
return array(50, 20, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function queueBindOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function queuePurge($ticket = 0, $queue = '', $nowait = false)
{
$args = new AMQPWriter();
$args->write_short($ticket);
$args->write_shortstr($queue);
$args->write_bits(array($nowait));
return array(50, 30, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function queuePurgeOk($args)
{
$ret = array();
$ret[] = $args->read_long();
return $ret;
}
/**
* @return array
*/
public function queueDelete($ticket = 0, $queue = '', $if_unused = false, $if_empty = false, $nowait = false)
{
$args = new AMQPWriter();
$args->write_short($ticket);
$args->write_shortstr($queue);
$args->write_bits(array($if_unused, $if_empty, $nowait));
return array(50, 40, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function queueDeleteOk($args)
{
$ret = array();
$ret[] = $args->read_long();
return $ret;
}
/**
* @return array
*/
public function queueUnbind($ticket = 0, $queue = '', $exchange, $routing_key = '', $arguments = array())
{
$args = new AMQPWriter();
$args->write_short($ticket);
$args->write_shortstr($queue);
$args->write_shortstr($exchange);
$args->write_shortstr($routing_key);
$args->write_table(empty($arguments) ? array() : $arguments);
return array(50, 50, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function queueUnbindOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function basicQos($prefetch_size = 0, $prefetch_count = 0, $global = false)
{
$args = new AMQPWriter();
$args->write_long($prefetch_size);
$args->write_short($prefetch_count);
$args->write_bits(array($global));
return array(60, 10, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function basicQosOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function basicConsume($ticket = 0, $queue = '', $consumer_tag = '', $no_local = false, $no_ack = false, $exclusive = false, $nowait = false, $arguments = array())
{
$args = new AMQPWriter();
$args->write_short($ticket);
$args->write_shortstr($queue);
$args->write_shortstr($consumer_tag);
$args->write_bits(array($no_local, $no_ack, $exclusive, $nowait));
$args->write_table(empty($arguments) ? array() : $arguments);
return array(60, 20, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function basicConsumeOk($args)
{
$ret = array();
$ret[] = $args->read_shortstr();
return $ret;
}
/**
* @return array
*/
public function basicCancel($consumer_tag, $nowait = false)
{
$args = new AMQPWriter();
$args->write_shortstr($consumer_tag);
$args->write_bits(array($nowait));
return array(60, 30, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function basicCancelOk($args)
{
$ret = array();
$ret[] = $args->read_shortstr();
return $ret;
}
/**
* @return array
*/
public function basicPublish($ticket = 0, $exchange = '', $routing_key = '', $mandatory = false, $immediate = false)
{
$args = new AMQPWriter();
$args->write_short($ticket);
$args->write_shortstr($exchange);
$args->write_shortstr($routing_key);
$args->write_bits(array($mandatory, $immediate));
return array(60, 40, $args);
}
/**
* @return array
*/
public function basicReturn($reply_code, $reply_text = '', $exchange, $routing_key)
{
$args = new AMQPWriter();
$args->write_short($reply_code);
$args->write_shortstr($reply_text);
$args->write_shortstr($exchange);
$args->write_shortstr($routing_key);
return array(60, 50, $args);
}
/**
* @return array
*/
public function basicDeliver($consumer_tag, $delivery_tag, $redelivered = false, $exchange, $routing_key)
{
$args = new AMQPWriter();
$args->write_shortstr($consumer_tag);
$args->write_longlong($delivery_tag);
$args->write_bits(array($redelivered));
$args->write_shortstr($exchange);
$args->write_shortstr($routing_key);
return array(60, 60, $args);
}
/**
* @return array
*/
public function basicGet($ticket = 0, $queue = '', $no_ack = false)
{
$args = new AMQPWriter();
$args->write_short($ticket);
$args->write_shortstr($queue);
$args->write_bits(array($no_ack));
return array(60, 70, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function basicGetOk($args)
{
$ret = array();
$ret[] = $args->read_longlong();
$ret[] = $args->read_bit();
$ret[] = $args->read_shortstr();
$ret[] = $args->read_shortstr();
$ret[] = $args->read_long();
return $ret;
}
/**
* @param AMQPReader $args
* @return array
*/
public static function basicGetEmpty($args)
{
$ret = array();
$ret[] = $args->read_shortstr();
return $ret;
}
/**
* @return array
*/
public function basicAck($delivery_tag = 0, $multiple = false)
{
$args = new AMQPWriter();
$args->write_longlong($delivery_tag);
$args->write_bits(array($multiple));
return array(60, 80, $args);
}
/**
* @return array
*/
public function basicReject($delivery_tag, $requeue = true)
{
$args = new AMQPWriter();
$args->write_longlong($delivery_tag);
$args->write_bits(array($requeue));
return array(60, 90, $args);
}
/**
* @return array
*/
public function basicRecoverAsync($requeue = false)
{
$args = new AMQPWriter();
$args->write_bits(array($requeue));
return array(60, 100, $args);
}
/**
* @return array
*/
public function basicRecover($requeue = false)
{
$args = new AMQPWriter();
$args->write_bits(array($requeue));
return array(60, 110, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function basicRecoverOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function basicNack($delivery_tag = 0, $multiple = false, $requeue = true)
{
$args = new AMQPWriter();
$args->write_longlong($delivery_tag);
$args->write_bits(array($multiple, $requeue));
return array(60, 120, $args);
}
/**
* @return array
*/
public function txSelect()
{
$args = new AMQPWriter();
return array(90, 10, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function txSelectOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function txCommit()
{
$args = new AMQPWriter();
return array(90, 20, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function txCommitOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function txRollback()
{
$args = new AMQPWriter();
return array(90, 30, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function txRollbackOk($args)
{
$ret = array();
return $ret;
}
/**
* @return array
*/
public function confirmSelect($nowait = false)
{
$args = new AMQPWriter();
$args->write_bits(array($nowait));
return array(85, 10, $args);
}
/**
* @param AMQPReader $args
* @return array
*/
public static function confirmSelectOk($args)
{
$ret = array();
return $ret;
}
}

View File

@@ -1,113 +0,0 @@
<?php
/* This file was autogenerated by spec/parser.php - Do not modify */
namespace PhpAmqpLib\Helper\Protocol;
class Wait080
{
protected $wait = array(
'connection.start' => '10,10',
'connection.start_ok' => '10,11',
'connection.secure' => '10,20',
'connection.secure_ok' => '10,21',
'connection.tune' => '10,30',
'connection.tune_ok' => '10,31',
'connection.open' => '10,40',
'connection.open_ok' => '10,41',
'connection.redirect' => '10,50',
'connection.close' => '10,60',
'connection.close_ok' => '10,61',
'channel.open' => '20,10',
'channel.open_ok' => '20,11',
'channel.flow' => '20,20',
'channel.flow_ok' => '20,21',
'channel.alert' => '20,30',
'channel.close' => '20,40',
'channel.close_ok' => '20,41',
'access.request' => '30,10',
'access.request_ok' => '30,11',
'exchange.declare' => '40,10',
'exchange.declare_ok' => '40,11',
'exchange.delete' => '40,20',
'exchange.delete_ok' => '40,21',
'queue.declare' => '50,10',
'queue.declare_ok' => '50,11',
'queue.bind' => '50,20',
'queue.bind_ok' => '50,21',
'queue.purge' => '50,30',
'queue.purge_ok' => '50,31',
'queue.delete' => '50,40',
'queue.delete_ok' => '50,41',
'queue.unbind' => '50,50',
'queue.unbind_ok' => '50,51',
'basic.qos' => '60,10',
'basic.qos_ok' => '60,11',
'basic.consume' => '60,20',
'basic.consume_ok' => '60,21',
'basic.cancel' => '60,30',
'basic.cancel_ok' => '60,31',
'basic.publish' => '60,40',
'basic.return' => '60,50',
'basic.deliver' => '60,60',
'basic.get' => '60,70',
'basic.get_ok' => '60,71',
'basic.get_empty' => '60,72',
'basic.ack' => '60,80',
'basic.reject' => '60,90',
'basic.recover_async' => '60,100',
'basic.recover' => '60,110',
'basic.recover_ok' => '60,111',
'file.qos' => '70,10',
'file.qos_ok' => '70,11',
'file.consume' => '70,20',
'file.consume_ok' => '70,21',
'file.cancel' => '70,30',
'file.cancel_ok' => '70,31',
'file.open' => '70,40',
'file.open_ok' => '70,41',
'file.stage' => '70,50',
'file.publish' => '70,60',
'file.return' => '70,70',
'file.deliver' => '70,80',
'file.ack' => '70,90',
'file.reject' => '70,100',
'stream.qos' => '80,10',
'stream.qos_ok' => '80,11',
'stream.consume' => '80,20',
'stream.consume_ok' => '80,21',
'stream.cancel' => '80,30',
'stream.cancel_ok' => '80,31',
'stream.publish' => '80,40',
'stream.return' => '80,50',
'stream.deliver' => '80,60',
'tx.select' => '90,10',
'tx.select_ok' => '90,11',
'tx.commit' => '90,20',
'tx.commit_ok' => '90,21',
'tx.rollback' => '90,30',
'tx.rollback_ok' => '90,31',
'dtx.select' => '100,10',
'dtx.select_ok' => '100,11',
'dtx.start' => '100,20',
'dtx.start_ok' => '100,21',
'tunnel.request' => '110,10',
'test.integer' => '120,10',
'test.integer_ok' => '120,11',
'test.string' => '120,20',
'test.string_ok' => '120,21',
'test.table' => '120,30',
'test.table_ok' => '120,31',
'test.content' => '120,40',
'test.content_ok' => '120,41',
);
public function get_wait($method)
{
return $this->wait[$method];
}
}

View File

@@ -1,84 +0,0 @@
<?php
/* This file was autogenerated by spec/parser.php - Do not modify */
namespace PhpAmqpLib\Helper\Protocol;
class Wait091
{
protected $wait = array(
'connection.start' => '10,10',
'connection.start_ok' => '10,11',
'connection.secure' => '10,20',
'connection.secure_ok' => '10,21',
'connection.tune' => '10,30',
'connection.tune_ok' => '10,31',
'connection.open' => '10,40',
'connection.open_ok' => '10,41',
'connection.close' => '10,50',
'connection.close_ok' => '10,51',
'connection.blocked' => '10,60',
'connection.unblocked' => '10,61',
'channel.open' => '20,10',
'channel.open_ok' => '20,11',
'channel.flow' => '20,20',
'channel.flow_ok' => '20,21',
'channel.close' => '20,40',
'channel.close_ok' => '20,41',
'access.request' => '30,10',
'access.request_ok' => '30,11',
'exchange.declare' => '40,10',
'exchange.declare_ok' => '40,11',
'exchange.delete' => '40,20',
'exchange.delete_ok' => '40,21',
'exchange.bind' => '40,30',
'exchange.bind_ok' => '40,31',
'exchange.unbind' => '40,40',
'exchange.unbind_ok' => '40,51',
'queue.declare' => '50,10',
'queue.declare_ok' => '50,11',
'queue.bind' => '50,20',
'queue.bind_ok' => '50,21',
'queue.purge' => '50,30',
'queue.purge_ok' => '50,31',
'queue.delete' => '50,40',
'queue.delete_ok' => '50,41',
'queue.unbind' => '50,50',
'queue.unbind_ok' => '50,51',
'basic.qos' => '60,10',
'basic.qos_ok' => '60,11',
'basic.consume' => '60,20',
'basic.consume_ok' => '60,21',
'basic.cancel' => '60,30',
'basic.cancel_ok' => '60,31',
'basic.publish' => '60,40',
'basic.return' => '60,50',
'basic.deliver' => '60,60',
'basic.get' => '60,70',
'basic.get_ok' => '60,71',
'basic.get_empty' => '60,72',
'basic.ack' => '60,80',
'basic.reject' => '60,90',
'basic.recover_async' => '60,100',
'basic.recover' => '60,110',
'basic.recover_ok' => '60,111',
'basic.nack' => '60,120',
'tx.select' => '90,10',
'tx.select_ok' => '90,11',
'tx.commit' => '90,20',
'tx.commit_ok' => '90,21',
'tx.rollback' => '90,30',
'tx.rollback_ok' => '90,31',
'confirm.select' => '85,10',
'confirm.select_ok' => '85,11',
);
public function get_wait($method)
{
return $this->wait[$method];
}
}

View File

@@ -1,57 +0,0 @@
<?php
namespace PhpAmqpLib\Message;
use PhpAmqpLib\Wire\GenericContent;
/**
* A Message for use with the Channnel.basic_* methods.
*/
class AMQPMessage extends GenericContent
{
/** @var string */
public $body;
public $body_size;
public $is_truncated = false;
/** @var string */
public $content_encoding;
/** @var array */
protected static $propertyDefinitions = array(
'content_type' => 'shortstr',
'content_encoding' => 'shortstr',
'application_headers' => 'table_object',
'delivery_mode' => 'octet',
'priority' => 'octet',
'correlation_id' => 'shortstr',
'reply_to' => 'shortstr',
'expiration' => 'shortstr',
'message_id' => 'shortstr',
'timestamp' => 'timestamp',
'type' => 'shortstr',
'user_id' => 'shortstr',
'app_id' => 'shortstr',
'cluster_id' => 'shortstr',
);
/**
* @param string $body
* @param null $properties
*/
public function __construct($body = '', $properties = null)
{
$this->setBody($body);
parent::__construct($properties, static::$propertyDefinitions);
}
/**
* Sets the message payload
*
* @param mixed $body
* @return $this
*/
public function setBody($body)
{
$this->body = $body;
}
}

View File

@@ -1,446 +0,0 @@
<?php
namespace PhpAmqpLib\Wire;
use PhpAmqpLib\Channel\AbstractChannel;
use PhpAmqpLib\Exception;
/**
* Iterator implemented for transparent integration with AMQPWriter::write_[array|table]()
*/
abstract class AMQPAbstractCollection implements \Iterator
{
//protocol defines available field types and their corresponding symbols
const PROTOCOL_080 = AbstractChannel::PROTOCOL_080;
const PROTOCOL_091 = AbstractChannel::PROTOCOL_091;
const PROTOCOL_RBT = 'rabbit'; //pseudo proto
//Abstract data types
const T_INT_SHORTSHORT = 1;
const T_INT_SHORTSHORT_U = 2;
const T_INT_SHORT = 3;
const T_INT_SHORT_U = 4;
const T_INT_LONG = 5;
const T_INT_LONG_U = 6;
const T_INT_LONGLONG = 7;
const T_INT_LONGLONG_U = 8;
const T_DECIMAL = 9;
const T_TIMESTAMP = 10;
const T_VOID = 11;
const T_BOOL = 12;
const T_STRING_SHORT = 13;
const T_STRING_LONG = 14;
const T_ARRAY = 15;
const T_TABLE = 16;
/**
* @var string
*/
private static $_protocol = null;
/*
* Field types messy mess http://www.rabbitmq.com/amqp-0-9-1-errata.html#section_3
* Default behaviour is to use rabbitMQ compatible field-set
* Define AMQP_STRICT_FLD_TYPES=true to use strict AMQP instead
*/
private static $_types_080 = array(
self::T_INT_LONG => 'I',
self::T_DECIMAL => 'D',
self::T_TIMESTAMP => 'T',
self::T_STRING_LONG => 'S',
self::T_TABLE => 'F'
);
/**
* @var array
*/
private static $_types_091 = array(
self::T_INT_SHORTSHORT => 'b',
self::T_INT_SHORTSHORT_U => 'B',
self::T_INT_SHORT => 'U',
self::T_INT_SHORT_U => 'u',
self::T_INT_LONG => 'I',
self::T_INT_LONG_U => 'i',
self::T_INT_LONGLONG => 'L',
self::T_INT_LONGLONG_U => 'l',
self::T_DECIMAL => 'D',
self::T_TIMESTAMP => 'T',
self::T_VOID => 'V',
self::T_BOOL => 't',
self::T_STRING_SHORT => 's',
self::T_STRING_LONG => 'S',
self::T_ARRAY => 'A',
self::T_TABLE => 'F'
);
/**
* @var array
*/
private static $_types_rabbit = array(
self::T_INT_SHORTSHORT => 'b',
self::T_INT_SHORT => 's',
self::T_INT_LONG => 'I',
self::T_INT_LONGLONG => 'l',
self::T_DECIMAL => 'D',
self::T_TIMESTAMP => 'T',
self::T_VOID => 'V',
self::T_BOOL => 't',
self::T_STRING_LONG => 'S',
self::T_ARRAY => 'A',
self::T_TABLE => 'F'
);
/**
* @var array
*/
protected $data = array();
public function __construct(array $data = null)
{
if (!empty($data)) {
$this->data = $this->encodeCollection($data);
}
}
/**
* @return int
*/
abstract public function getType();
/**
* @param mixed $val
* @param int $type
* @param string $key
*/
final protected function setValue($val, $type = null, $key = null)
{
if ($val instanceof self) {
if ($type && ($type != $val->getType())) {
throw new Exception\AMQPInvalidArgumentException(
'Attempted to add instance of ' . get_class($val) . ' representing type [' . $val->getType() . '] as mismatching type [' . $type . ']'
);
}
$type = $val->getType();
} elseif ($type) { //ensuring data integrity and that all members are properly validated
switch ($type) {
case self::T_ARRAY:
throw new Exception\AMQPInvalidArgumentException('Arrays must be passed as AMQPArray instance');
break;
case self::T_TABLE:
throw new Exception\AMQPInvalidArgumentException('Tables must be passed as AMQPTable instance');
break;
case self::T_DECIMAL:
if (!($val instanceof AMQPDecimal)) {
throw new Exception\AMQPInvalidArgumentException('Decimal values must be instance of AMQPDecimal');
}
break;
}
}
if ($type) {
self::checkDataTypeIsSupported($type, false);
$val = array($type, $val);
} else {
$val = $this->encodeValue($val);
}
if ($key === null) {
$this->data[] = $val;
} else {
$this->data[$key] = $val;
}
}
/**
* @return array
*/
final public function getNativeData()
{
return $this->decodeCollection($this->data);
}
/**
* @param array $val
* @return array
*/
final protected function encodeCollection(array $val)
{
foreach ($val as &$v) {
$v = $this->encodeValue($v);
}
unset($v);
return $val;
}
/**
* @param array $val
* @return array
*/
final protected function decodeCollection(array $val)
{
foreach ($val as &$v) {
$v = $this->decodeValue($v[1], $v[0]);
}
unset($v);
return $val;
}
/**
* @param mixed $val
* @return mixed
* @throws Exception\AMQPOutOfBoundsException
*/
protected function encodeValue($val)
{
if (is_string($val)) {
$val = $this->encodeString($val);
} elseif (is_float($val)) {
$val = $this->encodeFloat($val);
} elseif (is_int($val)) {
$val = $this->encodeInt($val);
} elseif (is_bool($val)) {
$val = $this->encodeBool($val);
} elseif (is_null($val)) {
$val = $this->encodeVoid();
} elseif ($val instanceof \DateTime) {
$val = array(self::T_TIMESTAMP, $val->getTimestamp());
} elseif ($val instanceof AMQPDecimal) {
$val = array(self::T_DECIMAL, $val);
} elseif ($val instanceof self) {
//avoid silent type correction of strictly typed values
self::checkDataTypeIsSupported($val->getType(), false);
$val = array($val->getType(), $val);
} elseif (is_array($val)) {
//AMQP specs says "Field names MUST start with a letter, '$' or '#'"
//so beware, some servers may raise an exception with 503 code in cases when indexed array is encoded as table
if (self::isProtocol(self::PROTOCOL_080)) {
//080 doesn't support arrays, forcing table
$val = array(self::T_TABLE, new AMQPTable($val));
} elseif (empty($val) || (array_keys($val) === range(0, count($val) - 1))) {
$val = array(self::T_ARRAY, new AMQPArray($val));
} else {
$val = array(self::T_TABLE, new AMQPTable($val));
}
} else {
throw new Exception\AMQPOutOfBoundsException(sprintf('Encountered value of unsupported type: %s', gettype($val)));
}
return $val;
}
/**
* @param mixed $val
* @param integer $type
* @return array|bool|\DateTime|null
*/
protected function decodeValue($val, $type)
{
if ($val instanceof self) {
//covering arrays and tables
$val = $val->getNativeData();
} else {
switch ($type) {
case self::T_BOOL:
$val = (bool) $val;
break;
case self::T_TIMESTAMP:
$val = \DateTime::createFromFormat('U', $val);
break;
case self::T_VOID:
$val = null;
break;
case self::T_ARRAY:
case self::T_TABLE:
throw new Exception\AMQPLogicException(
'Encountered an array/table struct which is not an instance of AMQPCollection. ' .
'This is considered a bug and should be fixed, please report'
);
}
}
return $val;
}
/**
* @param string $val
* @return array
*/
protected function encodeString($val)
{
return array(self::T_STRING_LONG, $val);
}
/**
* @param int $val
* @return array
*/
protected function encodeInt($val)
{
if (($val >= -2147483648) && ($val <= 2147483647)) {
$ev = array(self::T_INT_LONG, $val);
} elseif (self::isProtocol(self::PROTOCOL_080)) {
//080 doesn't support longlong
$ev = $this->encodeString((string) $val);
} else {
$ev = array(self::T_INT_LONGLONG, $val);
}
return $ev;
}
/**
* @param float $val
* @return array
*/
protected function encodeFloat($val)
{
return static::encodeString((string) $val);
}
/**
* @param bool $val
* @return array
*/
protected function encodeBool($val)
{
$val = (bool) $val;
return self::isProtocol(self::PROTOCOL_080) ? array(self::T_INT_LONG, (int) $val) : array(self::T_BOOL, $val);
}
/**
* @return array
*/
protected function encodeVoid()
{
return self::isProtocol(self::PROTOCOL_080) ? $this->encodeString('') : array(self::T_VOID, null);
}
/**
* @return string
*/
final public static function getProtocol()
{
if (self::$_protocol === null) {
self::$_protocol = defined('AMQP_STRICT_FLD_TYPES') && AMQP_STRICT_FLD_TYPES ?
AbstractChannel::getProtocolVersion() :
self::PROTOCOL_RBT;
}
return self::$_protocol;
}
/**
* @param string $proto
* @return bool
*/
final public static function isProtocol($proto)
{
return self::getProtocol() == $proto;
}
/**
* @return array [dataTypeConstant => dataTypeSymbol]
*/
final public static function getSupportedDataTypes()
{
switch ($proto = self::getProtocol()) {
case self::PROTOCOL_080:
$types = self::$_types_080;
break;
case self::PROTOCOL_091:
$types = self::$_types_091;
break;
case self::PROTOCOL_RBT:
$types = self::$_types_rabbit;
break;
default:
throw new Exception\AMQPOutOfRangeException(sprintf('Unknown protocol: %s', $proto));
}
return $types;
}
/**
* @param string $type
* @param bool $return Whether to return or raise AMQPOutOfRangeException
* @return boolean
*/
final public static function checkDataTypeIsSupported($type, $return = true)
{
try {
$supported = self::getSupportedDataTypes();
if (!isset($supported[$type])) {
throw new Exception\AMQPOutOfRangeException(sprintf('AMQP-%s doesn\'t support data of type [%s]', self::getProtocol(), $type));
}
return true;
} catch (Exception\AMQPOutOfRangeException $ex) {
if (!$return) {
throw $ex;
}
return false;
}
}
/**
* @param integer $type
* @return string
*/
final public static function getSymbolForDataType($type)
{
$types = self::getSupportedDataTypes();
if (!isset($types[$type])) {
throw new Exception\AMQPOutOfRangeException(sprintf('AMQP-%s doesn\'t support data of type [%s]', self::getProtocol(), $type));
}
return $types[$type];
}
/**
* @param string $symbol
* @return integer
*/
final public static function getDataTypeForSymbol($symbol)
{
$symbols = array_flip(self::getSupportedDataTypes());
if (!isset($symbols[$symbol])) {
throw new Exception\AMQPOutOfRangeException(sprintf('AMQP-%s doesn\'t define data of type [%s]', self::getProtocol(), $symbol));
}
return $symbols[$symbol];
}
public function current()
{
return current($this->data);
}
public function key()
{
return key($this->data);
}
public function next()
{
next($this->data);
}
public function rewind()
{
reset($this->data);
}
public function valid()
{
return key($this->data) !== null;
}
}

View File

@@ -1,32 +0,0 @@
<?php
namespace PhpAmqpLib\Wire;
class AMQPArray extends AMQPAbstractCollection
{
public function __construct(array $data = null)
{
parent::__construct(empty($data) ? null : array_values($data));
}
/**
* @return int
*/
final public function getType()
{
return self::T_ARRAY;
}
/**
* @param mixed $val
* @param null $type
* @return $this
*/
public function push($val, $type = null)
{
$this->setValue($val, $type);
return $this;
}
}

View File

@@ -1,47 +0,0 @@
<?php
namespace PhpAmqpLib\Wire;
use PhpAmqpLib\Exception\AMQPOutOfBoundsException;
/**
* AMQP protocol decimal value.
*
* Values are represented as (n,e) pairs. The actual value
* is n * 10^(-e).
*
* From 0.8 spec: Decimal values are
* not intended to support floating point values, but rather
* business values such as currency rates and amounts. The
* 'decimals' octet is not signed.
*/
class AMQPDecimal
{
/** @var int */
protected $n;
/** @var int */
protected $e;
/**
* @param $n
* @param $e
* @throws \PhpAmqpLib\Exception\AMQPOutOfBoundsException
*/
public function __construct($n, $e)
{
if ($e < 0) {
throw new AMQPOutOfBoundsException('Decimal exponent value must be unsigned!');
}
$this->n = $n;
$this->e = $e;
}
/**
* @return string
*/
public function asBCvalue()
{
return bcdiv($this->n, bcpow(10, $this->e));
}
}

View File

@@ -1,534 +0,0 @@
<?php
namespace PhpAmqpLib\Wire;
use PhpAmqpLib\Exception\AMQPInvalidArgumentException;
use PhpAmqpLib\Exception\AMQPOutOfBoundsException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Helper\MiscHelper;
use PhpAmqpLib\Wire\IO\AbstractIO;
/**
* This class can read from a string or from a stream
*
* TODO : split this class: AMQPStreamReader and a AMQPBufferReader
*/
class AMQPReader extends AbstractClient
{
const BIT = 1;
const OCTET = 1;
const SHORTSTR = 1;
const SHORT = 2;
const LONG = 4;
const SIGNED_LONG = 4;
const READ_PHP_INT = 4; // use READ_ to avoid possible clashes with PHP
const LONGLONG = 8;
const TIMESTAMP = 8;
/** @var string */
protected $str;
/** @var int */
protected $str_length;
/** @var int */
protected $offset;
/** @var int */
protected $bitcount;
/** @var bool */
protected $is64bits;
/** @var int */
protected $timeout;
/** @var int */
protected $bits;
/** @var \PhpAmqpLib\Wire\IO\AbstractIO */
protected $io;
/**
* @param string $str
* @param AbstractIO $io
* @param int $timeout
*/
public function __construct($str, AbstractIO $io = null, $timeout = 0)
{
parent::__construct();
$this->str = $str;
$this->str_length = mb_strlen($this->str, 'ASCII');
$this->io = $io;
$this->offset = 0;
$this->bitcount = $this->bits = 0;
$this->timeout = $timeout;
}
/**
* Resets the object from the injected param
*
* Used to not need to create a new AMQPReader instance every time.
* when we can just pass a string and reset the object state.
* NOTE: since we are working with strings we don't need to pass an AbstractIO
* or a timeout.
*
* @param string $str
*/
public function reuse($str)
{
$this->str = $str;
$this->str_length = mb_strlen($this->str, 'ASCII');
$this->offset = 0;
$this->bitcount = $this->bits = 0;
}
/**
* Closes the stream
*/
public function close()
{
if ($this->io) {
$this->io->close();
}
}
/**
* @param $n
* @return string
*/
public function read($n)
{
$this->bitcount = $this->bits = 0;
return $this->rawread($n);
}
/**
* Waits until some data is retrieved from the socket.
*
* AMQPTimeoutException can be raised if the timeout is set
*
* @throws \PhpAmqpLib\Exception\AMQPTimeoutException
*/
protected function wait()
{
if ($this->timeout == 0) {
return;
}
// wait ..
list($sec, $usec) = MiscHelper::splitSecondsMicroseconds($this->timeout);
$result = $this->io->select($sec, $usec);
if ($result === false) {
throw new AMQPRuntimeException('A network error occured while awaiting for incoming data');
}
if ($result === 0) {
throw new AMQPTimeoutException(sprintf(
'The connection timed out after %s sec while awaiting incoming data',
$this->getTimeout()
));
}
}
/**
* @param $n
* @return string
* @throws \RuntimeException
* @throws \PhpAmqpLib\Exception\AMQPRuntimeException
*/
protected function rawread($n)
{
if ($this->io) {
$this->wait();
$res = $this->io->read($n);
$this->offset += $n;
} else {
if ($this->str_length < $n) {
throw new AMQPRuntimeException(sprintf(
'Error reading data. Requested %s bytes while string buffer has only %s',
$n,
$this->str_length
));
}
$res = mb_substr($this->str, 0, $n, 'ASCII');
$this->str = mb_substr($this->str, $n, mb_strlen($this->str, 'ASCII') - $n, 'ASCII');
$this->str_length -= $n;
$this->offset += $n;
}
return $res;
}
/**
* @return bool
*/
public function read_bit()
{
if (!$this->bitcount) {
$this->bits = ord($this->rawread(1));
$this->bitcount = 8;
}
$result = ($this->bits & 1) == 1;
$this->bits >>= 1;
$this->bitcount -= 1;
return $result;
}
/**
* @return mixed
*/
public function read_octet()
{
$this->bitcount = $this->bits = 0;
list(, $res) = unpack('C', $this->rawread(1));
return $res;
}
/**
* @return mixed
*/
public function read_signed_octet()
{
$this->bitcount = $this->bits = 0;
list(, $res) = unpack('c', $this->rawread(1));
return $res;
}
/**
* @return mixed
*/
public function read_short()
{
$this->bitcount = $this->bits = 0;
list(, $res) = unpack('n', $this->rawread(2));
return $res;
}
/**
* @return mixed
*/
public function read_signed_short()
{
$this->bitcount = $this->bits = 0;
list(, $res) = unpack('s', $this->correctEndianness($this->rawread(2)));
return $res;
}
/**
* Reads 32 bit integer in big-endian byte order.
*
* On 64 bit systems it will return always unsigned int
* value in 0..2^32 range.
*
* On 32 bit systems it will return signed int value in
* -2^31...+2^31 range.
*
* Use with caution!
*/
public function read_php_int()
{
list(, $res) = unpack('N', $this->rawread(4));
if ($this->is64bits) {
$sres = sprintf('%u', $res);
return (int) $sres;
} else {
return $res;
}
}
/**
* PHP does not have unsigned 32 bit int,
* so we return it as a string
*
* @return string
*/
public function read_long()
{
$this->bitcount = $this->bits = 0;
list(, $res) = unpack('N', $this->rawread(4));
return !$this->is64bits && self::getLongMSB($res) ? sprintf('%u', $res) : $res;
}
/**
* @return integer
*/
private function read_signed_long()
{
$this->bitcount = $this->bits = 0;
list(, $res) = unpack('l', $this->correctEndianness($this->rawread(4)));
return $res;
}
/**
* Even on 64 bit systems PHP integers are singed.
* Since we need an unsigned value here we return it
* as a string.
*
* @return string
*/
public function read_longlong()
{
$this->bitcount = $this->bits = 0;
list(, $hi, $lo) = unpack('N2', $this->rawread(8));
$msb = self::getLongMSB($hi);
if (!$this->is64bits) {
if ($msb) {
$hi = sprintf('%u', $hi);
}
if (self::getLongMSB($lo)) {
$lo = sprintf('%u', $lo);
}
}
return bcadd($this->is64bits && !$msb ? $hi << 32 : bcmul($hi, '4294967296', 0), $lo, 0);
}
/**
* @return string
*/
public function read_signed_longlong()
{
$this->bitcount = $this->bits = 0;
list(, $hi, $lo) = unpack('N2', $this->rawread(8));
if ($this->is64bits) {
return bcadd($hi << 32, $lo, 0);
} else {
return bcadd(bcmul($hi, '4294967296', 0), self::getLongMSB($lo) ? sprintf('%u', $lo) : $lo, 0);
}
}
/**
* @param int $longInt
* @return bool
*/
private static function getLongMSB($longInt)
{
return (bool) ($longInt & 0x80000000);
}
/**
* Read a utf-8 encoded string that's stored in up to
* 255 bytes. Return it decoded as a PHP unicode object.
*/
public function read_shortstr()
{
$this->bitcount = $this->bits = 0;
list(, $slen) = unpack('C', $this->rawread(1));
return $this->rawread($slen);
}
/**
* Read a string that's up to 2**32 bytes, the encoding
* isn't specified in the AMQP spec, so just return it as
* a plain PHP string.
*/
public function read_longstr()
{
$this->bitcount = $this->bits = 0;
$slen = $this->read_php_int();
if ($slen < 0) {
throw new AMQPOutOfBoundsException('Strings longer than supported on this platform');
}
return $this->rawread($slen);
}
/**
* Read and AMQP timestamp, which is a 64-bit integer representing
* seconds since the Unix epoch in 1-second resolution.
*/
public function read_timestamp()
{
return $this->read_longlong();
}
/**
* Read an AMQP table, and return as a PHP array. keys are strings,
* values are (type,value) tuples.
*
* @param bool $returnObject Whether to return AMQPArray instance instead of plain array
* @return array|AMQPTable
*/
public function read_table($returnObject = false)
{
$this->bitcount = $this->bits = 0;
$tlen = $this->read_php_int();
if ($tlen < 0) {
throw new AMQPOutOfBoundsException('Table is longer than supported');
}
$table_data = new AMQPReader($this->rawread($tlen), null);
$result = $returnObject ? new AMQPTable() : array();
while ($table_data->tell() < $tlen) {
$name = $table_data->read_shortstr();
$ftype = AMQPAbstractCollection::getDataTypeForSymbol($ftypeSym = $table_data->rawread(1));
$val = $table_data->read_value($ftype, $returnObject);
$returnObject ? $result->set($name, $val, $ftype) : $result[$name] = array($ftypeSym, $val);
}
return $result;
}
/**
* @return array|AMQPTable
*/
public function read_table_object()
{
return $this->read_table(true);
}
/**
* Reads the array in the next value.
*
* @param bool $returnObject Whether to return AMQPArray instance instead of plain array
* @return array|AMQPArray
*/
public function read_array($returnObject = false)
{
$this->bitcount = $this->bits = 0;
// Determine array length and its end position
$arrayLength = $this->read_php_int();
$endOffset = $this->offset + $arrayLength;
$result = $returnObject ? new AMQPArray() : array();
// Read values until we reach the end of the array
while ($this->offset < $endOffset) {
$fieldType = AMQPAbstractCollection::getDataTypeForSymbol($this->rawread(1));
$fieldValue = $this->read_value($fieldType, $returnObject);
$returnObject ? $result->push($fieldValue, $fieldType) : $result[] = $fieldValue;
}
return $result;
}
/**
* @return array|AMQPArray
*/
public function read_array_object()
{
return $this->read_array(true);
}
/**
* Reads the next value as the provided field type.
*
* @param int $fieldType One of AMQPAbstractCollection::T_* constants
* @param bool $collectionsAsObjects Description
* @return mixed
* @throws \PhpAmqpLib\Exception\AMQPRuntimeException
*/
public function read_value($fieldType, $collectionsAsObjects = false)
{
$this->bitcount = $this->bits = 0;
$val = null;
switch ($fieldType) {
case AMQPAbstractCollection::T_INT_SHORTSHORT:
//according to AMQP091 spec, 'b' is not bit, it is short-short-int, also valid for rabbit/qpid
//$val=$this->read_bit();
$val = $this->read_signed_octet();
break;
case AMQPAbstractCollection::T_INT_SHORTSHORT_U:
$val = $this->read_octet();
break;
case AMQPAbstractCollection::T_INT_SHORT:
$val = $this->read_signed_short();
break;
case AMQPAbstractCollection::T_INT_SHORT_U:
$val = $this->read_short();
break;
case AMQPAbstractCollection::T_INT_LONG:
$val = $this->read_signed_long();
break;
case AMQPAbstractCollection::T_INT_LONG_U:
$val = $this->read_long();
break;
case AMQPAbstractCollection::T_INT_LONGLONG:
$val = $this->read_signed_longlong();
break;
case AMQPAbstractCollection::T_INT_LONGLONG_U:
$val = $this->read_longlong();
break;
case AMQPAbstractCollection::T_DECIMAL:
$e = $this->read_octet();
$n = $this->read_signed_long();
$val = new AMQPDecimal($n, $e);
break;
case AMQPAbstractCollection::T_TIMESTAMP:
$val = $this->read_timestamp();
break;
case AMQPAbstractCollection::T_BOOL:
$val = $this->read_octet();
break;
case AMQPAbstractCollection::T_STRING_SHORT:
$val = $this->read_shortstr();
break;
case AMQPAbstractCollection::T_STRING_LONG:
$val = $this->read_longstr();
break;
case AMQPAbstractCollection::T_ARRAY:
$val = $this->read_array($collectionsAsObjects);
break;
case AMQPAbstractCollection::T_TABLE:
$val = $this->read_table($collectionsAsObjects);
break;
case AMQPAbstractCollection::T_VOID:
$val = null;
break;
default:
throw new AMQPInvalidArgumentException(sprintf(
'Unsupported type "%s"',
$fieldType
));
}
return $val;
}
/**
* @return int
*/
protected function tell()
{
return $this->offset;
}
/**
* Sets the timeout (second)
*
* @param $timeout
*/
public function setTimeout($timeout)
{
$this->timeout = $timeout;
}
/**
* @return int
*/
public function getTimeout()
{
return $this->timeout;
}
}

View File

@@ -1,35 +0,0 @@
<?php
namespace PhpAmqpLib\Wire;
use PhpAmqpLib\Exception;
class AMQPTable extends AMQPAbstractCollection
{
/**
* @return int
*/
final public function getType()
{
return self::T_TABLE;
}
/**
* @param string $key
* @param mixed $val
* @param integer $type
*/
public function set($key, $val, $type = null)
{
//https://www.rabbitmq.com/resources/specs/amqp0-9-1.pdf, https://www.rabbitmq.com/resources/specs/amqp0-8.pdf
//Field names MUST start with a letter, '$' or '#' and may continue with letters, '$' or '#', digits, or underlines, to a maximum length of 128 characters
//The server SHOULD validate field names and upon receiving an invalid field name, it SHOULD signal a connection exception with reply code 503 (syntax error)
//validating length only and delegating other stuff to server, as rabbit seems to currently support numeric keys
if (!($len = strlen($key)) || ($len > 128)) {
throw new Exception\AMQPInvalidArgumentException('Table key must be non-empty string up to 128 chars in length');
}
$this->setValue($val, $type, $key);
}
}

View File

@@ -1,494 +0,0 @@
<?php
namespace PhpAmqpLib\Wire;
use PhpAmqpLib\Exception\AMQPInvalidArgumentException;
use PhpAmqpLib\Exception\AMQPOutOfBoundsException;
class AMQPWriter extends AbstractClient
{
/** @var string */
protected $out;
/** @var array */
protected $bits;
/** @var int */
protected $bitcount;
public function __construct()
{
parent::__construct();
$this->out = '';
$this->bits = array();
$this->bitcount = 0;
}
/**
* Packs integer into raw byte string in big-endian order
* Supports positive and negative ints represented as PHP int or string (except scientific notation)
*
* Floats has some precision issues and so intentionally not supported.
* Beware that floats out of PHP_INT_MAX range will be represented in scientific (exponential) notation when casted to string
*
* @param int|string $x Value to pack
* @param int $bytes Must be multiply of 2
* @return string
*/
private static function packBigEndian($x, $bytes)
{
if (($bytes <= 0) || ($bytes % 2)) {
throw new AMQPInvalidArgumentException(sprintf('Expected bytes count must be multiply of 2, %s given', $bytes));
}
$ox = $x; //purely for dbg purposes (overflow exception)
$isNeg = false;
if (is_int($x)) {
if ($x < 0) {
$isNeg = true;
$x = abs($x);
}
} elseif (is_string($x)) {
if (!is_numeric($x)) {
throw new AMQPInvalidArgumentException(sprintf('Unknown numeric string format: %s', $x));
}
$x = preg_replace('/^-/', '', $x, 1, $isNeg);
} else {
throw new AMQPInvalidArgumentException('Only integer and numeric string values are supported');
}
if ($isNeg) {
$x = bcadd($x, -1, 0);
} //in negative domain starting point is -1, not 0
$res = array();
for ($b = 0; $b < $bytes; $b += 2) {
$chnk = (int) bcmod($x, 65536);
$x = bcdiv($x, 65536, 0);
$res[] = pack('n', $isNeg ? ~$chnk : $chnk);
}
if ($x || ($isNeg && ($chnk & 0x8000))) {
throw new AMQPOutOfBoundsException(sprintf('Overflow detected while attempting to pack %s into %s bytes', $ox, $bytes));
}
return implode(array_reverse($res));
}
private function flushbits()
{
if (!empty($this->bits)) {
$this->out .= implode('', array_map('chr', $this->bits));
$this->bits = array();
$this->bitcount = 0;
}
}
/**
* Get what's been encoded so far.
*/
public function getvalue()
{
/* temporarily needed for compatibility with write_bit unit tests */
if ($this->bitcount) {
$this->flushbits();
}
return $this->out;
}
/**
* Write a plain PHP string, with no special encoding.
*/
public function write($s)
{
$this->out .= $s;
return $this;
}
/**
* Write a boolean value.
* (deprecated, use write_bits instead)
*
* @deprecated
* @param $b
* @return $this
*/
public function write_bit($b)
{
$b = (int) (bool) $b;
$shift = $this->bitcount % 8;
if ($shift == 0) {
$last = 0;
} else {
$last = array_pop($this->bits);
}
$last |= ($b << $shift);
array_push($this->bits, $last);
$this->bitcount += 1;
return $this;
}
/**
* Write multiple bits as an octet
*
* @param $bits
* @return $this
*/
public function write_bits($bits)
{
$value = 0;
foreach ($bits as $n => $bit) {
$bit = $bit ? 1 : 0;
$value |= ($bit << $n);
}
$this->out .= chr($value);
return $this;
}
/**
* Write an integer as an unsigned 8-bit value
*
* @param $n
* @return $this
* @throws \PhpAmqpLib\Exception\AMQPInvalidArgumentException
*/
public function write_octet($n)
{
if ($n < 0 || $n > 255) {
throw new AMQPInvalidArgumentException('Octet out of range: ' . $n);
}
$this->out .= chr($n);
return $this;
}
public function write_signed_octet($n)
{
if (($n < -128) || ($n > 127)) {
throw new AMQPInvalidArgumentException('Signed octet out of range: ' . $n);
}
$this->out .= pack('c', $n);
return $this;
}
/**
* Write an integer as an unsigned 16-bit value
*
* @param $n
* @return $this
* @throws \PhpAmqpLib\Exception\AMQPInvalidArgumentException
*/
public function write_short($n)
{
if ($n < 0 || $n > 65535) {
throw new AMQPInvalidArgumentException('Short out of range: ' . $n);
}
$this->out .= pack('n', $n);
return $this;
}
public function write_signed_short($n)
{
if (($n < -32768) || ($n > 32767)) {
throw new AMQPInvalidArgumentException('Signed short out of range: ' . $n);
}
$this->out .= $this->correctEndianness(pack('s', $n));
return $this;
}
/**
* Write an integer as an unsigned 32-bit value
*
* @param $n
* @return $this
*/
public function write_long($n)
{
if (($n < 0) || ($n > 4294967295)) {
throw new AMQPInvalidArgumentException('Long out of range: ' . $n);
}
//Numeric strings >PHP_INT_MAX on 32bit are casted to PHP_INT_MAX, damn PHP
if (!$this->is64bits && is_string($n)) {
$n = (float) $n;
}
$this->out .= pack('N', $n);
return $this;
}
/**
* @param $n
* @return $this
*/
private function write_signed_long($n)
{
if (($n < -2147483648) || ($n > 2147483647)) {
throw new AMQPInvalidArgumentException('Signed long out of range: ' . $n);
}
//on my 64bit debian this approach is slightly faster than splitIntoQuads()
$this->out .= $this->correctEndianness(pack('l', $n));
return $this;
}
/**
* Write an integer as an unsigned 64-bit value
*
* @param $n
* @return $this
*/
public function write_longlong($n)
{
if ($n < 0) {
throw new AMQPInvalidArgumentException('Longlong out of range: ' . $n);
}
// if PHP_INT_MAX is big enough for that
// direct $n<=PHP_INT_MAX check is unreliable on 64bit (values close to max) due to limited float precision
if (bcadd($n, -PHP_INT_MAX, 0) <= 0) {
// trick explained in http://www.php.net/manual/fr/function.pack.php#109328
if ($this->is64bits) {
list($hi, $lo) = $this->splitIntoQuads($n);
} else {
$hi = 0;
$lo = $n;
} //on 32bits hi quad is 0 a priori
$this->out .= pack('NN', $hi, $lo);
} else {
try {
$this->out .= self::packBigEndian($n, 8);
} catch (AMQPOutOfBoundsException $ex) {
throw new AMQPInvalidArgumentException('Longlong out of range: ' . $n, 0, $ex);
}
}
return $this;
}
public function write_signed_longlong($n)
{
if ((bcadd($n, PHP_INT_MAX, 0) >= -1) && (bcadd($n, -PHP_INT_MAX, 0) <= 0)) {
if ($this->is64bits) {
list($hi, $lo) = $this->splitIntoQuads($n);
} else {
$hi = $n < 0 ? -1 : 0;
$lo = $n;
} //0xffffffff for negatives
$this->out .= pack('NN', $hi, $lo);
} elseif ($this->is64bits) {
throw new AMQPInvalidArgumentException('Signed longlong out of range: ' . $n);
} else {
if (bcadd($n, '-9223372036854775807', 0) > 0) {
throw new AMQPInvalidArgumentException('Signed longlong out of range: ' . $n);
}
try {
//will catch only negative overflow, as values >9223372036854775807 are valid for 8bytes range (unsigned)
$this->out .= self::packBigEndian($n, 8);
} catch (AMQPOutOfBoundsException $ex) {
throw new AMQPInvalidArgumentException('Signed longlong out of range: ' . $n, 0, $ex);
}
}
return $this;
}
/**
* @param int $n
* @return array
*/
private function splitIntoQuads($n)
{
$n = (int) $n;
return array($n >> 32, $n & 0x00000000ffffffff);
}
/**
* Write a string up to 255 bytes long after encoding.
* Assume UTF-8 encoding
*
* @param $s
* @return $this
* @throws \PhpAmqpLib\Exception\AMQPInvalidArgumentException
*/
public function write_shortstr($s)
{
$len = mb_strlen($s, 'ASCII');
if ($len > 255) {
throw new AMQPInvalidArgumentException('String too long');
}
$this->write_octet($len);
$this->out .= $s;
return $this;
}
/**
* Write a string up to 2**32 bytes long. Assume UTF-8 encoding
*
* @param $s
* @return $this
*/
public function write_longstr($s)
{
$this->write_long(mb_strlen($s, 'ASCII'));
$this->out .= $s;
return $this;
}
/**
* Supports the writing of Array types, so that you can implement
* array methods, like Rabbitmq's HA parameters
*
* @param AMQPArray|array $a Instance of AMQPArray or PHP array WITHOUT format hints (unlike write_table())
* @return self
*/
public function write_array($a)
{
if (!($a instanceof AMQPArray)) {
$a = new AMQPArray($a);
}
$data = new AMQPWriter();
foreach ($a as $v) {
$data->write_value($v[0], $v[1]);
}
$data = $data->getvalue();
$this->write_long(mb_strlen($data, 'ASCII'));
$this->write($data);
return $this;
}
/**
* Write unix time_t value as 64 bit timestamp
*
* @param $v
* @return $this
*/
public function write_timestamp($v)
{
$this->write_longlong($v);
return $this;
}
/**
* Write PHP array, as table. Input array format: keys are strings,
* values are (type,value) tuples.
*
* @param AMQPTable|array $d Instance of AMQPTable or PHP array WITH format hints (unlike write_array())
* @return self
* @throws \PhpAmqpLib\Exception\AMQPInvalidArgumentException
*/
public function write_table($d)
{
$typeIsSym = !($d instanceof AMQPTable); //purely for back-compat purposes
$table_data = new AMQPWriter();
foreach ($d as $k => $va) {
list($ftype, $v) = $va;
$table_data->write_shortstr($k);
$table_data->write_value($typeIsSym ? AMQPAbstractCollection::getDataTypeForSymbol($ftype) : $ftype, $v);
}
$table_data = $table_data->getvalue();
$this->write_long(mb_strlen($table_data, 'ASCII'));
$this->write($table_data);
return $this;
}
/**
* for compat with method mapping used by AMQPMessage
*/
public function write_table_object($d)
{
return $this->write_table($d);
}
/**
* @param int $type One of AMQPAbstractCollection::T_* constants
* @param mixed $val
*/
private function write_value($type, $val)
{
//This will find appropriate symbol for given data type for currently selected protocol
//Also will raise an exception on unknown type
$this->write(AMQPAbstractCollection::getSymbolForDataType($type));
switch ($type) {
case AMQPAbstractCollection::T_INT_SHORTSHORT:
$this->write_signed_octet($val);
break;
case AMQPAbstractCollection::T_INT_SHORTSHORT_U:
$this->write_octet($val);
break;
case AMQPAbstractCollection::T_INT_SHORT:
$this->write_signed_short($val);
break;
case AMQPAbstractCollection::T_INT_SHORT_U:
$this->write_short($val);
break;
case AMQPAbstractCollection::T_INT_LONG:
$this->write_signed_long($val);
break;
case AMQPAbstractCollection::T_INT_LONG_U:
$this->write_long($val);
break;
case AMQPAbstractCollection::T_INT_LONGLONG:
$this->write_signed_longlong($val);
break;
case AMQPAbstractCollection::T_INT_LONGLONG_U:
$this->write_longlong($val);
break;
case AMQPAbstractCollection::T_DECIMAL:
$this->write_octet($val->e);
$this->write_signed_long($val->n);
break;
case AMQPAbstractCollection::T_TIMESTAMP:
$this->write_timestamp($val);
break;
case AMQPAbstractCollection::T_BOOL:
$this->write_octet($val ? 1 : 0);
break;
case AMQPAbstractCollection::T_STRING_SHORT:
$this->write_shortstr($val);
break;
case AMQPAbstractCollection::T_STRING_LONG:
$this->write_longstr($val);
break;
case AMQPAbstractCollection::T_ARRAY:
$this->write_array($val);
break;
case AMQPAbstractCollection::T_TABLE:
$this->write_table($val);
break;
case AMQPAbstractCollection::T_VOID:
break;
default:
throw new AMQPInvalidArgumentException(sprintf(
'Unsupported type "%s"',
$type
));
}
}
}

View File

@@ -1,36 +0,0 @@
<?php
namespace PhpAmqpLib\Wire;
class AbstractClient
{
/**
* @var bool
*/
protected $is64bits;
/**
* @var bool
*/
protected $isLittleEndian;
public function __construct()
{
$this->is64bits = PHP_INT_SIZE == 8;
$tmp = unpack('S', "\x01\x00"); // to maintain 5.3 compatibility
$this->isLittleEndian = $tmp[1] == 1;
}
/**
* Converts byte-string between native and network byte order, in both directions
*
* @param string $byteStr
* @return string
*/
protected function correctEndianness($byteStr)
{
return $this->isLittleEndian ? strrev($byteStr) : $byteStr;
}
}

View File

@@ -1,142 +0,0 @@
<?php
/* This file was autogenerated by spec/parser.php - Do not modify */
namespace PhpAmqpLib\Wire;
class Constants080
{
public static $AMQP_PROTOCOL_HEADER = "AMQP\x01\x01\x08\x00";
public static $FRAME_TYPES = array(
1 => 'FRAME-METHOD',
2 => 'FRAME-HEADER',
3 => 'FRAME-BODY',
4 => 'FRAME-OOB-METHOD',
5 => 'FRAME-OOB-HEADER',
6 => 'FRAME-OOB-BODY',
7 => 'FRAME-TRACE',
8 => 'FRAME-HEARTBEAT',
4096 => 'FRAME-MIN-SIZE',
206 => 'FRAME-END',
501 => 'FRAME-ERROR',
);
public static $CONTENT_METHODS = array(
0 => '60,40',
1 => '60,50',
2 => '60,60',
3 => '60,71',
4 => '70,50',
5 => '70,70',
6 => '80,40',
7 => '80,50',
8 => '80,60',
9 => '110,10',
10 => '120,40',
11 => '120,41',
);
public static $CLOSE_METHODS = array(
0 => '10,60',
1 => '20,40',
);
public static $GLOBAL_METHOD_NAMES = array(
'10,10' => 'Connection.start',
'10,11' => 'Connection.start_ok',
'10,20' => 'Connection.secure',
'10,21' => 'Connection.secure_ok',
'10,30' => 'Connection.tune',
'10,31' => 'Connection.tune_ok',
'10,40' => 'Connection.open',
'10,41' => 'Connection.open_ok',
'10,50' => 'Connection.redirect',
'10,60' => 'Connection.close',
'10,61' => 'Connection.close_ok',
'20,10' => 'Channel.open',
'20,11' => 'Channel.open_ok',
'20,20' => 'Channel.flow',
'20,21' => 'Channel.flow_ok',
'20,30' => 'Channel.alert',
'20,40' => 'Channel.close',
'20,41' => 'Channel.close_ok',
'30,10' => 'Access.request',
'30,11' => 'Access.request_ok',
'40,10' => 'Exchange.declare',
'40,11' => 'Exchange.declare_ok',
'40,20' => 'Exchange.delete',
'40,21' => 'Exchange.delete_ok',
'50,10' => 'Queue.declare',
'50,11' => 'Queue.declare_ok',
'50,20' => 'Queue.bind',
'50,21' => 'Queue.bind_ok',
'50,30' => 'Queue.purge',
'50,31' => 'Queue.purge_ok',
'50,40' => 'Queue.delete',
'50,41' => 'Queue.delete_ok',
'50,50' => 'Queue.unbind',
'50,51' => 'Queue.unbind_ok',
'60,10' => 'Basic.qos',
'60,11' => 'Basic.qos_ok',
'60,20' => 'Basic.consume',
'60,21' => 'Basic.consume_ok',
'60,30' => 'Basic.cancel',
'60,31' => 'Basic.cancel_ok',
'60,40' => 'Basic.publish',
'60,50' => 'Basic.return',
'60,60' => 'Basic.deliver',
'60,70' => 'Basic.get',
'60,71' => 'Basic.get_ok',
'60,72' => 'Basic.get_empty',
'60,80' => 'Basic.ack',
'60,90' => 'Basic.reject',
'60,100' => 'Basic.recover_async',
'60,110' => 'Basic.recover',
'60,111' => 'Basic.recover_ok',
'70,10' => 'File.qos',
'70,11' => 'File.qos_ok',
'70,20' => 'File.consume',
'70,21' => 'File.consume_ok',
'70,30' => 'File.cancel',
'70,31' => 'File.cancel_ok',
'70,40' => 'File.open',
'70,41' => 'File.open_ok',
'70,50' => 'File.stage',
'70,60' => 'File.publish',
'70,70' => 'File.return',
'70,80' => 'File.deliver',
'70,90' => 'File.ack',
'70,100' => 'File.reject',
'80,10' => 'Stream.qos',
'80,11' => 'Stream.qos_ok',
'80,20' => 'Stream.consume',
'80,21' => 'Stream.consume_ok',
'80,30' => 'Stream.cancel',
'80,31' => 'Stream.cancel_ok',
'80,40' => 'Stream.publish',
'80,50' => 'Stream.return',
'80,60' => 'Stream.deliver',
'90,10' => 'Tx.select',
'90,11' => 'Tx.select_ok',
'90,20' => 'Tx.commit',
'90,21' => 'Tx.commit_ok',
'90,30' => 'Tx.rollback',
'90,31' => 'Tx.rollback_ok',
'100,10' => 'Dtx.select',
'100,11' => 'Dtx.select_ok',
'100,20' => 'Dtx.start',
'100,21' => 'Dtx.start_ok',
'110,10' => 'Tunnel.request',
'120,10' => 'Test.integer',
'120,11' => 'Test.integer_ok',
'120,20' => 'Test.string',
'120,21' => 'Test.string_ok',
'120,30' => 'Test.table',
'120,31' => 'Test.table_ok',
'120,40' => 'Test.content',
'120,41' => 'Test.content_ok',
);
}

View File

@@ -1,101 +0,0 @@
<?php
/* This file was autogenerated by spec/parser.php - Do not modify */
namespace PhpAmqpLib\Wire;
class Constants091
{
public static $AMQP_PROTOCOL_HEADER = "AMQP\x00\x00\x09\x01";
public static $FRAME_TYPES = array(
1 => 'FRAME-METHOD',
2 => 'FRAME-HEADER',
3 => 'FRAME-BODY',
8 => 'FRAME-HEARTBEAT',
4096 => 'FRAME-MIN-SIZE',
206 => 'FRAME-END',
501 => 'FRAME-ERROR',
);
public static $CONTENT_METHODS = array(
0 => '60,40',
1 => '60,50',
2 => '60,60',
3 => '60,71',
);
public static $CLOSE_METHODS = array(
0 => '10,50',
1 => '20,40',
);
public static $GLOBAL_METHOD_NAMES = array(
'10,10' => 'Connection.start',
'10,11' => 'Connection.start_ok',
'10,20' => 'Connection.secure',
'10,21' => 'Connection.secure_ok',
'10,30' => 'Connection.tune',
'10,31' => 'Connection.tune_ok',
'10,40' => 'Connection.open',
'10,41' => 'Connection.open_ok',
'10,50' => 'Connection.close',
'10,51' => 'Connection.close_ok',
'10,60' => 'Connection.blocked',
'10,61' => 'Connection.unblocked',
'20,10' => 'Channel.open',
'20,11' => 'Channel.open_ok',
'20,20' => 'Channel.flow',
'20,21' => 'Channel.flow_ok',
'20,40' => 'Channel.close',
'20,41' => 'Channel.close_ok',
'30,10' => 'Access.request',
'30,11' => 'Access.request_ok',
'40,10' => 'Exchange.declare',
'40,11' => 'Exchange.declare_ok',
'40,20' => 'Exchange.delete',
'40,21' => 'Exchange.delete_ok',
'40,30' => 'Exchange.bind',
'40,31' => 'Exchange.bind_ok',
'40,40' => 'Exchange.unbind',
'40,51' => 'Exchange.unbind_ok',
'50,10' => 'Queue.declare',
'50,11' => 'Queue.declare_ok',
'50,20' => 'Queue.bind',
'50,21' => 'Queue.bind_ok',
'50,30' => 'Queue.purge',
'50,31' => 'Queue.purge_ok',
'50,40' => 'Queue.delete',
'50,41' => 'Queue.delete_ok',
'50,50' => 'Queue.unbind',
'50,51' => 'Queue.unbind_ok',
'60,10' => 'Basic.qos',
'60,11' => 'Basic.qos_ok',
'60,20' => 'Basic.consume',
'60,21' => 'Basic.consume_ok',
'60,30' => 'Basic.cancel',
'60,31' => 'Basic.cancel_ok',
'60,40' => 'Basic.publish',
'60,50' => 'Basic.return',
'60,60' => 'Basic.deliver',
'60,70' => 'Basic.get',
'60,71' => 'Basic.get_ok',
'60,72' => 'Basic.get_empty',
'60,80' => 'Basic.ack',
'60,90' => 'Basic.reject',
'60,100' => 'Basic.recover_async',
'60,110' => 'Basic.recover',
'60,111' => 'Basic.recover_ok',
'60,120' => 'Basic.nack',
'90,10' => 'Tx.select',
'90,11' => 'Tx.select_ok',
'90,20' => 'Tx.commit',
'90,21' => 'Tx.commit_ok',
'90,30' => 'Tx.rollback',
'90,31' => 'Tx.rollback_ok',
'85,10' => 'Confirm.select',
'85,11' => 'Confirm.select_ok',
);
}

View File

@@ -1,209 +0,0 @@
<?php
namespace PhpAmqpLib\Wire;
use PhpAmqpLib\Channel\AMQPChannel;
/**
* Abstract base class for AMQP content. Subclasses should override
* the PROPERTIES attribute.
*/
abstract class GenericContent
{
/** @var AMQPChannel[] */
public $delivery_info = array();
/** @var array Final property definitions */
protected $prop_types;
/** @var array Properties content */
private $properties = array();
/** @var string Compiled properties */
private $serialized_properties;
/**
* @var array
*/
protected static $PROPERTIES = array(
'dummy' => 'shortstr'
);
/**
* @param $props
* @param null $prop_types
*/
public function __construct($props, $prop_types = null)
{
if ($prop_types) {
$this->prop_types = $prop_types;
} else {
$this->prop_types = self::$PROPERTIES;
}
if ($props) {
$this->properties = array_intersect_key($props, $this->prop_types);
}
}
/**
* Check whether a property exists in the 'properties' dictionary
* or if present - in the 'delivery_info' dictionary.
*
* @param string $name
* @return bool
*/
public function has($name)
{
return isset($this->properties[$name]) || isset($this->delivery_info[$name]);
}
/**
* Look for additional properties in the 'properties' dictionary,
* and if present - the 'delivery_info' dictionary.
*
* @param string $name
* @throws \OutOfBoundsException
* @return mixed|AMQPChannel
*/
public function get($name)
{
if (isset($this->properties[$name])) {
return $this->properties[$name];
}
if (isset($this->delivery_info[$name])) {
return $this->delivery_info[$name];
}
throw new \OutOfBoundsException(sprintf(
'No "%s" property',
$name
));
}
/**
* Returns the properties content
*
* @return array
*/
public function get_properties()
{
return $this->properties;
}
/**
* Sets a property value
*
* @param string $name The property name (one of the property definition)
* @param mixed $value The property value
* @throws \OutOfBoundsException
*/
public function set($name, $value)
{
if (!array_key_exists($name, $this->prop_types)) {
throw new \OutOfBoundsException(sprintf(
'No "%s" property',
$name
));
}
$this->properties[$name] = $value;
}
/**
* Given the raw bytes containing the property-flags and
* property-list from a content-frame-header, parse and insert
* into a dictionary stored in this object as an attribute named
* 'properties'.
*
* @param AMQPReader $r
* NOTE: do not mutate $reader
*/
public function load_properties($r)
{
// Read 16-bit shorts until we get one with a low bit set to zero
$flags = array();
while (true) {
$flag_bits = $r->read_short();
$flags[] = $flag_bits;
if (($flag_bits & 1) == 0) {
break;
}
}
$shift = 0;
$d = array();
foreach ($this->prop_types as $key => $proptype) {
if ($shift == 0) {
if (!$flags) {
break;
}
$flag_bits = array_shift($flags);
$shift = 15;
}
if ($flag_bits & (1 << $shift)) {
$d[$key] = $r->{'read_' . $proptype}();
}
$shift -= 1;
}
$this->properties = $d;
}
/**
* Serializes the 'properties' attribute (a dictionary) into the
* raw bytes making up a set of property flags and a property
* list, suitable for putting into a content frame header.
*
* @return string
* @todo Inject the AMQPWriter to make the method easier to test
*/
public function serialize_properties()
{
if (!empty($this->serialized_properties)) {
return $this->serialized_properties;
}
$shift = 15;
$flag_bits = 0;
$flags = array();
$raw_bytes = new AMQPWriter();
foreach ($this->prop_types as $key => $prototype) {
$val = isset($this->properties[$key]) ? $this->properties[$key] : null;
// Very important: PHP type eval is weak, use the === to test the
// value content. Zero or false value should not be removed
if ($val === null) {
$shift -= 1;
continue;
}
if ($shift === 0) {
$flags[] = $flag_bits;
$flag_bits = 0;
$shift = 15;
}
$flag_bits |= (1 << $shift);
if ($prototype != 'bit') {
$raw_bytes->{'write_' . $prototype}($val);
}
$shift -= 1;
}
$flags[] = $flag_bits;
$result = new AMQPWriter();
foreach ($flags as $flag_bits) {
$result->write_short($flag_bits);
}
$result->write($raw_bytes->getvalue());
$this->serialized_properties = $result->getvalue();
return $this->serialized_properties;
}
}

View File

@@ -1,44 +0,0 @@
<?php
namespace PhpAmqpLib\Wire\IO;
abstract class AbstractIO
{
/**
* @param $n
* @return mixed
*/
abstract public function read($n);
/**
* @param $data
* @return mixed
*/
abstract public function write($data);
/**
* @return mixed
*/
abstract public function close();
/**
* @param $sec
* @param $usec
* @return mixed
*/
abstract public function select($sec, $usec);
/**
* @return mixed
*/
abstract public function connect();
/**
* @return mixed
*/
abstract public function reconnect();
/**
* @return mixed
*/
abstract public function getSocket();
}

View File

@@ -1,195 +0,0 @@
<?php
namespace PhpAmqpLib\Wire\IO;
use PhpAmqpLib\Exception\AMQPIOException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
class SocketIO extends AbstractIO
{
/** @var string */
protected $host;
/** @var int */
protected $port;
/** @var int */
protected $timeout;
/** @var resource */
private $sock;
/** @var bool */
private $keepalive;
/**
* @param string $host
* @param int $port
* @param int $timeout
* @param bool $keepalive
*/
public function __construct($host, $port, $timeout, $keepalive = false)
{
$this->host = $host;
$this->port = $port;
$this->timeout = $timeout;
$this->keepalive = $keepalive;
}
/**
* Sets up the socket connection
*
* @throws \Exception
*/
public function connect()
{
$this->sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($this->sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $this->timeout, 'usec' => 0));
socket_set_option($this->sock, SOL_SOCKET, SO_SNDTIMEO, array('sec' => $this->timeout, 'usec' => 0));
if (!socket_connect($this->sock, $this->host, $this->port)) {
$errno = socket_last_error($this->sock);
$errstr = socket_strerror($errno);
throw new AMQPIOException(sprintf(
'Error Connecting to server (%s): %s',
$errno,
$errstr
), $errno);
}
socket_set_block($this->sock);
socket_set_option($this->sock, SOL_TCP, TCP_NODELAY, 1);
if ($this->keepalive) {
$this->enable_keepalive();
}
}
/**
* @return resource
*/
public function getSocket()
{
return $this->sock;
}
/**
* Reconnects the socket
*/
public function reconnect()
{
$this->close();
$this->connect();
}
/**
* @param $n
* @return mixed|string
* @throws \PhpAmqpLib\Exception\AMQPIOException
* @throws \PhpAmqpLib\Exception\AMQPRuntimeException
*/
public function read($n)
{
$res = '';
$read = 0;
$buf = socket_read($this->sock, $n);
while ($read < $n && $buf !== '' && $buf !== false) {
// Null sockets are invalid, throw exception
if (is_null($this->sock)) {
throw new AMQPRuntimeException(sprintf(
'Socket was null! Last SocketError was: %s',
socket_strerror(socket_last_error())
));
}
$read += mb_strlen($buf, 'ASCII');
$res .= $buf;
$buf = socket_read($this->sock, $n - $read);
}
if (mb_strlen($res, 'ASCII') != $n) {
throw new AMQPIOException(sprintf(
'Error reading data. Received %s instead of expected %s bytes',
mb_strlen($res, 'ASCII'),
$n
));
}
return $res;
}
/**
* @param $data
* @return mixed|void
* @throws \PhpAmqpLib\Exception\AMQPIOException
* @throws \PhpAmqpLib\Exception\AMQPRuntimeException
*/
public function write($data)
{
$len = mb_strlen($data, 'ASCII');
while (true) {
// Null sockets are invalid, throw exception
if (is_null($this->sock)) {
throw new AMQPRuntimeException(sprintf(
'Socket was null! Last SocketError was: %s',
socket_strerror(socket_last_error())
));
}
$sent = socket_write($this->sock, $data, $len);
if ($sent === false) {
throw new AMQPIOException(sprintf(
'Error sending data. Last SocketError: %s',
socket_strerror(socket_last_error())
));
}
// Check if the entire message has been sent
if ($sent < $len) {
// If not sent the entire message.
// Get the part of the message that has not yet been sent as message
$data = mb_substr($data, $sent, mb_strlen($data, 'ASCII') - $sent, 'ASCII');
// Get the length of the not sent part
$len -= $sent;
} else {
break;
}
}
}
public function close()
{
if (is_resource($this->sock)) {
socket_close($this->sock);
}
$this->sock = null;
}
/**
* @param $sec
* @param $usec
* @return int|mixed
*/
public function select($sec, $usec)
{
$read = array($this->sock);
$write = null;
$except = null;
return socket_select($read, $write, $except, $sec, $usec);
}
/**
* @throws \PhpAmqpLib\Exception\AMQPIOException
*/
protected function enable_keepalive()
{
if (!defined('SOL_SOCKET') || !defined('SO_KEEPALIVE')) {
throw new AMQPIOException('Can not enable keepalive: SOL_SOCKET or SO_KEEPALIVE is not defined');
}
socket_set_option($this->sock, SOL_SOCKET, SO_KEEPALIVE, 1);
}
}

View File

@@ -1,309 +0,0 @@
<?php
namespace PhpAmqpLib\Wire\IO;
use PhpAmqpLib\Exception\AMQPIOException;
use PhpAmqpLib\Exception\AMQPRuntimeException;
use PhpAmqpLib\Exception\AMQPTimeoutException;
use PhpAmqpLib\Helper\MiscHelper;
use PhpAmqpLib\Wire\AMQPWriter;
class StreamIO extends AbstractIO
{
/** @var string */
protected $host;
/** @var int */
protected $port;
/** @var int */
protected $connection_timeout;
/** @var int */
protected $read_write_timeout;
/** @var resource */
protected $context;
/** @var bool */
protected $keepalive;
/** @var int */
protected $heartbeat;
/** @var float */
protected $last_read;
/** @var float */
protected $last_write;
/** @var resource */
private $sock;
/** @var bool */
private $canDispatchPcntlSignal;
/**
* @param string $host
* @param int $port
* @param int $connection_timeout
* @param int $read_write_timeout
* @param null $context
* @param bool $keepalive
* @param int $heartbeat
*/
public function __construct(
$host,
$port,
$connection_timeout,
$read_write_timeout,
$context = null,
$keepalive = false,
$heartbeat = 0
) {
$this->host = $host;
$this->port = $port;
$this->connection_timeout = $connection_timeout;
$this->read_write_timeout = $read_write_timeout;
$this->context = $context;
$this->keepalive = $keepalive;
$this->heartbeat = $heartbeat;
$this->canDispatchPcntlSignal = extension_loaded('pcntl') && function_exists('pcntl_signal_dispatch')
&& (defined('AMQP_WITHOUT_SIGNALS') ? !AMQP_WITHOUT_SIGNALS : true);
}
/**
* Sets up the stream connection
*
* @throws \PhpAmqpLib\Exception\AMQPRuntimeException
* @throws \Exception
*/
public function connect()
{
$errstr = $errno = null;
if ($this->context) {
$remote = sprintf('ssl://%s:%s', $this->host, $this->port);
$this->sock = @stream_socket_client(
$remote,
$errno,
$errstr,
$this->connection_timeout,
STREAM_CLIENT_CONNECT,
$this->context
);
} else {
$remote = sprintf('tcp://%s:%s', $this->host, $this->port);
$this->sock = @stream_socket_client(
$remote,
$errno,
$errstr,
$this->connection_timeout,
STREAM_CLIENT_CONNECT
);
}
if (!$this->sock) {
throw new AMQPRuntimeException(sprintf(
'Error Connecting to server (%s): %s',
$errno,
$errstr
), $errno);
}
list($sec, $uSec) = MiscHelper::splitSecondsMicroseconds($this->read_write_timeout);
if (!stream_set_timeout($this->sock, $sec, $uSec)) {
throw new AMQPIOException('Timeout could not be set');
}
stream_set_blocking($this->sock, 1);
if ($this->keepalive) {
$this->enable_keepalive();
}
}
/**
* Reconnects the socket
*/
public function reconnect()
{
$this->close();
$this->connect();
}
/**
* @param $n
* @throws \PhpAmqpLib\Exception\AMQPIOException
* @return mixed|string
*/
public function read($n)
{
$res = '';
$read = 0;
while ($read < $n && !feof($this->sock) && (false !== ($buf = fread($this->sock, $n - $read)))) {
$this->check_heartbeat();
if ($buf === '') {
if ($this->canDispatchPcntlSignal) {
pcntl_signal_dispatch();
}
continue;
}
$read += mb_strlen($buf, 'ASCII');
$res .= $buf;
$this->last_read = microtime(true);
}
if (mb_strlen($res, 'ASCII') != $n) {
throw new AMQPIOException(sprintf(
'Error reading data. Received %s instead of expected %s bytes',
mb_strlen($res, 'ASCII'),
$n
));
}
return $res;
}
/**
* @param $data
* @return mixed|void
* @throws \PhpAmqpLib\Exception\AMQPRuntimeException
* @throws \PhpAmqpLib\Exception\AMQPTimeoutException
*/
public function write($data)
{
$len = mb_strlen($data, 'ASCII');
while (true) {
if (is_null($this->sock)) {
throw new AMQPRuntimeException('Broken pipe or closed connection');
}
if (false === ($written = @fwrite($this->sock, $data))) {
throw new AMQPRuntimeException('Error sending data');
}
if ($written === 0) {
throw new AMQPRuntimeException('Broken pipe or closed connection');
}
if ($this->timed_out()) {
throw new AMQPTimeoutException('Error sending data. Socket connection timed out');
}
$len = $len - $written;
if ($len > 0) {
$data = mb_substr($data, 0 - $len, 0 - $len, 'ASCII');
} else {
$this->last_write = microtime(true);
break;
}
}
}
/**
* Heartbeat logic: check connection health here
*/
protected function check_heartbeat()
{
// ignore unless heartbeat interval is set
if ($this->heartbeat !== 0 && $this->last_read && $this->last_write) {
$t = microtime(true);
$t_read = round($t - $this->last_read);
$t_write = round($t - $this->last_write);
// server has gone away
if (($this->heartbeat * 2) < $t_read) {
$this->reconnect();
}
// time for client to send a heartbeat
if (($this->heartbeat / 2) < $t_write) {
$this->write_heartbeat();
}
}
}
/**
* Sends a heartbeat message
*/
protected function write_heartbeat()
{
$pkt = new AMQPWriter();
$pkt->write_octet(8);
$pkt->write_short(0);
$pkt->write_long(0);
$pkt->write_octet(0xCE);
$val = $pkt->getvalue();
$this->write($pkt->getvalue());
}
public function close()
{
if (is_resource($this->sock)) {
fclose($this->sock);
}
$this->sock = null;
}
/**
* @return resource
*/
public function get_socket()
{
return $this->sock;
}
/**
* @return resource
*/
public function getSocket()
{
return $this->get_socket();
}
/**
* @param $sec
* @param $usec
* @return int|mixed
*/
public function select($sec, $usec)
{
$read = array($this->sock);
$write = null;
$except = null;
return stream_select($read, $write, $except, $sec, $usec);
}
/**
* @return mixed
*/
protected function timed_out()
{
// get status of socket to determine whether or not it has timed out
$info = stream_get_meta_data($this->sock);
return $info['timed_out'];
}
/**
* @throws \PhpAmqpLib\Exception\AMQPIOException
*/
protected function enable_keepalive()
{
if (!function_exists('socket_import_stream')) {
throw new AMQPIOException('Can not enable keepalive: function socket_import_stream does not exist');
}
if (!defined('SOL_SOCKET') || !defined('SO_KEEPALIVE')) {
throw new AMQPIOException('Can not enable keepalive: SOL_SOCKET or SO_KEEPALIVE is not defined');
}
$socket = socket_import_stream($this->sock);
socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1);
}
}

View File

@@ -1,64 +0,0 @@
<?php
// @codingStandardsIgnoreFile
// @codeCoverageIgnoreStart
// this is an autogenerated file - do not edit
spl_autoload_register(
function($class) {
static $classes = null;
if ($classes === null) {
$classes = array(
'phpamqplib\\channel\\abstractchannel' => '/Channel/AbstractChannel.php',
'phpamqplib\\channel\\amqpchannel' => '/Channel/AMQPChannel.php',
'phpamqplib\\connection\\abstractconnection' => '/Connection/AbstractConnection.php',
'phpamqplib\\connection\\amqpconnection' => '/Connection/AMQPConnection.php',
'phpamqplib\\connection\\amqplazyconnection' => '/Connection/AMQPLazyConnection.php',
'phpamqplib\\connection\\amqpsocketconnection' => '/Connection/AMQPSocketConnection.php',
'phpamqplib\\connection\\amqpsslconnection' => '/Connection/AMQPSSLConnection.php',
'phpamqplib\\connection\\amqpstreamconnection' => '/Connection/AMQPStreamConnection.php',
'phpamqplib\\exception\\amqpbasiccancelexception' => '/Exception/AMQPBasicCancelException.php',
'phpamqplib\\exception\\amqpchannelexception' => '/Exception/AMQPChannelException.php',
'phpamqplib\\exception\\amqpconnectionexception' => '/Exception/AMQPConnectionException.php',
'phpamqplib\\exception\\amqpexception' => '/Exception/AMQPException.php',
'phpamqplib\\exception\\amqpexceptioninterface' => '/Exception/AMQPExceptionInterface.php',
'phpamqplib\\exception\\amqpinvalidargumentexception' => '/Exception/AMQPInvalidArgumentException.php',
'phpamqplib\\exception\\amqpioexception' => '/Exception/AMQPIOException.php',
'phpamqplib\\exception\\amqplogicexception' => '/Exception/AMQPLogicException.php',
'phpamqplib\\exception\\amqpoutofboundsexception' => '/Exception/AMQPOutOfBoundsException.php',
'phpamqplib\\exception\\amqpoutofrangeexception' => '/Exception/AMQPOutOfRangeException.php',
'phpamqplib\\exception\\amqpprotocolchannelexception' => '/Exception/AMQPProtocolChannelException.php',
'phpamqplib\\exception\\amqpprotocolconnectionexception' => '/Exception/AMQPProtocolConnectionException.php',
'phpamqplib\\exception\\amqpprotocolexception' => '/Exception/AMQPProtocolException.php',
'phpamqplib\\exception\\amqpruntimeexception' => '/Exception/AMQPRuntimeException.php',
'phpamqplib\\exception\\amqptimeoutexception' => '/Exception/AMQPTimeoutException.php',
'phpamqplib\\helper\\mischelper' => '/Helper/MiscHelper.php',
'phpamqplib\\helper\\protocol\\methodmap080' => '/Helper/Protocol/MethodMap080.php',
'phpamqplib\\helper\\protocol\\methodmap091' => '/Helper/Protocol/MethodMap091.php',
'phpamqplib\\helper\\protocol\\protocol080' => '/Helper/Protocol/Protocol080.php',
'phpamqplib\\helper\\protocol\\protocol091' => '/Helper/Protocol/Protocol091.php',
'phpamqplib\\helper\\protocol\\wait080' => '/Helper/Protocol/Wait080.php',
'phpamqplib\\helper\\protocol\\wait091' => '/Helper/Protocol/Wait091.php',
'phpamqplib\\message\\amqpmessage' => '/Message/AMQPMessage.php',
'phpamqplib\\wire\\abstractclient' => '/Wire/AbstractClient.php',
'phpamqplib\\wire\\amqpabstractcollection' => '/Wire/AMQPAbstractCollection.php',
'phpamqplib\\wire\\amqparray' => '/Wire/AMQPArray.php',
'phpamqplib\\wire\\amqpdecimal' => '/Wire/AMQPDecimal.php',
'phpamqplib\\wire\\amqpreader' => '/Wire/AMQPReader.php',
'phpamqplib\\wire\\amqptable' => '/Wire/AMQPTable.php',
'phpamqplib\\wire\\amqpwriter' => '/Wire/AMQPWriter.php',
'phpamqplib\\wire\\constants080' => '/Wire/Constants080.php',
'phpamqplib\\wire\\constants091' => '/Wire/Constants091.php',
'phpamqplib\\wire\\genericcontent' => '/Wire/GenericContent.php',
'phpamqplib\\wire\\io\\abstractio' => '/Wire/IO/AbstractIO.php',
'phpamqplib\\wire\\io\\socketio' => '/Wire/IO/SocketIO.php',
'phpamqplib\\wire\\io\\streamio' => '/Wire/IO/StreamIO.php'
);
}
$cn = strtolower($class);
if (isset($classes[$cn])) {
require __DIR__ . $classes[$cn];
}
},
true,
false
);
// @codeCoverageIgnoreEnd

View File

@@ -1,383 +0,0 @@
<?php
/**
* Color.php
*
* PHP version 5
*
* Copyright (c) 2007 Stefan Walk
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* @category Console
* @package Console_Color2
* @author Stefan Walk <et@php.net>
* @license http://www.opensource.org/licenses/mit-license.php MIT License
* @link http://pear.php.net/package/Console_Color2
*/
/**
* A simple class to use ANSI Colorcodes.
*
* Of all the functions, you probably only want to use convert() and escape().
* They are easier to use. However, if you want to access colorcodes more
* directly, look into the other functions.
*
* @category Console
* @package Console_Color
* @author Stefan Walk <et@php.net>
* @license http://www.opensource.org/licenses/mit-license.php MIT License
* @link http://pear.php.net/package/Console_Color
*/
class Console_Color2
{
protected $color_codes;
public function __construct()
{
$this->setColorCodes(
array(
'color' => array(
'black' => 30,
'red' => 31,
'green' => 32,
'brown' => 33,
'blue' => 34,
'purple' => 35,
'cyan' => 36,
'grey' => 37,
'yellow' => 33,
),
'style' => array(
'normal' => 0,
'bold' => 1,
'light' => 1,
'underscore' => 4,
'underline' => 4,
'blink' => 5,
'inverse' => 6,
'hidden' => 8,
'concealed' => 8,
),
'background' => array(
'black' => 40,
'red' => 41,
'green' => 42,
'brown' => 43,
'yellow' => 43,
'blue' => 44,
'purple' => 45,
'cyan' => 46,
'grey' => 47,
),
)
);
}//end __construct()
public function setColorCodes($color_codes)
{
$this->color_codes = $color_codes;
}//end setColorCodes()
public function getColorCodes()
{
return $this->color_codes;
}//end getColorCodes()
/**
* Returns an ANSI-Controlcode
*
* Takes 1 to 3 Arguments: either 1 to 3 strings containing the name of the
* FG Color, style and BG color, or one array with the indices color, style
* or background.
*
* @param mixed $color Optional.
* Either a string with the name of the foreground
* color, or an array with the indices 'color',
* 'style', 'background' and corresponding names as
* values.
* @param string $style Optional name of the style
* @param string $background Optional name of the background color
*
* @return string
*/
public function color($color=null, $style=null, $background=null)
{
$colors = $this->getColorCodes();
if (is_array($color)) {
$style = isset($color['style']) ? $color['style'] : null;
$background = isset($color['background']) ? $color['background'] : null;
$color = isset($color['color']) ? $color['color'] : null;
}
if ($color == 'reset') {
return "\033[0m";
}
$code = array();
if (isset($style)) {
$code[] = $colors['style'][$style];
}
if (isset($color)) {
$code[] = $colors['color'][$color];
}
if (isset($background)) {
$code[] = $colors['background'][$background];
}
if (empty($code)) {
$code[] = 0;
}
$code = implode(';', $code);
return "\033[{$code}m";
}//end color()
// }}}
/**
* Returns a FG color controlcode
*
* @param string $name Name of controlcode
*
* @return string
*/
public function fgcolor($name)
{
$colors = $this->getColorCodes();
return "\033[".$colors['color'][$name].'m';
}//end fgcolor()
/**
* Returns a style controlcode
*
* @param string $name Name of controlcode
*
* @return string
*/
function bgcolor($name)
{
$colors = $this->getColorCodes();
return "\033[".$colors['background'][$name].'m';
}//end bgcolor()
/**
* Converts colorcodes in the format %y (for yellow) into ansi-control
* codes. The conversion table is: ('bold' meaning 'light' on some
* terminals). It's almost the same conversion table irssi uses.
* <pre>
* text text background
* ------------------------------------------------
* %k %K %0 black dark grey black
* %r %R %1 red bold red red
* %g %G %2 green bold green green
* %y %Y %3 yellow bold yellow yellow
* %b %B %4 blue bold blue blue
* %m %M %5 magenta bold magenta magenta
* %p %P magenta (think: purple)
* %c %C %6 cyan bold cyan cyan
* %w %W %7 white bold white white
*
* %F Blinking, Flashing
* %U Underline
* %8 Reverse
* %_,%9 Bold
*
* %n Resets the color
* %% A single %
* </pre>
* First param is the string to convert, second is an optional flag if
* colors should be used. It defaults to true, if set to false, the
* colorcodes will just be removed (And %% will be transformed into %)
*
* @param string $string String to convert
* @param boolean $colored Should the string be colored?
*
* @return string
*/
public function convert($string, $colored=true)
{
static $conversions = array(
// static so the array doesn't get built
// everytime
// %y - yellow, and so on... {{{
'%y' => array(
'color' => 'yellow',
'style' => 'normal',
),
'%g' => array(
'color' => 'green',
'style' => 'normal',
),
'%b' => array(
'color' => 'blue',
'style' => 'normal',
),
'%r' => array(
'color' => 'red',
'style' => 'normal',
),
'%p' => array(
'color' => 'purple',
'style' => 'normal',
),
'%m' => array(
'color' => 'purple',
'style' => 'normal',
),
'%c' => array(
'color' => 'cyan',
'style' => 'normal',
),
'%w' => array(
'color' => 'grey',
'style' => 'normal',
),
'%k' => array(
'color' => 'black',
'style' => 'normal',
),
'%n' => array('color' => 'reset' ),
'%Y' => array(
'color' => 'yellow',
'style' => 'light',
),
'%G' => array(
'color' => 'green',
'style' => 'light',
),
'%B' => array(
'color' => 'blue',
'style' => 'light',
),
'%R' => array(
'color' => 'red',
'style' => 'light',
),
'%P' => array(
'color' => 'purple',
'style' => 'light',
),
'%M' => array(
'color' => 'purple',
'style' => 'light',
),
'%C' => array(
'color' => 'cyan',
'style' => 'light',
),
'%W' => array(
'color' => 'grey',
'style' => 'light',
),
'%K' => array(
'color' => 'black',
'style' => 'light',
),
'%N' => array(
'color' => 'reset',
'style' => 'light',
),
'%3' => array('background' => 'yellow'),
'%2' => array('background' => 'green' ),
'%4' => array('background' => 'blue' ),
'%1' => array('background' => 'red' ),
'%5' => array('background' => 'purple'),
'%6' => array('background' => 'cyan' ),
'%7' => array('background' => 'grey' ),
'%0' => array('background' => 'black' ),
// Don't use this, I can't stand flashing text
'%F' => array('style' => 'blink'),
'%U' => array('style' => 'underline'),
'%8' => array('style' => 'inverse'),
'%9' => array('style' => 'bold'),
'%_' => array('style' => 'bold'),
// }}}
);
if ($colored) {
$string = str_replace('%%', '% ', $string);
foreach ($conversions as $key => $value) {
$string = str_replace(
$key,
$this->color($value),
$string
);
}
$string = str_replace('% ', '%', $string);
}
else {
$string = preg_replace('/%((%)|.)/', '$2', $string);
}
return $string;
}//end convert()
/**
* Escapes % so they don't get interpreted as color codes
*
* @param string $string String to escape
*
* @return string
*/
public function escape($string)
{
return str_replace('%', '%%', $string);
}//end escape()
/**
* Strips ANSI color codes from a string
*
* @param string $string String to strip
*
* @acess public
* @return string
*/
public function strip($string)
{
return preg_replace('/\033\[[\d;]+m/', '', $string);
}//end strip()
}//end class

View File

@@ -1,965 +0,0 @@
<?php
/*
* Utility for printing tables from commandline scripts.
*
* PHP versions 4 and 5
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* o The names of the authors may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @category Console
* @package Console_Table
* @author Richard Heyes <richard@phpguru.org>
* @author Jan Schneider <jan@horde.org>
* @copyright 2002-2005 Richard Heyes
* @copyright 2006-2008 Jan Schneider
* @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
* @version CVS: $Id$
* @link http://pear.php.net/package/Console_Table
*/
define('CONSOLE_TABLE_HORIZONTAL_RULE', 1);
define('CONSOLE_TABLE_ALIGN_LEFT', -1);
define('CONSOLE_TABLE_ALIGN_CENTER', 0);
define('CONSOLE_TABLE_ALIGN_RIGHT', 1);
define('CONSOLE_TABLE_BORDER_ASCII', -1);
/*
* The main class.
*
* @category Console
* @package Console_Table
* @author Jan Schneider <jan@horde.org>
* @license http://www.debian.org/misc/bsd.license BSD License (3 Clause)
* @link http://pear.php.net/package/Console_Table
*/
class Console_Table
{
/*
* The table headers.
*
* @var array
*/
var $_headers = array();
/*
* The data of the table.
*
* @var array
*/
var $_data = array();
/*
* The maximum number of columns in a row.
*
* @var integer
*/
var $_max_cols = 0;
/*
* The maximum number of rows in the table.
*
* @var integer
*/
var $_max_rows = 0;
/*
* Lengths of the columns, calculated when rows are added to the table.
*
* @var array
*/
var $_cell_lengths = array();
/*
* Heights of the rows.
*
* @var array
*/
var $_row_heights = array();
/*
* How many spaces to use to pad the table.
*
* @var integer
*/
var $_padding = 1;
/*
* Column filters.
*
* @var array
*/
var $_filters = array();
/*
* Columns to calculate totals for.
*
* @var array
*/
var $_calculateTotals;
/*
* Alignment of the columns.
*
* @var array
*/
var $_col_align = array();
/*
* Default alignment of columns.
*
* @var integer
*/
var $_defaultAlign;
/*
* Character set of the data.
*
* @var string
*/
var $_charset = 'utf-8';
/*
* Border character.
*
* @var string
*/
var $_border = CONSOLE_TABLE_BORDER_ASCII;
/*
* Whether the data has ANSI colors.
*
* @var boolean
*/
var $_ansiColor = false;
/*
* Constructor.
*
* @param integer $align Default alignment. One of
* CONSOLE_TABLE_ALIGN_LEFT,
* CONSOLE_TABLE_ALIGN_CENTER or
* CONSOLE_TABLE_ALIGN_RIGHT.
* @param string $border The character used for table borders or
* CONSOLE_TABLE_BORDER_ASCII.
* @param integer $padding How many spaces to use to pad the table.
* @param string $charset A charset supported by the mbstring PHP
* extension.
* @param boolean $color Whether the data contains ansi color codes.
*/
function __construct(
$align=CONSOLE_TABLE_ALIGN_LEFT,
$border=CONSOLE_TABLE_BORDER_ASCII,
$padding=1,
$charset=null,
$color=false
) {
$this->_defaultAlign = $align;
$this->_border = $border;
$this->_padding = $padding;
$this->_ansiColor = $color;
if ($this->_ansiColor) {
include_once 'Console/Color.php';
}
if (!empty($charset)) {
$this->setCharset($charset);
}
}//end Console_Table()
/*
* Converts an array to a table.
*
* @param array $headers Headers for the table.
* @param array $data A two dimensional array with the table
* data.
* @param boolean $returnObject Whether to return the Console_Table object
* instead of the rendered table.
*
* @static
*
* @return Console_Table|string A Console_Table object or the generated
* table.
*/
function fromArray($headers, $data, $returnObject=false) {
if (!is_array($headers) || !is_array($data)) {
return false;
}
$table = new Console_Table();
$table->setHeaders($headers);
foreach ($data as $row) {
$table->addRow($row);
}
return $returnObject ? $table : $table->getTable();
}//end fromArray()
/*
* Adds a filter to a column.
*
* Filters are standard PHP callbacks which are run on the data before
* table generation is performed. Filters are applied in the order they
* are added. The callback function must accept a single argument, which
* is a single table cell.
*
* @param integer $col Column to apply filter to.
* @param mixed &$callback PHP callback to apply.
*
* @return void
*/
function addFilter($col, &$callback) {
$this->_filters[] = array(
$col,
&$callback,
);
}//end addFilter()
/*
* Sets the charset of the provided table data.
*
* @param string $charset A charset supported by the mbstring PHP
* extension.
*
* @return void
*/
function setCharset($charset) {
$locale = setlocale(LC_CTYPE, 0);
setlocale(LC_CTYPE, 'en_US');
$this->_charset = strtolower($charset);
setlocale(LC_CTYPE, $locale);
}//end setCharset()
/*
* Sets the alignment for the columns.
*
* @param integer $col_id The column number.
* @param integer $align Alignment to set for this column. One of
* CONSOLE_TABLE_ALIGN_LEFT
* CONSOLE_TABLE_ALIGN_CENTER
* CONSOLE_TABLE_ALIGN_RIGHT.
*
* @return void
*/
function setAlign($col_id, $align=CONSOLE_TABLE_ALIGN_LEFT)
{
switch ($align) {
case CONSOLE_TABLE_ALIGN_CENTER:
$pad = STR_PAD_BOTH;
break;
case CONSOLE_TABLE_ALIGN_RIGHT:
$pad = STR_PAD_LEFT;
break;
default:
$pad = STR_PAD_RIGHT;
break;
}
$this->_col_align[$col_id] = $pad;
}//end setAlign()
/*
* Specifies which columns are to have totals calculated for them and
* added as a new row at the bottom.
*
* @param array $cols Array of column numbers (starting with 0).
*
* @return void
*/
function calculateTotalsFor($cols) {
$this->_calculateTotals = $cols;
}//end calculateTotalsFor()
/*
* Sets the headers for the columns.
*
* @param array $headers The column headers.
*
* @return void
*/
function setHeaders($headers) {
$this->_headers = array(array_values($headers));
$this->_updateRowsCols($headers);
}//end setHeaders()
/*
* Adds a row to the table.
*
* @param array $row The row data to add.
* @param boolean $append Whether to append or prepend the row.
*
* @return void
*/
function addRow($row, $append=true) {
if ($append) {
$this->_data[] = array_values($row);
}
else {
array_unshift($this->_data, array_values($row));
}
$this->_updateRowsCols($row);
}//end addRow()
/*
* Inserts a row after a given row number in the table.
*
* If $row_id is not given it will prepend the row.
*
* @param array $row The data to insert.
* @param integer $row_id Row number to insert before.
*
* @return void
*/
function insertRow($row, $row_id=0) {
array_splice($this->_data, $row_id, 0, array($row));
$this->_updateRowsCols($row);
}//end insertRow()
/*
* Adds a column to the table.
*
* @param array $col_data The data of the column.
* @param integer $col_id The column index to populate.
* @param integer $row_id If starting row is not zero, specify it here.
*
* @return void
*/
function addCol($col_data, $col_id=0, $row_id=0) {
foreach ($col_data as $col_cell) {
$this->_data[$row_id++][$col_id] = $col_cell;
}
$this->_updateRowsCols();
$this->_max_cols = max($this->_max_cols, ($col_id + 1));
}//end addCol()
/*
* Adds data to the table.
*
* @param array $data A two dimensional array with the table data.
* @param integer $col_id Starting column number.
* @param integer $row_id Starting row number.
*
* @return void
*/
function addData($data, $col_id=0, $row_id=0) {
foreach ($data as $row) {
if ($row === CONSOLE_TABLE_HORIZONTAL_RULE) {
$this->_data[$row_id] = CONSOLE_TABLE_HORIZONTAL_RULE;
$row_id++;
continue;
}
$starting_col = $col_id;
foreach ($row as $cell) {
$this->_data[$row_id][$starting_col++] = $cell;
}
$this->_updateRowsCols();
$this->_max_cols = max($this->_max_cols, $starting_col);
$row_id++;
}
}//end addData()
/*
* Adds a horizontal seperator to the table.
*
* @return void
*/
function addSeparator() {
$this->_data[] = CONSOLE_TABLE_HORIZONTAL_RULE;
}//end addSeparator()
/*
* Returns the generated table.
*
* @return string The generated table.
*/
function getTable() {
$this->_applyFilters();
$this->_calculateTotals();
$this->_validateTable();
return $this->_buildTable();
}//end getTable()
/*
* Calculates totals for columns.
*
* @return void
*/
function _calculateTotals() {
if (empty($this->_calculateTotals)) {
return;
}
$this->addSeparator();
$totals = array();
foreach ($this->_data as $row) {
if (is_array($row)) {
foreach ($this->_calculateTotals as $columnID) {
$totals[$columnID] += $row[$columnID];
}
}
}
$this->_data[] = $totals;
$this->_updateRowsCols();
}//end _calculateTotals()
/*
* Applies any column filters to the data.
*
* @return void
*/
function _applyFilters() {
if (empty($this->_filters)) {
return;
}
foreach ($this->_filters as $filter) {
$column = $filter[0];
$callback = $filter[1];
foreach ($this->_data as $row_id => $row_data) {
if ($row_data !== CONSOLE_TABLE_HORIZONTAL_RULE) {
$this->_data[$row_id][$column] = call_user_func($callback, $row_data[$column]);
}
}
}
}//end _applyFilters()
/*
* Ensures that column and row counts are correct.
*
* @return void
*/
function _validateTable() {
if (!empty($this->_headers)) {
$this->_calculateRowHeight(-1, $this->_headers[0]);
}
for ($i = 0; $i < $this->_max_rows; $i++) {
for ($j = 0; $j < $this->_max_cols; $j++) {
if (!isset($this->_data[$i][$j])
&& (!isset($this->_data[$i])
|| $this->_data[$i] !== CONSOLE_TABLE_HORIZONTAL_RULE)
) {
$this->_data[$i][$j] = '';
}
}
$this->_calculateRowHeight($i, $this->_data[$i]);
if ($this->_data[$i] !== CONSOLE_TABLE_HORIZONTAL_RULE) {
ksort($this->_data[$i]);
}
}
$this->_splitMultilineRows();
// Update cell lengths.
$count_headers = count($this->_headers);
for ($i = 0; $i < $count_headers; $i++) {
$this->_calculateCellLengths($this->_headers[$i]);
}
for ($i = 0; $i < $this->_max_rows; $i++) {
$this->_calculateCellLengths($this->_data[$i]);
}
ksort($this->_data);
}//end _validateTable()
/*
* Splits multiline rows into many smaller one-line rows.
*
* @return void
*/
function _splitMultilineRows() {
ksort($this->_data);
$sections = array(
&$this->_headers,
&$this->_data,
);
$max_rows = array(
count($this->_headers),
$this->_max_rows,
);
$row_height_offset = array(
-1,
0,
);
for ($s = 0; $s <= 1; $s++) {
$inserted = 0;
$new_data = $sections[$s];
for ($i = 0; $i < $max_rows[$s]; $i++) {
// Process only rows that have many lines.
$height = $this->_row_heights[($i + $row_height_offset[$s])];
if ($height > 1) {
// Split column data into one-liners.
$split = array();
for ($j = 0; $j < $this->_max_cols; $j++) {
$split[$j] = preg_split(
'/\r?\n|\r/',
$sections[$s][$i][$j]
);
}
$new_rows = array();
// Construct new 'virtual' rows - insert empty strings for
// columns that have less lines that the highest one.
for ($i2 = 0; $i2 < $height; $i2++) {
for ($j = 0; $j < $this->_max_cols; $j++) {
$new_rows[$i2][$j] = !isset($split[$j][$i2]) ? '' : $split[$j][$i2];
}
}
// Replace current row with smaller rows. $inserted is
// used to take account of bigger array because of already
// inserted rows.
array_splice($new_data, ($i + $inserted), 1, $new_rows);
$inserted += (count($new_rows) - 1);
}//end if
}//end for
// Has the data been modified?
if ($inserted > 0) {
$sections[$s] = $new_data;
$this->_updateRowsCols();
}
}//end for
}//end _splitMultilineRows()
/*
* Builds the table.
*
* @return string The generated table string.
*/
function _buildTable() {
if (!count($this->_data)) {
return '';
}
$rule = $this->_border == CONSOLE_TABLE_BORDER_ASCII ? '|' : $this->_border;
$separator = $this->_getSeparator();
$return = array();
$count_data = count($this->_data);
for ($i = 0; $i < $count_data; $i++) {
$count_data_i = count($this->_data[$i]);
for ($j = 0; $j < $count_data_i; $j++) {
if ($this->_data[$i] !== CONSOLE_TABLE_HORIZONTAL_RULE
&& $this->_strlen($this->_data[$i][$j]) < $this->_cell_lengths[$j]
) {
$this->_data[$i][$j] = $this->_strpad(
$this->_data[$i][$j],
$this->_cell_lengths[$j],
' ',
$this->_col_align[$j]
);
}
}
if ($this->_data[$i] !== CONSOLE_TABLE_HORIZONTAL_RULE) {
$row_begin = $rule.str_repeat(' ', $this->_padding);
$row_end = str_repeat(' ', $this->_padding).$rule;
$implode_char = str_repeat(' ', $this->_padding).$rule.str_repeat(' ', $this->_padding);
$return[] = $row_begin.implode($implode_char, $this->_data[$i]).$row_end;
}
else if (!empty($separator)) {
$return[] = $separator;
}
}//end for
$return = implode(PHP_EOL, $return);
if (!empty($separator)) {
$return = $separator.PHP_EOL.$return.PHP_EOL.$separator;
}
$return .= PHP_EOL;
if (!empty($this->_headers)) {
$return = $this->_getHeaderLine().PHP_EOL.$return;
}
return $return;
}//end _buildTable()
/*
* Creates a horizontal separator for header separation and table
* start/end etc.
*
* @return string The horizontal separator.
*/
function _getSeparator() {
if (!$this->_border) {
return;
}
if ($this->_border == CONSOLE_TABLE_BORDER_ASCII) {
$rule = '-';
$sect = '+';
}
else {
$rule = $sect = $this->_border;
}
$return = array();
foreach ($this->_cell_lengths as $cl) {
$return[] = str_repeat($rule, $cl);
}
$row_begin = $sect.str_repeat($rule, $this->_padding);
$row_end = str_repeat($rule, $this->_padding).$sect;
$implode_char = str_repeat($rule, $this->_padding).$sect.str_repeat($rule, $this->_padding);
return $row_begin.implode($implode_char, $return).$row_end;
}//end _getSeparator()
/*
* Returns the header line for the table.
*
* @return string The header line of the table.
*/
function _getHeaderLine() {
// Make sure column count is correct
$count_headers = count($this->_headers);
for ($j = 0; $j < $count_headers; $j++) {
for ($i = 0; $i < $this->_max_cols; $i++) {
if (!isset($this->_headers[$j][$i])) {
$this->_headers[$j][$i] = '';
}
}
}
$count_headers = count($this->_headers);
for ($j = 0; $j < $count_headers; $j++) {
$count_headers_j = count($this->_headers[$j]);
for ($i = 0; $i < $count_headers_j; $i++) {
if ($this->_strlen($this->_headers[$j][$i]) < $this->_cell_lengths[$i]
) {
$this->_headers[$j][$i] = $this->_strpad(
$this->_headers[$j][$i],
$this->_cell_lengths[$i],
' ',
$this->_col_align[$i]
);
}
}
}
$rule = $this->_border == CONSOLE_TABLE_BORDER_ASCII ? '|' : $this->_border;
$row_begin = $rule.str_repeat(' ', $this->_padding);
$row_end = str_repeat(' ', $this->_padding).$rule;
$implode_char = str_repeat(' ', $this->_padding).$rule.str_repeat(' ', $this->_padding);
$separator = $this->_getSeparator();
if (!empty($separator)) {
$return[] = $separator;
}
for ($j = 0; $j < count($this->_headers); $j++) {
$return[] = $row_begin.implode($implode_char, $this->_headers[$j]).$row_end;
}
return implode(PHP_EOL, $return);
}//end _getHeaderLine()
/*
* Updates values for maximum columns and rows.
*
* @param array $rowdata Data array of a single row.
*
* @return void
*/
function _updateRowsCols($rowdata=null) {
// Update maximum columns.
$this->_max_cols = max($this->_max_cols, count($rowdata));
// Update maximum rows.
ksort($this->_data);
$keys = array_keys($this->_data);
$this->_max_rows = (end($keys) + 1);
switch ($this->_defaultAlign) {
case CONSOLE_TABLE_ALIGN_CENTER:
$pad = STR_PAD_BOTH;
break;
case CONSOLE_TABLE_ALIGN_RIGHT:
$pad = STR_PAD_LEFT;
break;
default:
$pad = STR_PAD_RIGHT;
break;
}
// Set default column alignments
for ($i = count($this->_col_align); $i < $this->_max_cols; $i++) {
$this->_col_align[$i] = $pad;
}
}//end _updateRowsCols()
/*
* Calculates the maximum length for each column of a row.
*
* @param array $row The row data.
*
* @return void
*/
function _calculateCellLengths($row) {
$count_row = count($row);
for ($i = 0; $i < $count_row; $i++) {
if (!isset($this->_cell_lengths[$i])) {
$this->_cell_lengths[$i] = 0;
}
$this->_cell_lengths[$i] = max(
$this->_cell_lengths[$i],
$this->_strlen($row[$i])
);
}
}//end _calculateCellLengths()
/*
* Calculates the maximum height for all columns of a row.
*
* @param integer $row_number The row number.
* @param array $row The row data.
*
* @return void
*/
function _calculateRowHeight($row_number, $row) {
if (!isset($this->_row_heights[$row_number])) {
$this->_row_heights[$row_number] = 1;
}
// Do not process horizontal rule rows.
if ($row === CONSOLE_TABLE_HORIZONTAL_RULE) {
return;
}
for ($i = 0, $c = count($row); $i < $c; ++$i) {
$lines = preg_split('/\r?\n|\r/', $row[$i]);
$this->_row_heights[$row_number] = max(
$this->_row_heights[$row_number],
count($lines)
);
}
}//end _calculateRowHeight()
/*
* Returns the character length of a string.
*
* @param string $str A multibyte or singlebyte string.
*
* @return integer The string length.
*/
function _strlen($str) {
static $mbstring;
// Strip ANSI color codes if requested.
if ($this->_ansiColor) {
$str = Console_Color::strip($str);
}
// Cache expensive function_exists() calls.
if (!isset($mbstring)) {
$mbstring = function_exists('mb_strwidth');
}
if ($mbstring) {
return mb_strwidth($str, $this->_charset);
}
return strlen($str);
}//end _strlen()
/*
* Returns part of a string.
*
* @param string $string The string to be converted.
* @param integer $start The part's start position, zero based.
* @param integer $length The part's length.
*
* @return string The string's part.
*/
function _substr($string, $start, $length=null) {
static $mbstring;
// Cache expensive function_exists() calls.
if (!isset($mbstring)) {
$mbstring = function_exists('mb_substr');
}
if (is_null($length)) {
$length = $this->_strlen($string);
}
if ($mbstring) {
$ret = @mb_substr($string, $start, $length, $this->_charset);
if (!empty($ret)) {
return $ret;
}
}
return substr($string, $start, $length);
}//end _substr()
/*
* Returns a string padded to a certain length with another string.
*
* This method behaves exactly like str_pad but is multibyte safe.
*
* @param string $input The string to be padded.
* @param integer $length The length of the resulting string.
* @param string $pad The string to pad the input string with. Must
* be in the same charset like the input string.
* @param const $type The padding type. One of STR_PAD_LEFT,
* STR_PAD_RIGHT, or STR_PAD_BOTH.
*
* @return string The padded string.
*/
function _strpad($input, $length, $pad=' ', $type=STR_PAD_RIGHT) {
$mb_length = $this->_strlen($input);
$sb_length = strlen($input);
$pad_length = $this->_strlen($pad);
// Return if we already have the length.
if ($mb_length >= $length) {
return $input;
}
// Shortcut for single byte strings.
if ($mb_length == $sb_length && $pad_length == strlen($pad)) {
return str_pad($input, $length, $pad, $type);
}
switch ($type) {
case STR_PAD_LEFT:
$left = ($length - $mb_length);
$output = $this->_substr(
str_repeat($pad, ceil($left / $pad_length)),
0,
$left,
$this->_charset
).$input;
break;
case STR_PAD_BOTH:
$left = floor(($length - $mb_length) / 2);
$right = ceil(($length - $mb_length) / 2);
$output = $this->_substr(
str_repeat($pad, ceil($left / $pad_length)),
0,
$left,
$this->_charset
).$input.$this->_substr(
str_repeat($pad, ceil($right / $pad_length)),
0,
$right,
$this->_charset
);
break;
case STR_PAD_RIGHT:
$right = ($length - $mb_length);
$output = $input.$this->_substr(
str_repeat($pad, ceil($right / $pad_length)),
0,
$right,
$this->_charset
);
break;
}//end switch
return $output;
}//end _strpad()
}//end class

View File

@@ -1,9 +0,0 @@
CREDITS
Almost everything written by Edward Z. Yang (Ambush Commander). Lots of thanks
to the DevNetwork Community for their help (see docs/ref-devnetwork.html for
more details), Feyd especially (namely IPv6 and optimization). Thanks to RSnake
for letting me package his fantastic XSS cheatsheet for a smoketest.
vim: et sw=4 sts=4

View File

@@ -1,373 +0,0 @@
Install
How to install HTML Purifier
HTML Purifier is designed to run out of the box, so actually using the
library is extremely easy. (Although... if you were looking for a
step-by-step installation GUI, you've downloaded the wrong software!)
While the impatient can get going immediately with some of the sample
code at the bottom of this library, it's well worth reading this entire
document--most of the other documentation assumes that you are familiar
with these contents.
---------------------------------------------------------------------------
1. Compatibility
HTML Purifier is PHP 5 and PHP 7, and is actively tested from PHP 5.0.5
and up. It has no core dependencies with other libraries.
These optional extensions can enhance the capabilities of HTML Purifier:
* iconv : Converts text to and from non-UTF-8 encodings
* bcmath : Used for unit conversion and imagecrash protection
* tidy : Used for pretty-printing HTML
These optional libraries can enhance the capabilities of HTML Purifier:
* CSSTidy : Clean CSS stylesheets using %Core.ExtractStyleBlocks
Note: You should use the modernized fork of CSSTidy available
at https://github.com/Cerdic/CSSTidy
* Net_IDNA2 (PEAR) : IRI support using %Core.EnableIDNA
Note: This is not necessary for PHP 5.3 or later
---------------------------------------------------------------------------
2. Reconnaissance
A big plus of HTML Purifier is its inerrant support of standards, so
your web-pages should be standards-compliant. (They should also use
semantic markup, but that's another issue altogether, one HTML Purifier
cannot fix without reading your mind.)
HTML Purifier can process these doctypes:
* XHTML 1.0 Transitional (default)
* XHTML 1.0 Strict
* HTML 4.01 Transitional
* HTML 4.01 Strict
* XHTML 1.1
...and these character encodings:
* UTF-8 (default)
* Any encoding iconv supports (with crippled internationalization support)
These defaults reflect what my choices would be if I were authoring an
HTML document, however, what you choose depends on the nature of your
codebase. If you don't know what doctype you are using, you can determine
the doctype from this identifier at the top of your source code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
...and the character encoding from this code:
<meta http-equiv="Content-type" content="text/html;charset=ENCODING">
If the character encoding declaration is missing, STOP NOW, and
read 'docs/enduser-utf8.html' (web accessible at
http://htmlpurifier.org/docs/enduser-utf8.html). In fact, even if it is
present, read this document anyway, as many websites specify their
document's character encoding incorrectly.
---------------------------------------------------------------------------
3. Including the library
The procedure is quite simple:
require_once '/path/to/library/HTMLPurifier.auto.php';
This will setup an autoloader, so the library's files are only included
when you use them.
Only the contents in the library/ folder are necessary, so you can remove
everything else when using HTML Purifier in a production environment.
If you installed HTML Purifier via PEAR, all you need to do is:
require_once 'HTMLPurifier.auto.php';
Please note that the usual PEAR practice of including just the classes you
want will not work with HTML Purifier's autoloading scheme.
Advanced users, read on; other users can skip to section 4.
Autoload compatibility
----------------------
HTML Purifier attempts to be as smart as possible when registering an
autoloader, but there are some cases where you will need to change
your own code to accomodate HTML Purifier. These are those cases:
PHP VERSION IS LESS THAN 5.1.2, AND YOU'VE DEFINED __autoload
Because spl_autoload_register() doesn't exist in early versions
of PHP 5, HTML Purifier has no way of adding itself to the autoload
stack. Modify your __autoload function to test
HTMLPurifier_Bootstrap::autoload($class)
For example, suppose your autoload function looks like this:
function __autoload($class) {
require str_replace('_', '/', $class) . '.php';
return true;
}
A modified version with HTML Purifier would look like this:
function __autoload($class) {
if (HTMLPurifier_Bootstrap::autoload($class)) return true;
require str_replace('_', '/', $class) . '.php';
return true;
}
Note that there *is* some custom behavior in our autoloader; the
original autoloader in our example would work for 99% of the time,
but would fail when including language files.
AN __autoload FUNCTION IS DECLARED AFTER OUR AUTOLOADER IS REGISTERED
spl_autoload_register() has the curious behavior of disabling
the existing __autoload() handler. Users need to explicitly
spl_autoload_register('__autoload'). Because we use SPL when it
is available, __autoload() will ALWAYS be disabled. If __autoload()
is declared before HTML Purifier is loaded, this is not a problem:
HTML Purifier will register the function for you. But if it is
declared afterwards, it will mysteriously not work. This
snippet of code (after your autoloader is defined) will fix it:
spl_autoload_register('__autoload')
Users should also be on guard if they use a version of PHP previous
to 5.1.2 without an autoloader--HTML Purifier will define __autoload()
for you, which can collide with an autoloader that was added by *you*
later.
For better performance
----------------------
Opcode caches, which greatly speed up PHP initialization for scripts
with large amounts of code (HTML Purifier included), don't like
autoloaders. We offer an include file that includes all of HTML Purifier's
files in one go in an opcode cache friendly manner:
// If /path/to/library isn't already in your include path, uncomment
// the below line:
// require '/path/to/library/HTMLPurifier.path.php';
require 'HTMLPurifier.includes.php';
Optional components still need to be included--you'll know if you try to
use a feature and you get a class doesn't exists error! The autoloader
can be used in conjunction with this approach to catch classes that are
missing. Simply add this afterwards:
require 'HTMLPurifier.autoload.php';
Standalone version
------------------
HTML Purifier has a standalone distribution; you can also generate
a standalone file from the full version by running the script
maintenance/generate-standalone.php . The standalone version has the
benefit of having most of its code in one file, so parsing is much
faster and the library is easier to manage.
If HTMLPurifier.standalone.php exists in the library directory, you
can use it like this:
require '/path/to/HTMLPurifier.standalone.php';
This is equivalent to including HTMLPurifier.includes.php, except that
the contents of standalone/ will be added to your path. To override this
behavior, specify a new HTMLPURIFIER_PREFIX where standalone files can
be found (usually, this will be one directory up, the "true" library
directory in full distributions). Don't forget to set your path too!
The autoloader can be added to the end to ensure the classes are
loaded when necessary; otherwise you can manually include them.
To use the autoloader, use this:
require 'HTMLPurifier.autoload.php';
For advanced users
------------------
HTMLPurifier.auto.php performs a number of operations that can be done
individually. These are:
HTMLPurifier.path.php
Puts /path/to/library in the include path. For high performance,
this should be done in php.ini.
HTMLPurifier.autoload.php
Registers our autoload handler HTMLPurifier_Bootstrap::autoload($class).
You can do these operations by yourself--in fact, you must modify your own
autoload handler if you are using a version of PHP earlier than PHP 5.1.2
(See "Autoload compatibility" above).
---------------------------------------------------------------------------
4. Configuration
HTML Purifier is designed to run out-of-the-box, but occasionally HTML
Purifier needs to be told what to do. If you answer no to any of these
questions, read on; otherwise, you can skip to the next section (or, if you're
into configuring things just for the heck of it, skip to 4.3).
* Am I using UTF-8?
* Am I using XHTML 1.0 Transitional?
If you answered no to any of these questions, instantiate a configuration
object and read on:
$config = HTMLPurifier_Config::createDefault();
4.1. Setting a different character encoding
You really shouldn't use any other encoding except UTF-8, especially if you
plan to support multilingual websites (read section three for more details).
However, switching to UTF-8 is not always immediately feasible, so we can
adapt.
HTML Purifier uses iconv to support other character encodings, as such,
any encoding that iconv supports <http://www.gnu.org/software/libiconv/>
HTML Purifier supports with this code:
$config->set('Core.Encoding', /* put your encoding here */);
An example usage for Latin-1 websites (the most common encoding for English
websites):
$config->set('Core.Encoding', 'ISO-8859-1');
Note that HTML Purifier's support for non-Unicode encodings is crippled by the
fact that any character not supported by that encoding will be silently
dropped, EVEN if it is ampersand escaped. If you want to work around
this, you are welcome to read docs/enduser-utf8.html for a fix,
but please be cognizant of the issues the "solution" creates (for this
reason, I do not include the solution in this document).
4.2. Setting a different doctype
For those of you using HTML 4.01 Transitional, you can disable
XHTML output like this:
$config->set('HTML.Doctype', 'HTML 4.01 Transitional');
Other supported doctypes include:
* HTML 4.01 Strict
* HTML 4.01 Transitional
* XHTML 1.0 Strict
* XHTML 1.0 Transitional
* XHTML 1.1
4.3. Other settings
There are more configuration directives which can be read about
here: <http://htmlpurifier.org/live/configdoc/plain.html> They're a bit boring,
but they can help out for those of you who like to exert maximum control over
your code. Some of the more interesting ones are configurable at the
demo <http://htmlpurifier.org/demo.php> and are well worth looking into
for your own system.
For example, you can fine tune allowed elements and attributes, convert
relative URLs to absolute ones, and even autoparagraph input text! These
are, respectively, %HTML.Allowed, %URI.MakeAbsolute and %URI.Base, and
%AutoFormat.AutoParagraph. The %Namespace.Directive naming convention
translates to:
$config->set('Namespace.Directive', $value);
E.g.
$config->set('HTML.Allowed', 'p,b,a[href],i');
$config->set('URI.Base', 'http://www.example.com');
$config->set('URI.MakeAbsolute', true);
$config->set('AutoFormat.AutoParagraph', true);
---------------------------------------------------------------------------
5. Caching
HTML Purifier generates some cache files (generally one or two) to speed up
its execution. For maximum performance, make sure that
library/HTMLPurifier/DefinitionCache/Serializer is writeable by the webserver.
If you are in the library/ folder of HTML Purifier, you can set the
appropriate permissions using:
chmod -R 0755 HTMLPurifier/DefinitionCache/Serializer
If the above command doesn't work, you may need to assign write permissions
to group:
chmod -R 0775 HTMLPurifier/DefinitionCache/Serializer
You can also chmod files via your FTP client; this option
is usually accessible by right clicking the corresponding directory and
then selecting "chmod" or "file permissions".
Starting with 2.0.1, HTML Purifier will generate friendly error messages
that will tell you exactly what you have to chmod the directory to, if in doubt,
follow its advice.
If you are unable or unwilling to give write permissions to the cache
directory, you can either disable the cache (and suffer a performance
hit):
$config->set('Core.DefinitionCache', null);
Or move the cache directory somewhere else (no trailing slash):
$config->set('Cache.SerializerPath', '/home/user/absolute/path');
---------------------------------------------------------------------------
6. Using the code
The interface is mind-numbingly simple:
$purifier = new HTMLPurifier($config);
$clean_html = $purifier->purify( $dirty_html );
That's it! For more examples, check out docs/examples/ (they aren't very
different though). Also, docs/enduser-slow.html gives advice on what to
do if HTML Purifier is slowing down your application.
---------------------------------------------------------------------------
7. Quick install
First, make sure library/HTMLPurifier/DefinitionCache/Serializer is
writable by the webserver (see Section 5: Caching above for details).
If your website is in UTF-8 and XHTML Transitional, use this code:
<?php
require_once '/path/to/htmlpurifier/library/HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
$clean_html = $purifier->purify($dirty_html);
?>
If your website is in a different encoding or doctype, use this code:
<?php
require_once '/path/to/htmlpurifier/library/HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$config->set('Core.Encoding', 'ISO-8859-1'); // replace with your encoding
$config->set('HTML.Doctype', 'HTML 4.01 Transitional'); // replace with your doctype
$purifier = new HTMLPurifier($config);
$clean_html = $purifier->purify($dirty_html);
?>
vim: et sw=4 sts=4

View File

@@ -1,504 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
vim: et sw=4 sts=4

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +0,0 @@
<?php
/**
* This is a stub include that automatically configures the include path.
*/
set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path() );
require_once 'HTMLPurifier/Bootstrap.php';
require_once 'HTMLPurifier.autoload.php';
// vim: et sw=4 sts=4

View File

@@ -1,27 +0,0 @@
<?php
/**
* @file
* Convenience file that registers autoload handler for HTML Purifier.
* It also does some sanity checks.
*/
if (function_exists('spl_autoload_register') && function_exists('spl_autoload_unregister')) {
// We need unregister for our pre-registering functionality
HTMLPurifier_Bootstrap::registerAutoload();
if (function_exists('__autoload')) {
// Be polite and ensure that userland autoload gets retained
spl_autoload_register('__autoload');
}
} elseif (!function_exists('__autoload')) {
function __autoload($class)
{
return HTMLPurifier_Bootstrap::autoload($class);
}
}
if (ini_get('zend.ze1_compatibility_mode')) {
trigger_error("HTML Purifier is not compatible with zend.ze1_compatibility_mode; please turn it off", E_USER_ERROR);
}
// vim: et sw=4 sts=4

View File

@@ -1,4 +0,0 @@
<?php
if (!defined('HTMLPURIFIER_PREFIX')) {
define('HTMLPURIFIER_PREFIX', dirname(__FILE__));
}

View File

@@ -1,25 +0,0 @@
<?php
/**
* @file
* Defines a function wrapper for HTML Purifier for quick use.
* @note ''HTMLPurifier()'' is NOT the same as ''new HTMLPurifier()''
*/
/**
* Purify HTML.
* @param string $html String HTML to purify
* @param mixed $config Configuration to use, can be any value accepted by
* HTMLPurifier_Config::create()
* @return string
*/
function HTMLPurifier($html, $config = null)
{
static $purifier = false;
if (!$purifier) {
$purifier = new HTMLPurifier();
}
return $purifier->purify($html, $config);
}
// vim: et sw=4 sts=4

View File

@@ -1,232 +0,0 @@
<?php
/**
* @file
* This file was auto-generated by generate-includes.php and includes all of
* the core files required by HTML Purifier. Use this if performance is a
* primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS
* FILE, changes will be overwritten the next time the script is run.
*
* @version 4.8.0
*
* @warning
* You must *not* include any other HTML Purifier files before this file,
* because 'require' not 'require_once' is used.
*
* @warning
* This file requires that the include path contains the HTML Purifier
* library directory; this is not auto-set.
*/
require 'HTMLPurifier.php';
require 'HTMLPurifier/Arborize.php';
require 'HTMLPurifier/AttrCollections.php';
require 'HTMLPurifier/AttrDef.php';
require 'HTMLPurifier/AttrTransform.php';
require 'HTMLPurifier/AttrTypes.php';
require 'HTMLPurifier/AttrValidator.php';
require 'HTMLPurifier/Bootstrap.php';
require 'HTMLPurifier/Definition.php';
require 'HTMLPurifier/CSSDefinition.php';
require 'HTMLPurifier/ChildDef.php';
require 'HTMLPurifier/Config.php';
require 'HTMLPurifier/ConfigSchema.php';
require 'HTMLPurifier/ContentSets.php';
require 'HTMLPurifier/Context.php';
require 'HTMLPurifier/DefinitionCache.php';
require 'HTMLPurifier/DefinitionCacheFactory.php';
require 'HTMLPurifier/Doctype.php';
require 'HTMLPurifier/DoctypeRegistry.php';
require 'HTMLPurifier/ElementDef.php';
require 'HTMLPurifier/Encoder.php';
require 'HTMLPurifier/EntityLookup.php';
require 'HTMLPurifier/EntityParser.php';
require 'HTMLPurifier/ErrorCollector.php';
require 'HTMLPurifier/ErrorStruct.php';
require 'HTMLPurifier/Exception.php';
require 'HTMLPurifier/Filter.php';
require 'HTMLPurifier/Generator.php';
require 'HTMLPurifier/HTMLDefinition.php';
require 'HTMLPurifier/HTMLModule.php';
require 'HTMLPurifier/HTMLModuleManager.php';
require 'HTMLPurifier/IDAccumulator.php';
require 'HTMLPurifier/Injector.php';
require 'HTMLPurifier/Language.php';
require 'HTMLPurifier/LanguageFactory.php';
require 'HTMLPurifier/Length.php';
require 'HTMLPurifier/Lexer.php';
require 'HTMLPurifier/Node.php';
require 'HTMLPurifier/PercentEncoder.php';
require 'HTMLPurifier/PropertyList.php';
require 'HTMLPurifier/PropertyListIterator.php';
require 'HTMLPurifier/Queue.php';
require 'HTMLPurifier/Strategy.php';
require 'HTMLPurifier/StringHash.php';
require 'HTMLPurifier/StringHashParser.php';
require 'HTMLPurifier/TagTransform.php';
require 'HTMLPurifier/Token.php';
require 'HTMLPurifier/TokenFactory.php';
require 'HTMLPurifier/URI.php';
require 'HTMLPurifier/URIDefinition.php';
require 'HTMLPurifier/URIFilter.php';
require 'HTMLPurifier/URIParser.php';
require 'HTMLPurifier/URIScheme.php';
require 'HTMLPurifier/URISchemeRegistry.php';
require 'HTMLPurifier/UnitConverter.php';
require 'HTMLPurifier/VarParser.php';
require 'HTMLPurifier/VarParserException.php';
require 'HTMLPurifier/Zipper.php';
require 'HTMLPurifier/AttrDef/CSS.php';
require 'HTMLPurifier/AttrDef/Clone.php';
require 'HTMLPurifier/AttrDef/Enum.php';
require 'HTMLPurifier/AttrDef/Integer.php';
require 'HTMLPurifier/AttrDef/Lang.php';
require 'HTMLPurifier/AttrDef/Switch.php';
require 'HTMLPurifier/AttrDef/Text.php';
require 'HTMLPurifier/AttrDef/URI.php';
require 'HTMLPurifier/AttrDef/CSS/Number.php';
require 'HTMLPurifier/AttrDef/CSS/AlphaValue.php';
require 'HTMLPurifier/AttrDef/CSS/Background.php';
require 'HTMLPurifier/AttrDef/CSS/BackgroundPosition.php';
require 'HTMLPurifier/AttrDef/CSS/Border.php';
require 'HTMLPurifier/AttrDef/CSS/Color.php';
require 'HTMLPurifier/AttrDef/CSS/Composite.php';
require 'HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php';
require 'HTMLPurifier/AttrDef/CSS/Filter.php';
require 'HTMLPurifier/AttrDef/CSS/Font.php';
require 'HTMLPurifier/AttrDef/CSS/FontFamily.php';
require 'HTMLPurifier/AttrDef/CSS/Ident.php';
require 'HTMLPurifier/AttrDef/CSS/ImportantDecorator.php';
require 'HTMLPurifier/AttrDef/CSS/Length.php';
require 'HTMLPurifier/AttrDef/CSS/ListStyle.php';
require 'HTMLPurifier/AttrDef/CSS/Multiple.php';
require 'HTMLPurifier/AttrDef/CSS/Percentage.php';
require 'HTMLPurifier/AttrDef/CSS/TextDecoration.php';
require 'HTMLPurifier/AttrDef/CSS/URI.php';
require 'HTMLPurifier/AttrDef/HTML/Bool.php';
require 'HTMLPurifier/AttrDef/HTML/Nmtokens.php';
require 'HTMLPurifier/AttrDef/HTML/Class.php';
require 'HTMLPurifier/AttrDef/HTML/Color.php';
require 'HTMLPurifier/AttrDef/HTML/FrameTarget.php';
require 'HTMLPurifier/AttrDef/HTML/ID.php';
require 'HTMLPurifier/AttrDef/HTML/Pixels.php';
require 'HTMLPurifier/AttrDef/HTML/Length.php';
require 'HTMLPurifier/AttrDef/HTML/LinkTypes.php';
require 'HTMLPurifier/AttrDef/HTML/MultiLength.php';
require 'HTMLPurifier/AttrDef/URI/Email.php';
require 'HTMLPurifier/AttrDef/URI/Host.php';
require 'HTMLPurifier/AttrDef/URI/IPv4.php';
require 'HTMLPurifier/AttrDef/URI/IPv6.php';
require 'HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php';
require 'HTMLPurifier/AttrTransform/Background.php';
require 'HTMLPurifier/AttrTransform/BdoDir.php';
require 'HTMLPurifier/AttrTransform/BgColor.php';
require 'HTMLPurifier/AttrTransform/BoolToCSS.php';
require 'HTMLPurifier/AttrTransform/Border.php';
require 'HTMLPurifier/AttrTransform/EnumToCSS.php';
require 'HTMLPurifier/AttrTransform/ImgRequired.php';
require 'HTMLPurifier/AttrTransform/ImgSpace.php';
require 'HTMLPurifier/AttrTransform/Input.php';
require 'HTMLPurifier/AttrTransform/Lang.php';
require 'HTMLPurifier/AttrTransform/Length.php';
require 'HTMLPurifier/AttrTransform/Name.php';
require 'HTMLPurifier/AttrTransform/NameSync.php';
require 'HTMLPurifier/AttrTransform/Nofollow.php';
require 'HTMLPurifier/AttrTransform/SafeEmbed.php';
require 'HTMLPurifier/AttrTransform/SafeObject.php';
require 'HTMLPurifier/AttrTransform/SafeParam.php';
require 'HTMLPurifier/AttrTransform/ScriptRequired.php';
require 'HTMLPurifier/AttrTransform/TargetBlank.php';
require 'HTMLPurifier/AttrTransform/TargetNoreferrer.php';
require 'HTMLPurifier/AttrTransform/Textarea.php';
require 'HTMLPurifier/ChildDef/Chameleon.php';
require 'HTMLPurifier/ChildDef/Custom.php';
require 'HTMLPurifier/ChildDef/Empty.php';
require 'HTMLPurifier/ChildDef/List.php';
require 'HTMLPurifier/ChildDef/Required.php';
require 'HTMLPurifier/ChildDef/Optional.php';
require 'HTMLPurifier/ChildDef/StrictBlockquote.php';
require 'HTMLPurifier/ChildDef/Table.php';
require 'HTMLPurifier/DefinitionCache/Decorator.php';
require 'HTMLPurifier/DefinitionCache/Null.php';
require 'HTMLPurifier/DefinitionCache/Serializer.php';
require 'HTMLPurifier/DefinitionCache/Decorator/Cleanup.php';
require 'HTMLPurifier/DefinitionCache/Decorator/Memory.php';
require 'HTMLPurifier/HTMLModule/Bdo.php';
require 'HTMLPurifier/HTMLModule/CommonAttributes.php';
require 'HTMLPurifier/HTMLModule/Edit.php';
require 'HTMLPurifier/HTMLModule/Forms.php';
require 'HTMLPurifier/HTMLModule/Hypertext.php';
require 'HTMLPurifier/HTMLModule/Iframe.php';
require 'HTMLPurifier/HTMLModule/Image.php';
require 'HTMLPurifier/HTMLModule/Legacy.php';
require 'HTMLPurifier/HTMLModule/List.php';
require 'HTMLPurifier/HTMLModule/Name.php';
require 'HTMLPurifier/HTMLModule/Nofollow.php';
require 'HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php';
require 'HTMLPurifier/HTMLModule/Object.php';
require 'HTMLPurifier/HTMLModule/Presentation.php';
require 'HTMLPurifier/HTMLModule/Proprietary.php';
require 'HTMLPurifier/HTMLModule/Ruby.php';
require 'HTMLPurifier/HTMLModule/SafeEmbed.php';
require 'HTMLPurifier/HTMLModule/SafeObject.php';
require 'HTMLPurifier/HTMLModule/SafeScripting.php';
require 'HTMLPurifier/HTMLModule/Scripting.php';
require 'HTMLPurifier/HTMLModule/StyleAttribute.php';
require 'HTMLPurifier/HTMLModule/Tables.php';
require 'HTMLPurifier/HTMLModule/Target.php';
require 'HTMLPurifier/HTMLModule/TargetBlank.php';
require 'HTMLPurifier/HTMLModule/TargetNoreferrer.php';
require 'HTMLPurifier/HTMLModule/Text.php';
require 'HTMLPurifier/HTMLModule/Tidy.php';
require 'HTMLPurifier/HTMLModule/XMLCommonAttributes.php';
require 'HTMLPurifier/HTMLModule/Tidy/Name.php';
require 'HTMLPurifier/HTMLModule/Tidy/Proprietary.php';
require 'HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php';
require 'HTMLPurifier/HTMLModule/Tidy/Strict.php';
require 'HTMLPurifier/HTMLModule/Tidy/Transitional.php';
require 'HTMLPurifier/HTMLModule/Tidy/XHTML.php';
require 'HTMLPurifier/Injector/AutoParagraph.php';
require 'HTMLPurifier/Injector/DisplayLinkURI.php';
require 'HTMLPurifier/Injector/Linkify.php';
require 'HTMLPurifier/Injector/PurifierLinkify.php';
require 'HTMLPurifier/Injector/RemoveEmpty.php';
require 'HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php';
require 'HTMLPurifier/Injector/SafeObject.php';
require 'HTMLPurifier/Lexer/DOMLex.php';
require 'HTMLPurifier/Lexer/DirectLex.php';
require 'HTMLPurifier/Node/Comment.php';
require 'HTMLPurifier/Node/Element.php';
require 'HTMLPurifier/Node/Text.php';
require 'HTMLPurifier/Strategy/Composite.php';
require 'HTMLPurifier/Strategy/Core.php';
require 'HTMLPurifier/Strategy/FixNesting.php';
require 'HTMLPurifier/Strategy/MakeWellFormed.php';
require 'HTMLPurifier/Strategy/RemoveForeignElements.php';
require 'HTMLPurifier/Strategy/ValidateAttributes.php';
require 'HTMLPurifier/TagTransform/Font.php';
require 'HTMLPurifier/TagTransform/Simple.php';
require 'HTMLPurifier/Token/Comment.php';
require 'HTMLPurifier/Token/Tag.php';
require 'HTMLPurifier/Token/Empty.php';
require 'HTMLPurifier/Token/End.php';
require 'HTMLPurifier/Token/Start.php';
require 'HTMLPurifier/Token/Text.php';
require 'HTMLPurifier/URIFilter/DisableExternal.php';
require 'HTMLPurifier/URIFilter/DisableExternalResources.php';
require 'HTMLPurifier/URIFilter/DisableResources.php';
require 'HTMLPurifier/URIFilter/HostBlacklist.php';
require 'HTMLPurifier/URIFilter/MakeAbsolute.php';
require 'HTMLPurifier/URIFilter/Munge.php';
require 'HTMLPurifier/URIFilter/SafeIframe.php';
require 'HTMLPurifier/URIScheme/data.php';
require 'HTMLPurifier/URIScheme/file.php';
require 'HTMLPurifier/URIScheme/ftp.php';
require 'HTMLPurifier/URIScheme/http.php';
require 'HTMLPurifier/URIScheme/https.php';
require 'HTMLPurifier/URIScheme/mailto.php';
require 'HTMLPurifier/URIScheme/news.php';
require 'HTMLPurifier/URIScheme/nntp.php';
require 'HTMLPurifier/URIScheme/tel.php';
require 'HTMLPurifier/VarParser/Flexible.php';
require 'HTMLPurifier/VarParser/Native.php';

View File

@@ -1,30 +0,0 @@
<?php
/**
* @file
* Emulation layer for code that used kses(), substituting in HTML Purifier.
*/
require_once dirname(__FILE__) . '/HTMLPurifier.auto.php';
function kses($string, $allowed_html, $allowed_protocols = null)
{
$config = HTMLPurifier_Config::createDefault();
$allowed_elements = array();
$allowed_attributes = array();
foreach ($allowed_html as $element => $attributes) {
$allowed_elements[$element] = true;
foreach ($attributes as $attribute => $x) {
$allowed_attributes["$element.$attribute"] = true;
}
}
$config->set('HTML.AllowedElements', $allowed_elements);
$config->set('HTML.AllowedAttributes', $allowed_attributes);
if ($allowed_protocols !== null) {
$config->set('URI.AllowedSchemes', $allowed_protocols);
}
$purifier = new HTMLPurifier($config);
return $purifier->purify($string);
}
// vim: et sw=4 sts=4

View File

@@ -1,11 +0,0 @@
<?php
/**
* @file
* Convenience stub file that adds HTML Purifier's library file to the path
* without any other side-effects.
*/
set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path() );
// vim: et sw=4 sts=4

View File

@@ -1,292 +0,0 @@
<?php
/*! @mainpage
*
* HTML Purifier is an HTML filter that will take an arbitrary snippet of
* HTML and rigorously test, validate and filter it into a version that
* is safe for output onto webpages. It achieves this by:
*
* -# Lexing (parsing into tokens) the document,
* -# Executing various strategies on the tokens:
* -# Removing all elements not in the whitelist,
* -# Making the tokens well-formed,
* -# Fixing the nesting of the nodes, and
* -# Validating attributes of the nodes; and
* -# Generating HTML from the purified tokens.
*
* However, most users will only need to interface with the HTMLPurifier
* and HTMLPurifier_Config.
*/
/*
HTML Purifier 4.8.0 - Standards Compliant HTML Filtering
Copyright (C) 2006-2008 Edward Z. Yang
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* Facade that coordinates HTML Purifier's subsystems in order to purify HTML.
*
* @note There are several points in which configuration can be specified
* for HTML Purifier. The precedence of these (from lowest to
* highest) is as follows:
* -# Instance: new HTMLPurifier($config)
* -# Invocation: purify($html, $config)
* These configurations are entirely independent of each other and
* are *not* merged (this behavior may change in the future).
*
* @todo We need an easier way to inject strategies using the configuration
* object.
*/
class HTMLPurifier
{
/**
* Version of HTML Purifier.
* @type string
*/
public $version = '4.8.0';
/**
* Constant with version of HTML Purifier.
*/
const VERSION = '4.8.0';
/**
* Global configuration object.
* @type HTMLPurifier_Config
*/
public $config;
/**
* Array of extra filter objects to run on HTML,
* for backwards compatibility.
* @type HTMLPurifier_Filter[]
*/
private $filters = array();
/**
* Single instance of HTML Purifier.
* @type HTMLPurifier
*/
private static $instance;
/**
* @type HTMLPurifier_Strategy_Core
*/
protected $strategy;
/**
* @type HTMLPurifier_Generator
*/
protected $generator;
/**
* Resultant context of last run purification.
* Is an array of contexts if the last called method was purifyArray().
* @type HTMLPurifier_Context
*/
public $context;
/**
* Initializes the purifier.
*
* @param HTMLPurifier_Config|mixed $config Optional HTMLPurifier_Config object
* for all instances of the purifier, if omitted, a default
* configuration is supplied (which can be overridden on a
* per-use basis).
* The parameter can also be any type that
* HTMLPurifier_Config::create() supports.
*/
public function __construct($config = null)
{
$this->config = HTMLPurifier_Config::create($config);
$this->strategy = new HTMLPurifier_Strategy_Core();
}
/**
* Adds a filter to process the output. First come first serve
*
* @param HTMLPurifier_Filter $filter HTMLPurifier_Filter object
*/
public function addFilter($filter)
{
trigger_error(
'HTMLPurifier->addFilter() is deprecated, use configuration directives' .
' in the Filter namespace or Filter.Custom',
E_USER_WARNING
);
$this->filters[] = $filter;
}
/**
* Filters an HTML snippet/document to be XSS-free and standards-compliant.
*
* @param string $html String of HTML to purify
* @param HTMLPurifier_Config $config Config object for this operation,
* if omitted, defaults to the config object specified during this
* object's construction. The parameter can also be any type
* that HTMLPurifier_Config::create() supports.
*
* @return string Purified HTML
*/
public function purify($html, $config = null)
{
// :TODO: make the config merge in, instead of replace
$config = $config ? HTMLPurifier_Config::create($config) : $this->config;
// implementation is partially environment dependant, partially
// configuration dependant
$lexer = HTMLPurifier_Lexer::create($config);
$context = new HTMLPurifier_Context();
// setup HTML generator
$this->generator = new HTMLPurifier_Generator($config, $context);
$context->register('Generator', $this->generator);
// set up global context variables
if ($config->get('Core.CollectErrors')) {
// may get moved out if other facilities use it
$language_factory = HTMLPurifier_LanguageFactory::instance();
$language = $language_factory->create($config, $context);
$context->register('Locale', $language);
$error_collector = new HTMLPurifier_ErrorCollector($context);
$context->register('ErrorCollector', $error_collector);
}
// setup id_accumulator context, necessary due to the fact that
// AttrValidator can be called from many places
$id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context);
$context->register('IDAccumulator', $id_accumulator);
$html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context);
// setup filters
$filter_flags = $config->getBatch('Filter');
$custom_filters = $filter_flags['Custom'];
unset($filter_flags['Custom']);
$filters = array();
foreach ($filter_flags as $filter => $flag) {
if (!$flag) {
continue;
}
if (strpos($filter, '.') !== false) {
continue;
}
$class = "HTMLPurifier_Filter_$filter";
$filters[] = new $class;
}
foreach ($custom_filters as $filter) {
// maybe "HTMLPurifier_Filter_$filter", but be consistent with AutoFormat
$filters[] = $filter;
}
$filters = array_merge($filters, $this->filters);
// maybe prepare(), but later
for ($i = 0, $filter_size = count($filters); $i < $filter_size; $i++) {
$html = $filters[$i]->preFilter($html, $config, $context);
}
// purified HTML
$html =
$this->generator->generateFromTokens(
// list of tokens
$this->strategy->execute(
// list of un-purified tokens
$lexer->tokenizeHTML(
// un-purified HTML
$html,
$config,
$context
),
$config,
$context
)
);
for ($i = $filter_size - 1; $i >= 0; $i--) {
$html = $filters[$i]->postFilter($html, $config, $context);
}
$html = HTMLPurifier_Encoder::convertFromUTF8($html, $config, $context);
$this->context =& $context;
return $html;
}
/**
* Filters an array of HTML snippets
*
* @param string[] $array_of_html Array of html snippets
* @param HTMLPurifier_Config $config Optional config object for this operation.
* See HTMLPurifier::purify() for more details.
*
* @return string[] Array of purified HTML
*/
public function purifyArray($array_of_html, $config = null)
{
$context_array = array();
foreach ($array_of_html as $key => $html) {
$array_of_html[$key] = $this->purify($html, $config);
$context_array[$key] = $this->context;
}
$this->context = $context_array;
return $array_of_html;
}
/**
* Singleton for enforcing just one HTML Purifier in your system
*
* @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype
* HTMLPurifier instance to overload singleton with,
* or HTMLPurifier_Config instance to configure the
* generated version with.
*
* @return HTMLPurifier
*/
public static function instance($prototype = null)
{
if (!self::$instance || $prototype) {
if ($prototype instanceof HTMLPurifier) {
self::$instance = $prototype;
} elseif ($prototype) {
self::$instance = new HTMLPurifier($prototype);
} else {
self::$instance = new HTMLPurifier();
}
}
return self::$instance;
}
/**
* Singleton for enforcing just one HTML Purifier in your system
*
* @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype
* HTMLPurifier instance to overload singleton with,
* or HTMLPurifier_Config instance to configure the
* generated version with.
*
* @return HTMLPurifier
* @note Backwards compatibility, see instance()
*/
public static function getInstance($prototype = null)
{
return HTMLPurifier::instance($prototype);
}
}
// vim: et sw=4 sts=4

View File

@@ -1,226 +0,0 @@
<?php
/**
* @file
* This file was auto-generated by generate-includes.php and includes all of
* the core files required by HTML Purifier. This is a convenience stub that
* includes all files using dirname(__FILE__) and require_once. PLEASE DO NOT
* EDIT THIS FILE, changes will be overwritten the next time the script is run.
*
* Changes to include_path are not necessary.
*/
$__dir = dirname(__FILE__);
require_once $__dir . '/HTMLPurifier.php';
require_once $__dir . '/HTMLPurifier/Arborize.php';
require_once $__dir . '/HTMLPurifier/AttrCollections.php';
require_once $__dir . '/HTMLPurifier/AttrDef.php';
require_once $__dir . '/HTMLPurifier/AttrTransform.php';
require_once $__dir . '/HTMLPurifier/AttrTypes.php';
require_once $__dir . '/HTMLPurifier/AttrValidator.php';
require_once $__dir . '/HTMLPurifier/Bootstrap.php';
require_once $__dir . '/HTMLPurifier/Definition.php';
require_once $__dir . '/HTMLPurifier/CSSDefinition.php';
require_once $__dir . '/HTMLPurifier/ChildDef.php';
require_once $__dir . '/HTMLPurifier/Config.php';
require_once $__dir . '/HTMLPurifier/ConfigSchema.php';
require_once $__dir . '/HTMLPurifier/ContentSets.php';
require_once $__dir . '/HTMLPurifier/Context.php';
require_once $__dir . '/HTMLPurifier/DefinitionCache.php';
require_once $__dir . '/HTMLPurifier/DefinitionCacheFactory.php';
require_once $__dir . '/HTMLPurifier/Doctype.php';
require_once $__dir . '/HTMLPurifier/DoctypeRegistry.php';
require_once $__dir . '/HTMLPurifier/ElementDef.php';
require_once $__dir . '/HTMLPurifier/Encoder.php';
require_once $__dir . '/HTMLPurifier/EntityLookup.php';
require_once $__dir . '/HTMLPurifier/EntityParser.php';
require_once $__dir . '/HTMLPurifier/ErrorCollector.php';
require_once $__dir . '/HTMLPurifier/ErrorStruct.php';
require_once $__dir . '/HTMLPurifier/Exception.php';
require_once $__dir . '/HTMLPurifier/Filter.php';
require_once $__dir . '/HTMLPurifier/Generator.php';
require_once $__dir . '/HTMLPurifier/HTMLDefinition.php';
require_once $__dir . '/HTMLPurifier/HTMLModule.php';
require_once $__dir . '/HTMLPurifier/HTMLModuleManager.php';
require_once $__dir . '/HTMLPurifier/IDAccumulator.php';
require_once $__dir . '/HTMLPurifier/Injector.php';
require_once $__dir . '/HTMLPurifier/Language.php';
require_once $__dir . '/HTMLPurifier/LanguageFactory.php';
require_once $__dir . '/HTMLPurifier/Length.php';
require_once $__dir . '/HTMLPurifier/Lexer.php';
require_once $__dir . '/HTMLPurifier/Node.php';
require_once $__dir . '/HTMLPurifier/PercentEncoder.php';
require_once $__dir . '/HTMLPurifier/PropertyList.php';
require_once $__dir . '/HTMLPurifier/PropertyListIterator.php';
require_once $__dir . '/HTMLPurifier/Queue.php';
require_once $__dir . '/HTMLPurifier/Strategy.php';
require_once $__dir . '/HTMLPurifier/StringHash.php';
require_once $__dir . '/HTMLPurifier/StringHashParser.php';
require_once $__dir . '/HTMLPurifier/TagTransform.php';
require_once $__dir . '/HTMLPurifier/Token.php';
require_once $__dir . '/HTMLPurifier/TokenFactory.php';
require_once $__dir . '/HTMLPurifier/URI.php';
require_once $__dir . '/HTMLPurifier/URIDefinition.php';
require_once $__dir . '/HTMLPurifier/URIFilter.php';
require_once $__dir . '/HTMLPurifier/URIParser.php';
require_once $__dir . '/HTMLPurifier/URIScheme.php';
require_once $__dir . '/HTMLPurifier/URISchemeRegistry.php';
require_once $__dir . '/HTMLPurifier/UnitConverter.php';
require_once $__dir . '/HTMLPurifier/VarParser.php';
require_once $__dir . '/HTMLPurifier/VarParserException.php';
require_once $__dir . '/HTMLPurifier/Zipper.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Clone.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Enum.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Integer.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Lang.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Switch.php';
require_once $__dir . '/HTMLPurifier/AttrDef/Text.php';
require_once $__dir . '/HTMLPurifier/AttrDef/URI.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Number.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/AlphaValue.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Background.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Border.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Color.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Composite.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Filter.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Font.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/FontFamily.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Ident.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Length.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/ListStyle.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Multiple.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Percentage.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/TextDecoration.php';
require_once $__dir . '/HTMLPurifier/AttrDef/CSS/URI.php';
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Bool.php';
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Nmtokens.php';
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Class.php';
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Color.php';
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/FrameTarget.php';
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/ID.php';
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Pixels.php';
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Length.php';
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/LinkTypes.php';
require_once $__dir . '/HTMLPurifier/AttrDef/HTML/MultiLength.php';
require_once $__dir . '/HTMLPurifier/AttrDef/URI/Email.php';
require_once $__dir . '/HTMLPurifier/AttrDef/URI/Host.php';
require_once $__dir . '/HTMLPurifier/AttrDef/URI/IPv4.php';
require_once $__dir . '/HTMLPurifier/AttrDef/URI/IPv6.php';
require_once $__dir . '/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Background.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/BdoDir.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/BgColor.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/BoolToCSS.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Border.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/EnumToCSS.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/ImgRequired.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/ImgSpace.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Input.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Lang.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Length.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Name.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/NameSync.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Nofollow.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeEmbed.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeObject.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/SafeParam.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/ScriptRequired.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/TargetBlank.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/TargetNoreferrer.php';
require_once $__dir . '/HTMLPurifier/AttrTransform/Textarea.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Chameleon.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Custom.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Empty.php';
require_once $__dir . '/HTMLPurifier/ChildDef/List.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Required.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Optional.php';
require_once $__dir . '/HTMLPurifier/ChildDef/StrictBlockquote.php';
require_once $__dir . '/HTMLPurifier/ChildDef/Table.php';
require_once $__dir . '/HTMLPurifier/DefinitionCache/Decorator.php';
require_once $__dir . '/HTMLPurifier/DefinitionCache/Null.php';
require_once $__dir . '/HTMLPurifier/DefinitionCache/Serializer.php';
require_once $__dir . '/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php';
require_once $__dir . '/HTMLPurifier/DefinitionCache/Decorator/Memory.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Bdo.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/CommonAttributes.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Edit.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Forms.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Hypertext.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Iframe.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Image.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Legacy.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/List.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Name.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Nofollow.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Object.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Presentation.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Proprietary.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Ruby.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/SafeEmbed.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/SafeObject.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/SafeScripting.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Scripting.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/StyleAttribute.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tables.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Target.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/TargetBlank.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/TargetNoreferrer.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Text.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/XMLCommonAttributes.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Name.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Proprietary.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Strict.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Transitional.php';
require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/XHTML.php';
require_once $__dir . '/HTMLPurifier/Injector/AutoParagraph.php';
require_once $__dir . '/HTMLPurifier/Injector/DisplayLinkURI.php';
require_once $__dir . '/HTMLPurifier/Injector/Linkify.php';
require_once $__dir . '/HTMLPurifier/Injector/PurifierLinkify.php';
require_once $__dir . '/HTMLPurifier/Injector/RemoveEmpty.php';
require_once $__dir . '/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php';
require_once $__dir . '/HTMLPurifier/Injector/SafeObject.php';
require_once $__dir . '/HTMLPurifier/Lexer/DOMLex.php';
require_once $__dir . '/HTMLPurifier/Lexer/DirectLex.php';
require_once $__dir . '/HTMLPurifier/Node/Comment.php';
require_once $__dir . '/HTMLPurifier/Node/Element.php';
require_once $__dir . '/HTMLPurifier/Node/Text.php';
require_once $__dir . '/HTMLPurifier/Strategy/Composite.php';
require_once $__dir . '/HTMLPurifier/Strategy/Core.php';
require_once $__dir . '/HTMLPurifier/Strategy/FixNesting.php';
require_once $__dir . '/HTMLPurifier/Strategy/MakeWellFormed.php';
require_once $__dir . '/HTMLPurifier/Strategy/RemoveForeignElements.php';
require_once $__dir . '/HTMLPurifier/Strategy/ValidateAttributes.php';
require_once $__dir . '/HTMLPurifier/TagTransform/Font.php';
require_once $__dir . '/HTMLPurifier/TagTransform/Simple.php';
require_once $__dir . '/HTMLPurifier/Token/Comment.php';
require_once $__dir . '/HTMLPurifier/Token/Tag.php';
require_once $__dir . '/HTMLPurifier/Token/Empty.php';
require_once $__dir . '/HTMLPurifier/Token/End.php';
require_once $__dir . '/HTMLPurifier/Token/Start.php';
require_once $__dir . '/HTMLPurifier/Token/Text.php';
require_once $__dir . '/HTMLPurifier/URIFilter/DisableExternal.php';
require_once $__dir . '/HTMLPurifier/URIFilter/DisableExternalResources.php';
require_once $__dir . '/HTMLPurifier/URIFilter/DisableResources.php';
require_once $__dir . '/HTMLPurifier/URIFilter/HostBlacklist.php';
require_once $__dir . '/HTMLPurifier/URIFilter/MakeAbsolute.php';
require_once $__dir . '/HTMLPurifier/URIFilter/Munge.php';
require_once $__dir . '/HTMLPurifier/URIFilter/SafeIframe.php';
require_once $__dir . '/HTMLPurifier/URIScheme/data.php';
require_once $__dir . '/HTMLPurifier/URIScheme/file.php';
require_once $__dir . '/HTMLPurifier/URIScheme/ftp.php';
require_once $__dir . '/HTMLPurifier/URIScheme/http.php';
require_once $__dir . '/HTMLPurifier/URIScheme/https.php';
require_once $__dir . '/HTMLPurifier/URIScheme/mailto.php';
require_once $__dir . '/HTMLPurifier/URIScheme/news.php';
require_once $__dir . '/HTMLPurifier/URIScheme/nntp.php';
require_once $__dir . '/HTMLPurifier/URIScheme/tel.php';
require_once $__dir . '/HTMLPurifier/VarParser/Flexible.php';
require_once $__dir . '/HTMLPurifier/VarParser/Native.php';

View File

@@ -1,71 +0,0 @@
<?php
/**
* Converts a stream of HTMLPurifier_Token into an HTMLPurifier_Node,
* and back again.
*
* @note This transformation is not an equivalence. We mutate the input
* token stream to make it so; see all [MUT] markers in code.
*/
class HTMLPurifier_Arborize
{
public static function arborize($tokens, $config, $context) {
$definition = $config->getHTMLDefinition();
$parent = new HTMLPurifier_Token_Start($definition->info_parent);
$stack = array($parent->toNode());
foreach ($tokens as $token) {
$token->skip = null; // [MUT]
$token->carryover = null; // [MUT]
if ($token instanceof HTMLPurifier_Token_End) {
$token->start = null; // [MUT]
$r = array_pop($stack);
assert($r->name === $token->name);
assert(empty($token->attr));
$r->endCol = $token->col;
$r->endLine = $token->line;
$r->endArmor = $token->armor;
continue;
}
$node = $token->toNode();
$stack[count($stack)-1]->children[] = $node;
if ($token instanceof HTMLPurifier_Token_Start) {
$stack[] = $node;
}
}
assert(count($stack) == 1);
return $stack[0];
}
public static function flatten($node, $config, $context) {
$level = 0;
$nodes = array($level => new HTMLPurifier_Queue(array($node)));
$closingTokens = array();
$tokens = array();
do {
while (!$nodes[$level]->isEmpty()) {
$node = $nodes[$level]->shift(); // FIFO
list($start, $end) = $node->toTokenPair();
if ($level > 0) {
$tokens[] = $start;
}
if ($end !== NULL) {
$closingTokens[$level][] = $end;
}
if ($node instanceof HTMLPurifier_Node_Element) {
$level++;
$nodes[$level] = new HTMLPurifier_Queue();
foreach ($node->children as $childNode) {
$nodes[$level]->push($childNode);
}
}
}
$level--;
if ($level && isset($closingTokens[$level])) {
while ($token = array_pop($closingTokens[$level])) {
$tokens[] = $token;
}
}
} while ($level > 0);
return $tokens;
}
}

View File

@@ -1,148 +0,0 @@
<?php
/**
* Defines common attribute collections that modules reference
*/
class HTMLPurifier_AttrCollections
{
/**
* Associative array of attribute collections, indexed by name.
* @type array
*/
public $info = array();
/**
* Performs all expansions on internal data for use by other inclusions
* It also collects all attribute collection extensions from
* modules
* @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
* @param HTMLPurifier_HTMLModule[] $modules Hash array of HTMLPurifier_HTMLModule members
*/
public function __construct($attr_types, $modules)
{
$this->doConstruct($attr_types, $modules);
}
public function doConstruct($attr_types, $modules)
{
// load extensions from the modules
foreach ($modules as $module) {
foreach ($module->attr_collections as $coll_i => $coll) {
if (!isset($this->info[$coll_i])) {
$this->info[$coll_i] = array();
}
foreach ($coll as $attr_i => $attr) {
if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
// merge in includes
$this->info[$coll_i][$attr_i] = array_merge(
$this->info[$coll_i][$attr_i],
$attr
);
continue;
}
$this->info[$coll_i][$attr_i] = $attr;
}
}
}
// perform internal expansions and inclusions
foreach ($this->info as $name => $attr) {
// merge attribute collections that include others
$this->performInclusions($this->info[$name]);
// replace string identifiers with actual attribute objects
$this->expandIdentifiers($this->info[$name], $attr_types);
}
}
/**
* Takes a reference to an attribute associative array and performs
* all inclusions specified by the zero index.
* @param array &$attr Reference to attribute array
*/
public function performInclusions(&$attr)
{
if (!isset($attr[0])) {
return;
}
$merge = $attr[0];
$seen = array(); // recursion guard
// loop through all the inclusions
for ($i = 0; isset($merge[$i]); $i++) {
if (isset($seen[$merge[$i]])) {
continue;
}
$seen[$merge[$i]] = true;
// foreach attribute of the inclusion, copy it over
if (!isset($this->info[$merge[$i]])) {
continue;
}
foreach ($this->info[$merge[$i]] as $key => $value) {
if (isset($attr[$key])) {
continue;
} // also catches more inclusions
$attr[$key] = $value;
}
if (isset($this->info[$merge[$i]][0])) {
// recursion
$merge = array_merge($merge, $this->info[$merge[$i]][0]);
}
}
unset($attr[0]);
}
/**
* Expands all string identifiers in an attribute array by replacing
* them with the appropriate values inside HTMLPurifier_AttrTypes
* @param array &$attr Reference to attribute array
* @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
*/
public function expandIdentifiers(&$attr, $attr_types)
{
// because foreach will process new elements we add, make sure we
// skip duplicates
$processed = array();
foreach ($attr as $def_i => $def) {
// skip inclusions
if ($def_i === 0) {
continue;
}
if (isset($processed[$def_i])) {
continue;
}
// determine whether or not attribute is required
if ($required = (strpos($def_i, '*') !== false)) {
// rename the definition
unset($attr[$def_i]);
$def_i = trim($def_i, '*');
$attr[$def_i] = $def;
}
$processed[$def_i] = true;
// if we've already got a literal object, move on
if (is_object($def)) {
// preserve previous required
$attr[$def_i]->required = ($required || $attr[$def_i]->required);
continue;
}
if ($def === false) {
unset($attr[$def_i]);
continue;
}
if ($t = $attr_types->get($def)) {
$attr[$def_i] = $t;
$attr[$def_i]->required = $required;
} else {
unset($attr[$def_i]);
}
}
}
}
// vim: et sw=4 sts=4

View File

@@ -1,138 +0,0 @@
<?php
/**
* Base class for all validating attribute definitions.
*
* This family of classes forms the core for not only HTML attribute validation,
* but also any sort of string that needs to be validated or cleaned (which
* means CSS properties and composite definitions are defined here too).
* Besides defining (through code) what precisely makes the string valid,
* subclasses are also responsible for cleaning the code if possible.
*/
abstract class HTMLPurifier_AttrDef
{
/**
* Tells us whether or not an HTML attribute is minimized.
* Has no meaning in other contexts.
* @type bool
*/
public $minimized = false;
/**
* Tells us whether or not an HTML attribute is required.
* Has no meaning in other contexts
* @type bool
*/
public $required = false;
/**
* Validates and cleans passed string according to a definition.
*
* @param string $string String to be validated and cleaned.
* @param HTMLPurifier_Config $config Mandatory HTMLPurifier_Config object.
* @param HTMLPurifier_Context $context Mandatory HTMLPurifier_Context object.
*/
abstract public function validate($string, $config, $context);
/**
* Convenience method that parses a string as if it were CDATA.
*
* This method process a string in the manner specified at
* <http://www.w3.org/TR/html4/types.html#h-6.2> by removing
* leading and trailing whitespace, ignoring line feeds, and replacing
* carriage returns and tabs with spaces. While most useful for HTML
* attributes specified as CDATA, it can also be applied to most CSS
* values.
*
* @note This method is not entirely standards compliant, as trim() removes
* more types of whitespace than specified in the spec. In practice,
* this is rarely a problem, as those extra characters usually have
* already been removed by HTMLPurifier_Encoder.
*
* @warning This processing is inconsistent with XML's whitespace handling
* as specified by section 3.3.3 and referenced XHTML 1.0 section
* 4.7. However, note that we are NOT necessarily
* parsing XML, thus, this behavior may still be correct. We
* assume that newlines have been normalized.
*/
public function parseCDATA($string)
{
$string = trim($string);
$string = str_replace(array("\n", "\t", "\r"), ' ', $string);
return $string;
}
/**
* Factory method for creating this class from a string.
* @param string $string String construction info
* @return HTMLPurifier_AttrDef Created AttrDef object corresponding to $string
*/
public function make($string)
{
// default implementation, return a flyweight of this object.
// If $string has an effect on the returned object (i.e. you
// need to overload this method), it is best
// to clone or instantiate new copies. (Instantiation is safer.)
return $this;
}
/**
* Removes spaces from rgb(0, 0, 0) so that shorthand CSS properties work
* properly. THIS IS A HACK!
* @param string $string a CSS colour definition
* @return string
*/
protected function mungeRgb($string)
{
return preg_replace('/rgb\((\d+)\s*,\s*(\d+)\s*,\s*(\d+)\)/', 'rgb(\1,\2,\3)', $string);
}
/**
* Parses a possibly escaped CSS string and returns the "pure"
* version of it.
*/
protected function expandCSSEscape($string)
{
// flexibly parse it
$ret = '';
for ($i = 0, $c = strlen($string); $i < $c; $i++) {
if ($string[$i] === '\\') {
$i++;
if ($i >= $c) {
$ret .= '\\';
break;
}
if (ctype_xdigit($string[$i])) {
$code = $string[$i];
for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) {
if (!ctype_xdigit($string[$i])) {
break;
}
$code .= $string[$i];
}
// We have to be extremely careful when adding
// new characters, to make sure we're not breaking
// the encoding.
$char = HTMLPurifier_Encoder::unichr(hexdec($code));
if (HTMLPurifier_Encoder::cleanUTF8($char) === '') {
continue;
}
$ret .= $char;
if ($i < $c && trim($string[$i]) !== '') {
$i--;
}
continue;
}
if ($string[$i] === "\n") {
continue;
}
}
$ret .= $string[$i];
}
return $ret;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,111 +0,0 @@
<?php
/**
* Validates the HTML attribute style, otherwise known as CSS.
* @note We don't implement the whole CSS specification, so it might be
* difficult to reuse this component in the context of validating
* actual stylesheet declarations.
* @note If we were really serious about validating the CSS, we would
* tokenize the styles and then parse the tokens. Obviously, we
* are not doing that. Doing that could seriously harm performance,
* but would make these components a lot more viable for a CSS
* filtering solution.
*/
class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
{
/**
* @param string $css
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($css, $config, $context)
{
$css = $this->parseCDATA($css);
$definition = $config->getCSSDefinition();
$allow_duplicates = $config->get("CSS.AllowDuplicates");
// we're going to break the spec and explode by semicolons.
// This is because semicolon rarely appears in escaped form
// Doing this is generally flaky but fast
// IT MIGHT APPEAR IN URIs, see HTMLPurifier_AttrDef_CSSURI
// for details
$declarations = explode(';', $css);
$propvalues = array();
$new_declarations = '';
/**
* Name of the current CSS property being validated.
*/
$property = false;
$context->register('CurrentCSSProperty', $property);
foreach ($declarations as $declaration) {
if (!$declaration) {
continue;
}
if (!strpos($declaration, ':')) {
continue;
}
list($property, $value) = explode(':', $declaration, 2);
$property = trim($property);
$value = trim($value);
$ok = false;
do {
if (isset($definition->info[$property])) {
$ok = true;
break;
}
if (ctype_lower($property)) {
break;
}
$property = strtolower($property);
if (isset($definition->info[$property])) {
$ok = true;
break;
}
} while (0);
if (!$ok) {
continue;
}
// inefficient call, since the validator will do this again
if (strtolower(trim($value)) !== 'inherit') {
// inherit works for everything (but only on the base property)
$result = $definition->info[$property]->validate(
$value,
$config,
$context
);
} else {
$result = 'inherit';
}
if ($result === false) {
continue;
}
if ($allow_duplicates) {
$new_declarations .= "$property:$result;";
} else {
$propvalues[$property] = $result;
}
}
$context->destroy('CurrentCSSProperty');
// procedure does not write the new CSS simultaneously, so it's
// slightly inefficient, but it's the only way of getting rid of
// duplicates. Perhaps config to optimize it, but not now.
foreach ($propvalues as $prop => $value) {
$new_declarations .= "$prop:$value;";
}
return $new_declarations ? $new_declarations : false;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,34 +0,0 @@
<?php
class HTMLPurifier_AttrDef_CSS_AlphaValue extends HTMLPurifier_AttrDef_CSS_Number
{
public function __construct()
{
parent::__construct(false); // opacity is non-negative, but we will clamp it
}
/**
* @param string $number
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return string
*/
public function validate($number, $config, $context)
{
$result = parent::validate($number, $config, $context);
if ($result === false) {
return $result;
}
$float = (float)$result;
if ($float < 0.0) {
$result = '0';
}
if ($float > 1.0) {
$result = '1';
}
return $result;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,111 +0,0 @@
<?php
/**
* Validates shorthand CSS property background.
* @warning Does not support url tokens that have internal spaces.
*/
class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
{
/**
* Local copy of component validators.
* @type HTMLPurifier_AttrDef[]
* @note See HTMLPurifier_AttrDef_Font::$info for a similar impl.
*/
protected $info;
/**
* @param HTMLPurifier_Config $config
*/
public function __construct($config)
{
$def = $config->getCSSDefinition();
$this->info['background-color'] = $def->info['background-color'];
$this->info['background-image'] = $def->info['background-image'];
$this->info['background-repeat'] = $def->info['background-repeat'];
$this->info['background-attachment'] = $def->info['background-attachment'];
$this->info['background-position'] = $def->info['background-position'];
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
// regular pre-processing
$string = $this->parseCDATA($string);
if ($string === '') {
return false;
}
// munge rgb() decl if necessary
$string = $this->mungeRgb($string);
// assumes URI doesn't have spaces in it
$bits = explode(' ', $string); // bits to process
$caught = array();
$caught['color'] = false;
$caught['image'] = false;
$caught['repeat'] = false;
$caught['attachment'] = false;
$caught['position'] = false;
$i = 0; // number of catches
foreach ($bits as $bit) {
if ($bit === '') {
continue;
}
foreach ($caught as $key => $status) {
if ($key != 'position') {
if ($status !== false) {
continue;
}
$r = $this->info['background-' . $key]->validate($bit, $config, $context);
} else {
$r = $bit;
}
if ($r === false) {
continue;
}
if ($key == 'position') {
if ($caught[$key] === false) {
$caught[$key] = '';
}
$caught[$key] .= $r . ' ';
} else {
$caught[$key] = $r;
}
$i++;
break;
}
}
if (!$i) {
return false;
}
if ($caught['position'] !== false) {
$caught['position'] = $this->info['background-position']->
validate($caught['position'], $config, $context);
}
$ret = array();
foreach ($caught as $value) {
if ($value === false) {
continue;
}
$ret[] = $value;
}
if (empty($ret)) {
return false;
}
return implode(' ', $ret);
}
}
// vim: et sw=4 sts=4

View File

@@ -1,157 +0,0 @@
<?php
/* W3C says:
[ // adjective and number must be in correct order, even if
// you could switch them without introducing ambiguity.
// some browsers support that syntax
[
<percentage> | <length> | left | center | right
]
[
<percentage> | <length> | top | center | bottom
]?
] |
[ // this signifies that the vertical and horizontal adjectives
// can be arbitrarily ordered, however, there can only be two,
// one of each, or none at all
[
left | center | right
] ||
[
top | center | bottom
]
]
top, left = 0%
center, (none) = 50%
bottom, right = 100%
*/
/* QuirksMode says:
keyword + length/percentage must be ordered correctly, as per W3C
Internet Explorer and Opera, however, support arbitrary ordering. We
should fix it up.
Minor issue though, not strictly necessary.
*/
// control freaks may appreciate the ability to convert these to
// percentages or something, but it's not necessary
/**
* Validates the value of background-position.
*/
class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
{
/**
* @type HTMLPurifier_AttrDef_CSS_Length
*/
protected $length;
/**
* @type HTMLPurifier_AttrDef_CSS_Percentage
*/
protected $percentage;
public function __construct()
{
$this->length = new HTMLPurifier_AttrDef_CSS_Length();
$this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage();
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = $this->parseCDATA($string);
$bits = explode(' ', $string);
$keywords = array();
$keywords['h'] = false; // left, right
$keywords['v'] = false; // top, bottom
$keywords['ch'] = false; // center (first word)
$keywords['cv'] = false; // center (second word)
$measures = array();
$i = 0;
$lookup = array(
'top' => 'v',
'bottom' => 'v',
'left' => 'h',
'right' => 'h',
'center' => 'c'
);
foreach ($bits as $bit) {
if ($bit === '') {
continue;
}
// test for keyword
$lbit = ctype_lower($bit) ? $bit : strtolower($bit);
if (isset($lookup[$lbit])) {
$status = $lookup[$lbit];
if ($status == 'c') {
if ($i == 0) {
$status = 'ch';
} else {
$status = 'cv';
}
}
$keywords[$status] = $lbit;
$i++;
}
// test for length
$r = $this->length->validate($bit, $config, $context);
if ($r !== false) {
$measures[] = $r;
$i++;
}
// test for percentage
$r = $this->percentage->validate($bit, $config, $context);
if ($r !== false) {
$measures[] = $r;
$i++;
}
}
if (!$i) {
return false;
} // no valid values were caught
$ret = array();
// first keyword
if ($keywords['h']) {
$ret[] = $keywords['h'];
} elseif ($keywords['ch']) {
$ret[] = $keywords['ch'];
$keywords['cv'] = false; // prevent re-use: center = center center
} elseif (count($measures)) {
$ret[] = array_shift($measures);
}
if ($keywords['v']) {
$ret[] = $keywords['v'];
} elseif ($keywords['cv']) {
$ret[] = $keywords['cv'];
} elseif (count($measures)) {
$ret[] = array_shift($measures);
}
if (empty($ret)) {
return false;
}
return implode(' ', $ret);
}
}
// vim: et sw=4 sts=4

View File

@@ -1,56 +0,0 @@
<?php
/**
* Validates the border property as defined by CSS.
*/
class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef
{
/**
* Local copy of properties this property is shorthand for.
* @type HTMLPurifier_AttrDef[]
*/
protected $info = array();
/**
* @param HTMLPurifier_Config $config
*/
public function __construct($config)
{
$def = $config->getCSSDefinition();
$this->info['border-width'] = $def->info['border-width'];
$this->info['border-style'] = $def->info['border-style'];
$this->info['border-top-color'] = $def->info['border-top-color'];
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = $this->parseCDATA($string);
$string = $this->mungeRgb($string);
$bits = explode(' ', $string);
$done = array(); // segments we've finished
$ret = ''; // return value
foreach ($bits as $bit) {
foreach ($this->info as $propname => $validator) {
if (isset($done[$propname])) {
continue;
}
$r = $validator->validate($bit, $config, $context);
if ($r !== false) {
$ret .= $r . ' ';
$done[$propname] = true;
break;
}
}
}
return rtrim($ret);
}
}
// vim: et sw=4 sts=4

View File

@@ -1,105 +0,0 @@
<?php
/**
* Validates Color as defined by CSS.
*/
class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
{
/**
* @param string $color
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($color, $config, $context)
{
static $colors = null;
if ($colors === null) {
$colors = $config->get('Core.ColorKeywords');
}
$color = trim($color);
if ($color === '') {
return false;
}
$lower = strtolower($color);
if (isset($colors[$lower])) {
return $colors[$lower];
}
if (strpos($color, 'rgb(') !== false) {
// rgb literal handling
$length = strlen($color);
if (strpos($color, ')') !== $length - 1) {
return false;
}
$triad = substr($color, 4, $length - 4 - 1);
$parts = explode(',', $triad);
if (count($parts) !== 3) {
return false;
}
$type = false; // to ensure that they're all the same type
$new_parts = array();
foreach ($parts as $part) {
$part = trim($part);
if ($part === '') {
return false;
}
$length = strlen($part);
if ($part[$length - 1] === '%') {
// handle percents
if (!$type) {
$type = 'percentage';
} elseif ($type !== 'percentage') {
return false;
}
$num = (float)substr($part, 0, $length - 1);
if ($num < 0) {
$num = 0;
}
if ($num > 100) {
$num = 100;
}
$new_parts[] = "$num%";
} else {
// handle integers
if (!$type) {
$type = 'integer';
} elseif ($type !== 'integer') {
return false;
}
$num = (int)$part;
if ($num < 0) {
$num = 0;
}
if ($num > 255) {
$num = 255;
}
$new_parts[] = (string)$num;
}
}
$new_triad = implode(',', $new_parts);
$color = "rgb($new_triad)";
} else {
// hexadecimal handling
if ($color[0] === '#') {
$hex = substr($color, 1);
} else {
$hex = $color;
$color = '#' . $color;
}
$length = strlen($hex);
if ($length !== 3 && $length !== 6) {
return false;
}
if (!ctype_xdigit($hex)) {
return false;
}
}
return $color;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,48 +0,0 @@
<?php
/**
* Allows multiple validators to attempt to validate attribute.
*
* Composite is just what it sounds like: a composite of many validators.
* This means that multiple HTMLPurifier_AttrDef objects will have a whack
* at the string. If one of them passes, that's what is returned. This is
* especially useful for CSS values, which often are a choice between
* an enumerated set of predefined values or a flexible data type.
*/
class HTMLPurifier_AttrDef_CSS_Composite extends HTMLPurifier_AttrDef
{
/**
* List of objects that may process strings.
* @type HTMLPurifier_AttrDef[]
* @todo Make protected
*/
public $defs;
/**
* @param HTMLPurifier_AttrDef[] $defs List of HTMLPurifier_AttrDef objects
*/
public function __construct($defs)
{
$this->defs = $defs;
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
foreach ($this->defs as $i => $def) {
$result = $this->defs[$i]->validate($string, $config, $context);
if ($result !== false) {
return $result;
}
}
return false;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,44 +0,0 @@
<?php
/**
* Decorator which enables CSS properties to be disabled for specific elements.
*/
class HTMLPurifier_AttrDef_CSS_DenyElementDecorator extends HTMLPurifier_AttrDef
{
/**
* @type HTMLPurifier_AttrDef
*/
public $def;
/**
* @type string
*/
public $element;
/**
* @param HTMLPurifier_AttrDef $def Definition to wrap
* @param string $element Element to deny
*/
public function __construct($def, $element)
{
$this->def = $def;
$this->element = $element;
}
/**
* Checks if CurrentToken is set and equal to $this->element
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$token = $context->get('CurrentToken', true);
if ($token && $token->name == $this->element) {
return false;
}
return $this->def->validate($string, $config, $context);
}
}
// vim: et sw=4 sts=4

View File

@@ -1,77 +0,0 @@
<?php
/**
* Microsoft's proprietary filter: CSS property
* @note Currently supports the alpha filter. In the future, this will
* probably need an extensible framework
*/
class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef
{
/**
* @type HTMLPurifier_AttrDef_Integer
*/
protected $intValidator;
public function __construct()
{
$this->intValidator = new HTMLPurifier_AttrDef_Integer();
}
/**
* @param string $value
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($value, $config, $context)
{
$value = $this->parseCDATA($value);
if ($value === 'none') {
return $value;
}
// if we looped this we could support multiple filters
$function_length = strcspn($value, '(');
$function = trim(substr($value, 0, $function_length));
if ($function !== 'alpha' &&
$function !== 'Alpha' &&
$function !== 'progid:DXImageTransform.Microsoft.Alpha'
) {
return false;
}
$cursor = $function_length + 1;
$parameters_length = strcspn($value, ')', $cursor);
$parameters = substr($value, $cursor, $parameters_length);
$params = explode(',', $parameters);
$ret_params = array();
$lookup = array();
foreach ($params as $param) {
list($key, $value) = explode('=', $param);
$key = trim($key);
$value = trim($value);
if (isset($lookup[$key])) {
continue;
}
if ($key !== 'opacity') {
continue;
}
$value = $this->intValidator->validate($value, $config, $context);
if ($value === false) {
continue;
}
$int = (int)$value;
if ($int > 100) {
$value = '100';
}
if ($int < 0) {
$value = '0';
}
$ret_params[] = "$key=$value";
$lookup[$key] = true;
}
$ret_parameters = implode(',', $ret_params);
$ret_function = "$function($ret_parameters)";
return $ret_function;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,176 +0,0 @@
<?php
/**
* Validates shorthand CSS property font.
*/
class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
{
/**
* Local copy of validators
* @type HTMLPurifier_AttrDef[]
* @note If we moved specific CSS property definitions to their own
* classes instead of having them be assembled at run time by
* CSSDefinition, this wouldn't be necessary. We'd instantiate
* our own copies.
*/
protected $info = array();
/**
* @param HTMLPurifier_Config $config
*/
public function __construct($config)
{
$def = $config->getCSSDefinition();
$this->info['font-style'] = $def->info['font-style'];
$this->info['font-variant'] = $def->info['font-variant'];
$this->info['font-weight'] = $def->info['font-weight'];
$this->info['font-size'] = $def->info['font-size'];
$this->info['line-height'] = $def->info['line-height'];
$this->info['font-family'] = $def->info['font-family'];
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
static $system_fonts = array(
'caption' => true,
'icon' => true,
'menu' => true,
'message-box' => true,
'small-caption' => true,
'status-bar' => true
);
// regular pre-processing
$string = $this->parseCDATA($string);
if ($string === '') {
return false;
}
// check if it's one of the keywords
$lowercase_string = strtolower($string);
if (isset($system_fonts[$lowercase_string])) {
return $lowercase_string;
}
$bits = explode(' ', $string); // bits to process
$stage = 0; // this indicates what we're looking for
$caught = array(); // which stage 0 properties have we caught?
$stage_1 = array('font-style', 'font-variant', 'font-weight');
$final = ''; // output
for ($i = 0, $size = count($bits); $i < $size; $i++) {
if ($bits[$i] === '') {
continue;
}
switch ($stage) {
case 0: // attempting to catch font-style, font-variant or font-weight
foreach ($stage_1 as $validator_name) {
if (isset($caught[$validator_name])) {
continue;
}
$r = $this->info[$validator_name]->validate(
$bits[$i],
$config,
$context
);
if ($r !== false) {
$final .= $r . ' ';
$caught[$validator_name] = true;
break;
}
}
// all three caught, continue on
if (count($caught) >= 3) {
$stage = 1;
}
if ($r !== false) {
break;
}
case 1: // attempting to catch font-size and perhaps line-height
$found_slash = false;
if (strpos($bits[$i], '/') !== false) {
list($font_size, $line_height) =
explode('/', $bits[$i]);
if ($line_height === '') {
// ooh, there's a space after the slash!
$line_height = false;
$found_slash = true;
}
} else {
$font_size = $bits[$i];
$line_height = false;
}
$r = $this->info['font-size']->validate(
$font_size,
$config,
$context
);
if ($r !== false) {
$final .= $r;
// attempt to catch line-height
if ($line_height === false) {
// we need to scroll forward
for ($j = $i + 1; $j < $size; $j++) {
if ($bits[$j] === '') {
continue;
}
if ($bits[$j] === '/') {
if ($found_slash) {
return false;
} else {
$found_slash = true;
continue;
}
}
$line_height = $bits[$j];
break;
}
} else {
// slash already found
$found_slash = true;
$j = $i;
}
if ($found_slash) {
$i = $j;
$r = $this->info['line-height']->validate(
$line_height,
$config,
$context
);
if ($r !== false) {
$final .= '/' . $r;
}
}
$final .= ' ';
$stage = 2;
break;
}
return false;
case 2: // attempting to catch font-family
$font_family =
implode(' ', array_slice($bits, $i, $size - $i));
$r = $this->info['font-family']->validate(
$font_family,
$config,
$context
);
if ($r !== false) {
$final .= $r . ' ';
// processing completed successfully
return rtrim($final);
}
return false;
}
}
return false;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,219 +0,0 @@
<?php
/**
* Validates a font family list according to CSS spec
*/
class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
{
protected $mask = null;
public function __construct()
{
$this->mask = '_- ';
for ($c = 'a'; $c <= 'z'; $c++) {
$this->mask .= $c;
}
for ($c = 'A'; $c <= 'Z'; $c++) {
$this->mask .= $c;
}
for ($c = '0'; $c <= '9'; $c++) {
$this->mask .= $c;
} // cast-y, but should be fine
// special bytes used by UTF-8
for ($i = 0x80; $i <= 0xFF; $i++) {
// We don't bother excluding invalid bytes in this range,
// because the our restriction of well-formed UTF-8 will
// prevent these from ever occurring.
$this->mask .= chr($i);
}
/*
PHP's internal strcspn implementation is
O(length of string * length of mask), making it inefficient
for large masks. However, it's still faster than
preg_match 8)
for (p = s1;;) {
spanp = s2;
do {
if (*spanp == c || p == s1_end) {
return p - s1;
}
} while (spanp++ < (s2_end - 1));
c = *++p;
}
*/
// possible optimization: invert the mask.
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
static $generic_names = array(
'serif' => true,
'sans-serif' => true,
'monospace' => true,
'fantasy' => true,
'cursive' => true
);
$allowed_fonts = $config->get('CSS.AllowedFonts');
// assume that no font names contain commas in them
$fonts = explode(',', $string);
$final = '';
foreach ($fonts as $font) {
$font = trim($font);
if ($font === '') {
continue;
}
// match a generic name
if (isset($generic_names[$font])) {
if ($allowed_fonts === null || isset($allowed_fonts[$font])) {
$final .= $font . ', ';
}
continue;
}
// match a quoted name
if ($font[0] === '"' || $font[0] === "'") {
$length = strlen($font);
if ($length <= 2) {
continue;
}
$quote = $font[0];
if ($font[$length - 1] !== $quote) {
continue;
}
$font = substr($font, 1, $length - 2);
}
$font = $this->expandCSSEscape($font);
// $font is a pure representation of the font name
if ($allowed_fonts !== null && !isset($allowed_fonts[$font])) {
continue;
}
if (ctype_alnum($font) && $font !== '') {
// very simple font, allow it in unharmed
$final .= $font . ', ';
continue;
}
// bugger out on whitespace. form feed (0C) really
// shouldn't show up regardless
$font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font);
// Here, there are various classes of characters which need
// to be treated differently:
// - Alphanumeric characters are essentially safe. We
// handled these above.
// - Spaces require quoting, though most parsers will do
// the right thing if there aren't any characters that
// can be misinterpreted
// - Dashes rarely occur, but they fairly unproblematic
// for parsing/rendering purposes.
// The above characters cover the majority of Western font
// names.
// - Arbitrary Unicode characters not in ASCII. Because
// most parsers give little thought to Unicode, treatment
// of these codepoints is basically uniform, even for
// punctuation-like codepoints. These characters can
// show up in non-Western pages and are supported by most
// major browsers, for example: " 明朝" is a
// legitimate font-name
// <http://ja.wikipedia.org/wiki/MS_明朝>. See
// the CSS3 spec for more examples:
// <http://www.w3.org/TR/2011/WD-css3-fonts-20110324/localizedfamilynames.png>
// You can see live samples of these on the Internet:
// <http://www.google.co.jp/search?q=font-family++明朝|ゴシック>
// However, most of these fonts have ASCII equivalents:
// for example, 'MS Mincho', and it's considered
// professional to use ASCII font names instead of
// Unicode font names. Thanks Takeshi Terada for
// providing this information.
// The following characters, to my knowledge, have not been
// used to name font names.
// - Single quote. While theoretically you might find a
// font name that has a single quote in its name (serving
// as an apostrophe, e.g. Dave's Scribble), I haven't
// been able to find any actual examples of this.
// Internet Explorer's cssText translation (which I
// believe is invoked by innerHTML) normalizes any
// quoting to single quotes, and fails to escape single
// quotes. (Note that this is not IE's behavior for all
// CSS properties, just some sort of special casing for
// font-family). So a single quote *cannot* be used
// safely in the font-family context if there will be an
// innerHTML/cssText translation. Note that Firefox 3.x
// does this too.
// - Double quote. In IE, these get normalized to
// single-quotes, no matter what the encoding. (Fun
// fact, in IE8, the 'content' CSS property gained
// support, where they special cased to preserve encoded
// double quotes, but still translate unadorned double
// quotes into single quotes.) So, because their
// fixpoint behavior is identical to single quotes, they
// cannot be allowed either. Firefox 3.x displays
// single-quote style behavior.
// - Backslashes are reduced by one (so \\ -> \) every
// iteration, so they cannot be used safely. This shows
// up in IE7, IE8 and FF3
// - Semicolons, commas and backticks are handled properly.
// - The rest of the ASCII punctuation is handled properly.
// We haven't checked what browsers do to unadorned
// versions, but this is not important as long as the
// browser doesn't /remove/ surrounding quotes (as IE does
// for HTML).
//
// With these results in hand, we conclude that there are
// various levels of safety:
// - Paranoid: alphanumeric, spaces and dashes(?)
// - International: Paranoid + non-ASCII Unicode
// - Edgy: Everything except quotes, backslashes
// - NoJS: Standards compliance, e.g. sod IE. Note that
// with some judicious character escaping (since certain
// types of escaping doesn't work) this is theoretically
// OK as long as innerHTML/cssText is not called.
// We believe that international is a reasonable default
// (that we will implement now), and once we do more
// extensive research, we may feel comfortable with dropping
// it down to edgy.
// Edgy: alphanumeric, spaces, dashes, underscores and Unicode. Use of
// str(c)spn assumes that the string was already well formed
// Unicode (which of course it is).
if (strspn($font, $this->mask) !== strlen($font)) {
continue;
}
// Historical:
// In the absence of innerHTML/cssText, these ugly
// transforms don't pose a security risk (as \\ and \"
// might--these escapes are not supported by most browsers).
// We could try to be clever and use single-quote wrapping
// when there is a double quote present, but I have choosen
// not to implement that. (NOTE: you can reduce the amount
// of escapes by one depending on what quoting style you use)
// $font = str_replace('\\', '\\5C ', $font);
// $font = str_replace('"', '\\22 ', $font);
// $font = str_replace("'", '\\27 ', $font);
// font possibly with spaces, requires quoting
$final .= "'$font', ";
}
$final = rtrim($final, ', ');
if ($final === '') {
return false;
}
return $final;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,32 +0,0 @@
<?php
/**
* Validates based on {ident} CSS grammar production
*/
class HTMLPurifier_AttrDef_CSS_Ident extends HTMLPurifier_AttrDef
{
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string);
// early abort: '' and '0' (strings that convert to false) are invalid
if (!$string) {
return false;
}
$pattern = '/^(-?[A-Za-z_][A-Za-z_\-0-9]*)$/';
if (!preg_match($pattern, $string)) {
return false;
}
return $string;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,56 +0,0 @@
<?php
/**
* Decorator which enables !important to be used in CSS values.
*/
class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef
{
/**
* @type HTMLPurifier_AttrDef
*/
public $def;
/**
* @type bool
*/
public $allow;
/**
* @param HTMLPurifier_AttrDef $def Definition to wrap
* @param bool $allow Whether or not to allow !important
*/
public function __construct($def, $allow = false)
{
$this->def = $def;
$this->allow = $allow;
}
/**
* Intercepts and removes !important if necessary
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
// test for ! and important tokens
$string = trim($string);
$is_important = false;
// :TODO: optimization: test directly for !important and ! important
if (strlen($string) >= 9 && substr($string, -9) === 'important') {
$temp = rtrim(substr($string, 0, -9));
// use a temp, because we might want to restore important
if (strlen($temp) >= 1 && substr($temp, -1) === '!') {
$string = rtrim(substr($temp, 0, -1));
$is_important = true;
}
}
$string = $this->def->validate($string, $config, $context);
if ($this->allow && $is_important) {
$string .= ' !important';
}
return $string;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,77 +0,0 @@
<?php
/**
* Represents a Length as defined by CSS.
*/
class HTMLPurifier_AttrDef_CSS_Length extends HTMLPurifier_AttrDef
{
/**
* @type HTMLPurifier_Length|string
*/
protected $min;
/**
* @type HTMLPurifier_Length|string
*/
protected $max;
/**
* @param HTMLPurifier_Length|string $min Minimum length, or null for no bound. String is also acceptable.
* @param HTMLPurifier_Length|string $max Maximum length, or null for no bound. String is also acceptable.
*/
public function __construct($min = null, $max = null)
{
$this->min = $min !== null ? HTMLPurifier_Length::make($min) : null;
$this->max = $max !== null ? HTMLPurifier_Length::make($max) : null;
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = $this->parseCDATA($string);
// Optimizations
if ($string === '') {
return false;
}
if ($string === '0') {
return '0';
}
if (strlen($string) === 1) {
return false;
}
$length = HTMLPurifier_Length::make($string);
if (!$length->isValid()) {
return false;
}
if ($this->min) {
$c = $length->compareTo($this->min);
if ($c === false) {
return false;
}
if ($c < 0) {
return false;
}
}
if ($this->max) {
$c = $length->compareTo($this->max);
if ($c === false) {
return false;
}
if ($c > 0) {
return false;
}
}
return $length->toString();
}
}
// vim: et sw=4 sts=4

View File

@@ -1,112 +0,0 @@
<?php
/**
* Validates shorthand CSS property list-style.
* @warning Does not support url tokens that have internal spaces.
*/
class HTMLPurifier_AttrDef_CSS_ListStyle extends HTMLPurifier_AttrDef
{
/**
* Local copy of validators.
* @type HTMLPurifier_AttrDef[]
* @note See HTMLPurifier_AttrDef_CSS_Font::$info for a similar impl.
*/
protected $info;
/**
* @param HTMLPurifier_Config $config
*/
public function __construct($config)
{
$def = $config->getCSSDefinition();
$this->info['list-style-type'] = $def->info['list-style-type'];
$this->info['list-style-position'] = $def->info['list-style-position'];
$this->info['list-style-image'] = $def->info['list-style-image'];
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
// regular pre-processing
$string = $this->parseCDATA($string);
if ($string === '') {
return false;
}
// assumes URI doesn't have spaces in it
$bits = explode(' ', strtolower($string)); // bits to process
$caught = array();
$caught['type'] = false;
$caught['position'] = false;
$caught['image'] = false;
$i = 0; // number of catches
$none = false;
foreach ($bits as $bit) {
if ($i >= 3) {
return;
} // optimization bit
if ($bit === '') {
continue;
}
foreach ($caught as $key => $status) {
if ($status !== false) {
continue;
}
$r = $this->info['list-style-' . $key]->validate($bit, $config, $context);
if ($r === false) {
continue;
}
if ($r === 'none') {
if ($none) {
continue;
} else {
$none = true;
}
if ($key == 'image') {
continue;
}
}
$caught[$key] = $r;
$i++;
break;
}
}
if (!$i) {
return false;
}
$ret = array();
// construct type
if ($caught['type']) {
$ret[] = $caught['type'];
}
// construct image
if ($caught['image']) {
$ret[] = $caught['image'];
}
// construct position
if ($caught['position']) {
$ret[] = $caught['position'];
}
if (empty($ret)) {
return false;
}
return implode(' ', $ret);
}
}
// vim: et sw=4 sts=4

View File

@@ -1,71 +0,0 @@
<?php
/**
* Framework class for strings that involve multiple values.
*
* Certain CSS properties such as border-width and margin allow multiple
* lengths to be specified. This class can take a vanilla border-width
* definition and multiply it, usually into a max of four.
*
* @note Even though the CSS specification isn't clear about it, inherit
* can only be used alone: it will never manifest as part of a multi
* shorthand declaration. Thus, this class does not allow inherit.
*/
class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef
{
/**
* Instance of component definition to defer validation to.
* @type HTMLPurifier_AttrDef
* @todo Make protected
*/
public $single;
/**
* Max number of values allowed.
* @todo Make protected
*/
public $max;
/**
* @param HTMLPurifier_AttrDef $single HTMLPurifier_AttrDef to multiply
* @param int $max Max number of values allowed (usually four)
*/
public function __construct($single, $max = 4)
{
$this->single = $single;
$this->max = $max;
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = $this->mungeRgb($this->parseCDATA($string));
if ($string === '') {
return false;
}
$parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n
$length = count($parts);
$final = '';
for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) {
if (ctype_space($parts[$i])) {
continue;
}
$result = $this->single->validate($parts[$i], $config, $context);
if ($result !== false) {
$final .= $result . ' ';
$num++;
}
}
if ($final === '') {
return false;
}
return rtrim($final);
}
}
// vim: et sw=4 sts=4

View File

@@ -1,84 +0,0 @@
<?php
/**
* Validates a number as defined by the CSS spec.
*/
class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
{
/**
* Indicates whether or not only positive values are allowed.
* @type bool
*/
protected $non_negative = false;
/**
* @param bool $non_negative indicates whether negatives are forbidden
*/
public function __construct($non_negative = false)
{
$this->non_negative = $non_negative;
}
/**
* @param string $number
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return string|bool
* @warning Some contexts do not pass $config, $context. These
* variables should not be used without checking HTMLPurifier_Length
*/
public function validate($number, $config, $context)
{
$number = $this->parseCDATA($number);
if ($number === '') {
return false;
}
if ($number === '0') {
return '0';
}
$sign = '';
switch ($number[0]) {
case '-':
if ($this->non_negative) {
return false;
}
$sign = '-';
case '+':
$number = substr($number, 1);
}
if (ctype_digit($number)) {
$number = ltrim($number, '0');
return $number ? $sign . $number : '0';
}
// Period is the only non-numeric character allowed
if (strpos($number, '.') === false) {
return false;
}
list($left, $right) = explode('.', $number, 2);
if ($left === '' && $right === '') {
return false;
}
if ($left !== '' && !ctype_digit($left)) {
return false;
}
$left = ltrim($left, '0');
$right = rtrim($right, '0');
if ($right === '') {
return $left ? $sign . $left : '0';
} elseif (!ctype_digit($right)) {
return false;
}
return $sign . $left . '.' . $right;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,54 +0,0 @@
<?php
/**
* Validates a Percentage as defined by the CSS spec.
*/
class HTMLPurifier_AttrDef_CSS_Percentage extends HTMLPurifier_AttrDef
{
/**
* Instance to defer number validation to.
* @type HTMLPurifier_AttrDef_CSS_Number
*/
protected $number_def;
/**
* @param bool $non_negative Whether to forbid negative values
*/
public function __construct($non_negative = false)
{
$this->number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative);
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = $this->parseCDATA($string);
if ($string === '') {
return false;
}
$length = strlen($string);
if ($length === 1) {
return false;
}
if ($string[$length - 1] !== '%') {
return false;
}
$number = substr($string, 0, $length - 1);
$number = $this->number_def->validate($number, $config, $context);
if ($number === false) {
return false;
}
return "$number%";
}
}
// vim: et sw=4 sts=4

View File

@@ -1,46 +0,0 @@
<?php
/**
* Validates the value for the CSS property text-decoration
* @note This class could be generalized into a version that acts sort of
* like Enum except you can compound the allowed values.
*/
class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
{
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
static $allowed_values = array(
'line-through' => true,
'overline' => true,
'underline' => true,
);
$string = strtolower($this->parseCDATA($string));
if ($string === 'none') {
return $string;
}
$parts = explode(' ', $string);
$final = '';
foreach ($parts as $part) {
if (isset($allowed_values[$part])) {
$final .= $part . ' ';
}
}
$final = rtrim($final);
if ($final === '') {
return false;
}
return $final;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,77 +0,0 @@
<?php
/**
* Validates a URI in CSS syntax, which uses url('http://example.com')
* @note While theoretically speaking a URI in a CSS document could
* be non-embedded, as of CSS2 there is no such usage so we're
* generalizing it. This may need to be changed in the future.
* @warning Since HTMLPurifier_AttrDef_CSS blindly uses semicolons as
* the separator, you cannot put a literal semicolon in
* in the URI. Try percent encoding it, in that case.
*/
class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
{
public function __construct()
{
parent::__construct(true); // always embedded
}
/**
* @param string $uri_string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($uri_string, $config, $context)
{
// parse the URI out of the string and then pass it onto
// the parent object
$uri_string = $this->parseCDATA($uri_string);
if (strpos($uri_string, 'url(') !== 0) {
return false;
}
$uri_string = substr($uri_string, 4);
if (strlen($uri_string) == 0) {
return false;
}
$new_length = strlen($uri_string) - 1;
if ($uri_string[$new_length] != ')') {
return false;
}
$uri = trim(substr($uri_string, 0, $new_length));
if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) {
$quote = $uri[0];
$new_length = strlen($uri) - 1;
if ($uri[$new_length] !== $quote) {
return false;
}
$uri = substr($uri, 1, $new_length - 1);
}
$uri = $this->expandCSSEscape($uri);
$result = parent::validate($uri, $config, $context);
if ($result === false) {
return false;
}
// extra sanity check; should have been done by URI
$result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result);
// suspicious characters are ()'; we're going to percent encode
// them for safety.
$result = str_replace(array('(', ')', "'"), array('%28', '%29', '%27'), $result);
// there's an extra bug where ampersands lose their escaping on
// an innerHTML cycle, so a very unlucky query parameter could
// then change the meaning of the URL. Unfortunately, there's
// not much we can do about that...
return "url(\"$result\")";
}
}
// vim: et sw=4 sts=4

View File

@@ -1,44 +0,0 @@
<?php
/**
* Dummy AttrDef that mimics another AttrDef, BUT it generates clones
* with make.
*/
class HTMLPurifier_AttrDef_Clone extends HTMLPurifier_AttrDef
{
/**
* What we're cloning.
* @type HTMLPurifier_AttrDef
*/
protected $clone;
/**
* @param HTMLPurifier_AttrDef $clone
*/
public function __construct($clone)
{
$this->clone = $clone;
}
/**
* @param string $v
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($v, $config, $context)
{
return $this->clone->validate($v, $config, $context);
}
/**
* @param string $string
* @return HTMLPurifier_AttrDef
*/
public function make($string)
{
return clone $this->clone;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,73 +0,0 @@
<?php
// Enum = Enumerated
/**
* Validates a keyword against a list of valid values.
* @warning The case-insensitive compare of this function uses PHP's
* built-in strtolower and ctype_lower functions, which may
* cause problems with international comparisons
*/
class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
{
/**
* Lookup table of valid values.
* @type array
* @todo Make protected
*/
public $valid_values = array();
/**
* Bool indicating whether or not enumeration is case sensitive.
* @note In general this is always case insensitive.
*/
protected $case_sensitive = false; // values according to W3C spec
/**
* @param array $valid_values List of valid values
* @param bool $case_sensitive Whether or not case sensitive
*/
public function __construct($valid_values = array(), $case_sensitive = false)
{
$this->valid_values = array_flip($valid_values);
$this->case_sensitive = $case_sensitive;
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string);
if (!$this->case_sensitive) {
// we may want to do full case-insensitive libraries
$string = ctype_lower($string) ? $string : strtolower($string);
}
$result = isset($this->valid_values[$string]);
return $result ? $string : false;
}
/**
* @param string $string In form of comma-delimited list of case-insensitive
* valid values. Example: "foo,bar,baz". Prepend "s:" to make
* case sensitive
* @return HTMLPurifier_AttrDef_Enum
*/
public function make($string)
{
if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') {
$string = substr($string, 2);
$sensitive = true;
} else {
$sensitive = false;
}
$values = explode(',', $string);
return new HTMLPurifier_AttrDef_Enum($values, $sensitive);
}
}
// vim: et sw=4 sts=4

View File

@@ -1,48 +0,0 @@
<?php
/**
* Validates a boolean attribute
*/
class HTMLPurifier_AttrDef_HTML_Bool extends HTMLPurifier_AttrDef
{
/**
* @type bool
*/
protected $name;
/**
* @type bool
*/
public $minimized = true;
/**
* @param bool $name
*/
public function __construct($name = false)
{
$this->name = $name;
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
return $this->name;
}
/**
* @param string $string Name of attribute
* @return HTMLPurifier_AttrDef_HTML_Bool
*/
public function make($string)
{
return new HTMLPurifier_AttrDef_HTML_Bool($string);
}
}
// vim: et sw=4 sts=4

View File

@@ -1,48 +0,0 @@
<?php
/**
* Implements special behavior for class attribute (normally NMTOKENS)
*/
class HTMLPurifier_AttrDef_HTML_Class extends HTMLPurifier_AttrDef_HTML_Nmtokens
{
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
protected function split($string, $config, $context)
{
// really, this twiddle should be lazy loaded
$name = $config->getDefinition('HTML')->doctype->name;
if ($name == "XHTML 1.1" || $name == "XHTML 2.0") {
return parent::split($string, $config, $context);
} else {
return preg_split('/\s+/', $string);
}
}
/**
* @param array $tokens
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
protected function filter($tokens, $config, $context)
{
$allowed = $config->get('Attr.AllowedClasses');
$forbidden = $config->get('Attr.ForbiddenClasses');
$ret = array();
foreach ($tokens as $token) {
if (($allowed === null || isset($allowed[$token])) &&
!isset($forbidden[$token]) &&
// We need this O(n) check because of PHP's array
// implementation that casts -0 to 0.
!in_array($token, $ret, true)
) {
$ret[] = $token;
}
}
return $ret;
}
}

View File

@@ -1,51 +0,0 @@
<?php
/**
* Validates a color according to the HTML spec.
*/
class HTMLPurifier_AttrDef_HTML_Color extends HTMLPurifier_AttrDef
{
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
static $colors = null;
if ($colors === null) {
$colors = $config->get('Core.ColorKeywords');
}
$string = trim($string);
if (empty($string)) {
return false;
}
$lower = strtolower($string);
if (isset($colors[$lower])) {
return $colors[$lower];
}
if ($string[0] === '#') {
$hex = substr($string, 1);
} else {
$hex = $string;
}
$length = strlen($hex);
if ($length !== 3 && $length !== 6) {
return false;
}
if (!ctype_xdigit($hex)) {
return false;
}
if ($length === 3) {
$hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
}
return "#$hex";
}
}
// vim: et sw=4 sts=4

View File

@@ -1,38 +0,0 @@
<?php
/**
* Special-case enum attribute definition that lazy loads allowed frame targets
*/
class HTMLPurifier_AttrDef_HTML_FrameTarget extends HTMLPurifier_AttrDef_Enum
{
/**
* @type array
*/
public $valid_values = false; // uninitialized value
/**
* @type bool
*/
protected $case_sensitive = false;
public function __construct()
{
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
if ($this->valid_values === false) {
$this->valid_values = $config->get('Attr.AllowedFrameTargets');
}
return parent::validate($string, $config, $context);
}
}
// vim: et sw=4 sts=4

View File

@@ -1,113 +0,0 @@
<?php
/**
* Validates the HTML attribute ID.
* @warning Even though this is the id processor, it
* will ignore the directive Attr:IDBlacklist, since it will only
* go according to the ID accumulator. Since the accumulator is
* automatically generated, it will have already absorbed the
* blacklist. If you're hacking around, make sure you use load()!
*/
class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef
{
// selector is NOT a valid thing to use for IDREFs, because IDREFs
// *must* target IDs that exist, whereas selector #ids do not.
/**
* Determines whether or not we're validating an ID in a CSS
* selector context.
* @type bool
*/
protected $selector;
/**
* @param bool $selector
*/
public function __construct($selector = false)
{
$this->selector = $selector;
}
/**
* @param string $id
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($id, $config, $context)
{
if (!$this->selector && !$config->get('Attr.EnableID')) {
return false;
}
$id = trim($id); // trim it first
if ($id === '') {
return false;
}
$prefix = $config->get('Attr.IDPrefix');
if ($prefix !== '') {
$prefix .= $config->get('Attr.IDPrefixLocal');
// prevent re-appending the prefix
if (strpos($id, $prefix) !== 0) {
$id = $prefix . $id;
}
} elseif ($config->get('Attr.IDPrefixLocal') !== '') {
trigger_error(
'%Attr.IDPrefixLocal cannot be used unless ' .
'%Attr.IDPrefix is set',
E_USER_WARNING
);
}
if (!$this->selector) {
$id_accumulator =& $context->get('IDAccumulator');
if (isset($id_accumulator->ids[$id])) {
return false;
}
}
// we purposely avoid using regex, hopefully this is faster
if ($config->get('Attr.ID.HTML5') === true) {
if (preg_match('/[\t\n\x0b\x0c ]/', $id)) {
return false;
}
} else {
if (ctype_alpha($id)) {
// OK
} else {
if (!ctype_alpha(@$id[0])) {
return false;
}
// primitive style of regexps, I suppose
$trim = trim(
$id,
'A..Za..z0..9:-._'
);
if ($trim !== '') {
return false;
}
}
}
$regexp = $config->get('Attr.IDBlacklistRegexp');
if ($regexp && preg_match($regexp, $id)) {
return false;
}
if (!$this->selector) {
$id_accumulator->add($id);
}
// if no change was made to the ID, return the result
// else, return the new id if stripping whitespace made it
// valid, or return false.
return $id;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,56 +0,0 @@
<?php
/**
* Validates the HTML type length (not to be confused with CSS's length).
*
* This accepts integer pixels or percentages as lengths for certain
* HTML attributes.
*/
class HTMLPurifier_AttrDef_HTML_Length extends HTMLPurifier_AttrDef_HTML_Pixels
{
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string);
if ($string === '') {
return false;
}
$parent_result = parent::validate($string, $config, $context);
if ($parent_result !== false) {
return $parent_result;
}
$length = strlen($string);
$last_char = $string[$length - 1];
if ($last_char !== '%') {
return false;
}
$points = substr($string, 0, $length - 1);
if (!is_numeric($points)) {
return false;
}
$points = (int)$points;
if ($points < 0) {
return '0%';
}
if ($points > 100) {
return '100%';
}
return ((string)$points) . '%';
}
}
// vim: et sw=4 sts=4

View File

@@ -1,72 +0,0 @@
<?php
/**
* Validates a rel/rev link attribute against a directive of allowed values
* @note We cannot use Enum because link types allow multiple
* values.
* @note Assumes link types are ASCII text
*/
class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef
{
/**
* Name config attribute to pull.
* @type string
*/
protected $name;
/**
* @param string $name
*/
public function __construct($name)
{
$configLookup = array(
'rel' => 'AllowedRel',
'rev' => 'AllowedRev'
);
if (!isset($configLookup[$name])) {
trigger_error(
'Unrecognized attribute name for link ' .
'relationship.',
E_USER_ERROR
);
return;
}
$this->name = $configLookup[$name];
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$allowed = $config->get('Attr.' . $this->name);
if (empty($allowed)) {
return false;
}
$string = $this->parseCDATA($string);
$parts = explode(' ', $string);
// lookup to prevent duplicates
$ret_lookup = array();
foreach ($parts as $part) {
$part = strtolower(trim($part));
if (!isset($allowed[$part])) {
continue;
}
$ret_lookup[$part] = true;
}
if (empty($ret_lookup)) {
return false;
}
$string = implode(' ', array_keys($ret_lookup));
return $string;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,60 +0,0 @@
<?php
/**
* Validates a MultiLength as defined by the HTML spec.
*
* A multilength is either a integer (pixel count), a percentage, or
* a relative number.
*/
class HTMLPurifier_AttrDef_HTML_MultiLength extends HTMLPurifier_AttrDef_HTML_Length
{
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string);
if ($string === '') {
return false;
}
$parent_result = parent::validate($string, $config, $context);
if ($parent_result !== false) {
return $parent_result;
}
$length = strlen($string);
$last_char = $string[$length - 1];
if ($last_char !== '*') {
return false;
}
$int = substr($string, 0, $length - 1);
if ($int == '') {
return '*';
}
if (!is_numeric($int)) {
return false;
}
$int = (int)$int;
if ($int < 0) {
return false;
}
if ($int == 0) {
return '0';
}
if ($int == 1) {
return '*';
}
return ((string)$int) . '*';
}
}
// vim: et sw=4 sts=4

View File

@@ -1,70 +0,0 @@
<?php
/**
* Validates contents based on NMTOKENS attribute type.
*/
class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
{
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string);
// early abort: '' and '0' (strings that convert to false) are invalid
if (!$string) {
return false;
}
$tokens = $this->split($string, $config, $context);
$tokens = $this->filter($tokens, $config, $context);
if (empty($tokens)) {
return false;
}
return implode(' ', $tokens);
}
/**
* Splits a space separated list of tokens into its constituent parts.
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
protected function split($string, $config, $context)
{
// OPTIMIZABLE!
// do the preg_match, capture all subpatterns for reformulation
// we don't support U+00A1 and up codepoints or
// escaping because I don't know how to do that with regexps
// and plus it would complicate optimization efforts (you never
// see that anyway).
$pattern = '/(?:(?<=\s)|\A)' . // look behind for space or string start
'((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)' .
'(?:(?=\s)|\z)/'; // look ahead for space or string end
preg_match_all($pattern, $string, $matches);
return $matches[1];
}
/**
* Template method for removing certain tokens based on arbitrary criteria.
* @note If we wanted to be really functional, we'd do an array_filter
* with a callback. But... we're not.
* @param array $tokens
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return array
*/
protected function filter($tokens, $config, $context)
{
return $tokens;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,76 +0,0 @@
<?php
/**
* Validates an integer representation of pixels according to the HTML spec.
*/
class HTMLPurifier_AttrDef_HTML_Pixels extends HTMLPurifier_AttrDef
{
/**
* @type int
*/
protected $max;
/**
* @param int $max
*/
public function __construct($max = null)
{
$this->max = $max;
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string);
if ($string === '0') {
return $string;
}
if ($string === '') {
return false;
}
$length = strlen($string);
if (substr($string, $length - 2) == 'px') {
$string = substr($string, 0, $length - 2);
}
if (!is_numeric($string)) {
return false;
}
$int = (int)$string;
if ($int < 0) {
return '0';
}
// upper-bound value, extremely high values can
// crash operating systems, see <http://ha.ckers.org/imagecrash.html>
// WARNING, above link WILL crash you if you're using Windows
if ($this->max !== null && $int > $this->max) {
return (string)$this->max;
}
return (string)$int;
}
/**
* @param string $string
* @return HTMLPurifier_AttrDef
*/
public function make($string)
{
if ($string === '') {
$max = null;
} else {
$max = (int)$string;
}
$class = get_class($this);
return new $class($max);
}
}
// vim: et sw=4 sts=4

View File

@@ -1,91 +0,0 @@
<?php
/**
* Validates an integer.
* @note While this class was modeled off the CSS definition, no currently
* allowed CSS uses this type. The properties that do are: widows,
* orphans, z-index, counter-increment, counter-reset. Some of the
* HTML attributes, however, find use for a non-negative version of this.
*/
class HTMLPurifier_AttrDef_Integer extends HTMLPurifier_AttrDef
{
/**
* Whether or not negative values are allowed.
* @type bool
*/
protected $negative = true;
/**
* Whether or not zero is allowed.
* @type bool
*/
protected $zero = true;
/**
* Whether or not positive values are allowed.
* @type bool
*/
protected $positive = true;
/**
* @param $negative Bool indicating whether or not negative values are allowed
* @param $zero Bool indicating whether or not zero is allowed
* @param $positive Bool indicating whether or not positive values are allowed
*/
public function __construct($negative = true, $zero = true, $positive = true)
{
$this->negative = $negative;
$this->zero = $zero;
$this->positive = $positive;
}
/**
* @param string $integer
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($integer, $config, $context)
{
$integer = $this->parseCDATA($integer);
if ($integer === '') {
return false;
}
// we could possibly simply typecast it to integer, but there are
// certain fringe cases that must not return an integer.
// clip leading sign
if ($this->negative && $integer[0] === '-') {
$digits = substr($integer, 1);
if ($digits === '0') {
$integer = '0';
} // rm minus sign for zero
} elseif ($this->positive && $integer[0] === '+') {
$digits = $integer = substr($integer, 1); // rm unnecessary plus
} else {
$digits = $integer;
}
// test if it's numeric
if (!ctype_digit($digits)) {
return false;
}
// perform scope tests
if (!$this->zero && $integer == 0) {
return false;
}
if (!$this->positive && $integer > 0) {
return false;
}
if (!$this->negative && $integer < 0) {
return false;
}
return $integer;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,86 +0,0 @@
<?php
/**
* Validates the HTML attribute lang, effectively a language code.
* @note Built according to RFC 3066, which obsoleted RFC 1766
*/
class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef
{
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$string = trim($string);
if (!$string) {
return false;
}
$subtags = explode('-', $string);
$num_subtags = count($subtags);
if ($num_subtags == 0) { // sanity check
return false;
}
// process primary subtag : $subtags[0]
$length = strlen($subtags[0]);
switch ($length) {
case 0:
return false;
case 1:
if (!($subtags[0] == 'x' || $subtags[0] == 'i')) {
return false;
}
break;
case 2:
case 3:
if (!ctype_alpha($subtags[0])) {
return false;
} elseif (!ctype_lower($subtags[0])) {
$subtags[0] = strtolower($subtags[0]);
}
break;
default:
return false;
}
$new_string = $subtags[0];
if ($num_subtags == 1) {
return $new_string;
}
// process second subtag : $subtags[1]
$length = strlen($subtags[1]);
if ($length == 0 || ($length == 1 && $subtags[1] != 'x') || $length > 8 || !ctype_alnum($subtags[1])) {
return $new_string;
}
if (!ctype_lower($subtags[1])) {
$subtags[1] = strtolower($subtags[1]);
}
$new_string .= '-' . $subtags[1];
if ($num_subtags == 2) {
return $new_string;
}
// process all other subtags, index 2 and up
for ($i = 2; $i < $num_subtags; $i++) {
$length = strlen($subtags[$i]);
if ($length == 0 || $length > 8 || !ctype_alnum($subtags[$i])) {
return $new_string;
}
if (!ctype_lower($subtags[$i])) {
$subtags[$i] = strtolower($subtags[$i]);
}
$new_string .= '-' . $subtags[$i];
}
return $new_string;
}
}
// vim: et sw=4 sts=4

View File

@@ -1,53 +0,0 @@
<?php
/**
* Decorator that, depending on a token, switches between two definitions.
*/
class HTMLPurifier_AttrDef_Switch
{
/**
* @type string
*/
protected $tag;
/**
* @type HTMLPurifier_AttrDef
*/
protected $withTag;
/**
* @type HTMLPurifier_AttrDef
*/
protected $withoutTag;
/**
* @param string $tag Tag name to switch upon
* @param HTMLPurifier_AttrDef $with_tag Call if token matches tag
* @param HTMLPurifier_AttrDef $without_tag Call if token doesn't match, or there is no token
*/
public function __construct($tag, $with_tag, $without_tag)
{
$this->tag = $tag;
$this->withTag = $with_tag;
$this->withoutTag = $without_tag;
}
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
$token = $context->get('CurrentToken', true);
if (!$token || $token->name !== $this->tag) {
return $this->withoutTag->validate($string, $config, $context);
} else {
return $this->withTag->validate($string, $config, $context);
}
}
}
// vim: et sw=4 sts=4

View File

@@ -1,21 +0,0 @@
<?php
/**
* Validates arbitrary text according to the HTML spec.
*/
class HTMLPurifier_AttrDef_Text extends HTMLPurifier_AttrDef
{
/**
* @param string $string
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($string, $config, $context)
{
return $this->parseCDATA($string);
}
}
// vim: et sw=4 sts=4

View File

@@ -1,111 +0,0 @@
<?php
/**
* Validates a URI as defined by RFC 3986.
* @note Scheme-specific mechanics deferred to HTMLPurifier_URIScheme
*/
class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
{
/**
* @type HTMLPurifier_URIParser
*/
protected $parser;
/**
* @type bool
*/
protected $embedsResource;
/**
* @param bool $embeds_resource Does the URI here result in an extra HTTP request?
*/
public function __construct($embeds_resource = false)
{
$this->parser = new HTMLPurifier_URIParser();
$this->embedsResource = (bool)$embeds_resource;
}
/**
* @param string $string
* @return HTMLPurifier_AttrDef_URI
*/
public function make($string)
{
$embeds = ($string === 'embedded');
return new HTMLPurifier_AttrDef_URI($embeds);
}
/**
* @param string $uri
* @param HTMLPurifier_Config $config
* @param HTMLPurifier_Context $context
* @return bool|string
*/
public function validate($uri, $config, $context)
{
if ($config->get('URI.Disable')) {
return false;
}
$uri = $this->parseCDATA($uri);
// parse the URI
$uri = $this->parser->parse($uri);
if ($uri === false) {
return false;
}
// add embedded flag to context for validators
$context->register('EmbeddedURI', $this->embedsResource);
$ok = false;
do {
// generic validation
$result = $uri->validate($config, $context);
if (!$result) {
break;
}
// chained filtering
$uri_def = $config->getDefinition('URI');
$result = $uri_def->filter($uri, $config, $context);
if (!$result) {
break;
}
// scheme-specific validation
$scheme_obj = $uri->getSchemeObj($config, $context);
if (!$scheme_obj) {
break;
}
if ($this->embedsResource && !$scheme_obj->browsable) {
break;
}
$result = $scheme_obj->validate($uri, $config, $context);
if (!$result) {
break;
}
// Post chained filtering
$result = $uri_def->postFilter($uri, $config, $context);
if (!$result) {
break;
}
// survived gauntlet
$ok = true;
} while (false);
$context->destroy('EmbeddedURI');
if (!$ok) {
return false;
}
// back to string
return $uri->toString();
}
}
// vim: et sw=4 sts=4

Some files were not shown because too many files have changed in this diff Show More