mirror of
https://github.com/librenms/librenms.git
synced 2024-10-07 16:52:45 +00:00
refactor: use Composer to manage php dependencies (#5216)
This commit is contained in:
committed by
Neil Lathwood
parent
74a4371fb4
commit
e20a242785
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Connection;
|
||||
|
||||
/**
|
||||
* Class AMQPConnection
|
||||
*
|
||||
* Kept for BC
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
class AMQPConnection extends AMQPStreamConnection
|
||||
{
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Exception;
|
||||
|
||||
/**
|
||||
* @deprecated use AMQPProtocolChannelException instead
|
||||
*/
|
||||
class AMQPChannelException extends AMQPException
|
||||
{
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Exception;
|
||||
|
||||
/**
|
||||
* @deprecated use AMQPProtocolConnectionException instead
|
||||
*/
|
||||
class AMQPConnectionException extends AMQPException
|
||||
{
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Exception;
|
||||
|
||||
interface AMQPExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Exception;
|
||||
|
||||
class AMQPIOException extends \Exception implements AMQPExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Exception;
|
||||
|
||||
class AMQPInvalidArgumentException extends \RuntimeException implements AMQPExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Exception;
|
||||
|
||||
class AMQPLogicException extends \LogicException implements AMQPExceptionInterface
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Exception;
|
||||
|
||||
class AMQPOutOfBoundsException extends \OutOfBoundsException implements AMQPExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Exception;
|
||||
|
||||
class AMQPOutOfRangeException extends \OutOfRangeException implements AMQPExceptionInterface
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Exception;
|
||||
|
||||
class AMQPProtocolChannelException extends AMQPProtocolException
|
||||
{
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Exception;
|
||||
|
||||
class AMQPProtocolConnectionException extends AMQPProtocolException
|
||||
{
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Exception;
|
||||
|
||||
class AMQPRuntimeException extends \RuntimeException implements AMQPExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
namespace PhpAmqpLib\Exception;
|
||||
|
||||
class AMQPTimeoutException extends \RuntimeException implements AMQPExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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',
|
||||
);
|
||||
|
||||
}
|
||||
@@ -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',
|
||||
);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -1,4 +0,0 @@
|
||||
<?php
|
||||
if (!defined('HTMLPURIFIER_PREFIX')) {
|
||||
define('HTMLPURIFIER_PREFIX', dirname(__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
|
||||
@@ -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';
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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';
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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: "MS 明朝" 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+MS+明朝|ゴシック>
|
||||
// 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user