649 lines
17 KiB
PHP
649 lines
17 KiB
PHP
<?php
|
|
/**
|
|
* base include file for SimpleTest
|
|
* @package SimpleTest
|
|
* @subpackage WebTester
|
|
* @version $Id: encoding.php 2011 2011-04-29 08:22:48Z pp11 $
|
|
*/
|
|
|
|
/**#@+
|
|
* include other SimpleTest class files
|
|
*/
|
|
require_once(dirname(__FILE__) . '/socket.php');
|
|
/**#@-*/
|
|
|
|
/**
|
|
* Single post parameter.
|
|
* @package SimpleTest
|
|
* @subpackage WebTester
|
|
*/
|
|
class SimpleEncodedPair {
|
|
private $key;
|
|
private $value;
|
|
|
|
/**
|
|
* Stashes the data for rendering later.
|
|
* @param string $key Form element name.
|
|
* @param string $value Data to send.
|
|
*/
|
|
function __construct($key, $value) {
|
|
$this->key = $key;
|
|
$this->value = $value;
|
|
}
|
|
|
|
/**
|
|
* The pair as a single string.
|
|
* @return string Encoded pair.
|
|
* @access public
|
|
*/
|
|
function asRequest() {
|
|
return urlencode($this->key) . '=' . urlencode($this->value);
|
|
}
|
|
|
|
/**
|
|
* The MIME part as a string.
|
|
* @return string MIME part encoding.
|
|
* @access public
|
|
*/
|
|
function asMime() {
|
|
$part = 'Content-Disposition: form-data; ';
|
|
$part .= "name=\"" . $this->key . "\"\r\n";
|
|
$part .= "\r\n" . $this->value;
|
|
return $part;
|
|
}
|
|
|
|
/**
|
|
* Is this the value we are looking for?
|
|
* @param string $key Identifier.
|
|
* @return boolean True if matched.
|
|
* @access public
|
|
*/
|
|
function isKey($key) {
|
|
return $key == $this->key;
|
|
}
|
|
|
|
/**
|
|
* Is this the value we are looking for?
|
|
* @return string Identifier.
|
|
* @access public
|
|
*/
|
|
function getKey() {
|
|
return $this->key;
|
|
}
|
|
|
|
/**
|
|
* Is this the value we are looking for?
|
|
* @return string Content.
|
|
* @access public
|
|
*/
|
|
function getValue() {
|
|
return $this->value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Single post parameter.
|
|
* @package SimpleTest
|
|
* @subpackage WebTester
|
|
*/
|
|
class SimpleAttachment {
|
|
private $key;
|
|
private $content;
|
|
private $filename;
|
|
|
|
/**
|
|
* Stashes the data for rendering later.
|
|
* @param string $key Key to add value to.
|
|
* @param string $content Raw data.
|
|
* @param hash $filename Original filename.
|
|
*/
|
|
function __construct($key, $content, $filename) {
|
|
$this->key = $key;
|
|
$this->content = $content;
|
|
$this->filename = $filename;
|
|
}
|
|
|
|
/**
|
|
* The pair as a single string.
|
|
* @return string Encoded pair.
|
|
* @access public
|
|
*/
|
|
function asRequest() {
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* The MIME part as a string.
|
|
* @return string MIME part encoding.
|
|
* @access public
|
|
*/
|
|
function asMime() {
|
|
$part = 'Content-Disposition: form-data; ';
|
|
$part .= 'name="' . $this->key . '"; ';
|
|
$part .= 'filename="' . $this->filename . '"';
|
|
$part .= "\r\nContent-Type: " . $this->deduceMimeType();
|
|
$part .= "\r\n\r\n" . $this->content;
|
|
return $part;
|
|
}
|
|
|
|
/**
|
|
* Attempts to figure out the MIME type from the
|
|
* file extension and the content.
|
|
* @return string MIME type.
|
|
* @access private
|
|
*/
|
|
protected function deduceMimeType() {
|
|
if ($this->isOnlyAscii($this->content)) {
|
|
return 'text/plain';
|
|
}
|
|
return 'application/octet-stream';
|
|
}
|
|
|
|
/**
|
|
* Tests each character is in the range 0-127.
|
|
* @param string $ascii String to test.
|
|
* @access private
|
|
*/
|
|
protected function isOnlyAscii($ascii) {
|
|
for ($i = 0, $length = strlen($ascii); $i < $length; $i++) {
|
|
if (ord($ascii[$i]) > 127) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Is this the value we are looking for?
|
|
* @param string $key Identifier.
|
|
* @return boolean True if matched.
|
|
* @access public
|
|
*/
|
|
function isKey($key) {
|
|
return $key == $this->key;
|
|
}
|
|
|
|
/**
|
|
* Is this the value we are looking for?
|
|
* @return string Identifier.
|
|
* @access public
|
|
*/
|
|
function getKey() {
|
|
return $this->key;
|
|
}
|
|
|
|
/**
|
|
* Is this the value we are looking for?
|
|
* @return string Content.
|
|
* @access public
|
|
*/
|
|
function getValue() {
|
|
return $this->filename;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bundle of GET/POST parameters. Can include
|
|
* repeated parameters.
|
|
* @package SimpleTest
|
|
* @subpackage WebTester
|
|
*/
|
|
class SimpleEncoding {
|
|
private $request;
|
|
|
|
/**
|
|
* Starts empty.
|
|
* @param array $query Hash of parameters.
|
|
* Multiple values are
|
|
* as lists on a single key.
|
|
* @access public
|
|
*/
|
|
function __construct($query = false) {
|
|
if (! $query) {
|
|
$query = array();
|
|
}
|
|
$this->clear();
|
|
$this->merge($query);
|
|
}
|
|
|
|
/**
|
|
* Empties the request of parameters.
|
|
* @access public
|
|
*/
|
|
function clear() {
|
|
$this->request = array();
|
|
}
|
|
|
|
/**
|
|
* Adds a parameter to the query.
|
|
* @param string $key Key to add value to.
|
|
* @param string/array $value New data.
|
|
* @access public
|
|
*/
|
|
function add($key, $value) {
|
|
if ($value === false) {
|
|
return;
|
|
}
|
|
if (is_array($value)) {
|
|
foreach ($value as $item) {
|
|
$this->addPair($key, $item);
|
|
}
|
|
} else {
|
|
$this->addPair($key, $value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a new value into the request.
|
|
* @param string $key Key to add value to.
|
|
* @param string/array $value New data.
|
|
* @access private
|
|
*/
|
|
protected function addPair($key, $value) {
|
|
$this->request[] = new SimpleEncodedPair($key, $value);
|
|
}
|
|
|
|
/**
|
|
* Adds a MIME part to the query. Does nothing for a
|
|
* form encoded packet.
|
|
* @param string $key Key to add value to.
|
|
* @param string $content Raw data.
|
|
* @param hash $filename Original filename.
|
|
* @access public
|
|
*/
|
|
function attach($key, $content, $filename) {
|
|
$this->request[] = new SimpleAttachment($key, $content, $filename);
|
|
}
|
|
|
|
/**
|
|
* Adds a set of parameters to this query.
|
|
* @param array/SimpleQueryString $query Multiple values are
|
|
* as lists on a single key.
|
|
* @access public
|
|
*/
|
|
function merge($query) {
|
|
if (is_object($query)) {
|
|
$this->request = array_merge($this->request, $query->getAll());
|
|
} elseif (is_array($query)) {
|
|
foreach ($query as $key => $value) {
|
|
$this->add($key, $value);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Accessor for single value.
|
|
* @return string/array False if missing, string
|
|
* if present and array if
|
|
* multiple entries.
|
|
* @access public
|
|
*/
|
|
function getValue($key) {
|
|
$values = array();
|
|
foreach ($this->request as $pair) {
|
|
if ($pair->isKey($key)) {
|
|
$values[] = $pair->getValue();
|
|
}
|
|
}
|
|
if (count($values) == 0) {
|
|
return false;
|
|
} elseif (count($values) == 1) {
|
|
return $values[0];
|
|
} else {
|
|
return $values;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Accessor for listing of pairs.
|
|
* @return array All pair objects.
|
|
* @access public
|
|
*/
|
|
function getAll() {
|
|
return $this->request;
|
|
}
|
|
|
|
/**
|
|
* Renders the query string as a URL encoded
|
|
* request part.
|
|
* @return string Part of URL.
|
|
* @access protected
|
|
*/
|
|
protected function encode() {
|
|
$statements = array();
|
|
foreach ($this->request as $pair) {
|
|
if ($statement = $pair->asRequest()) {
|
|
$statements[] = $statement;
|
|
}
|
|
}
|
|
return implode('&', $statements);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bundle of GET parameters. Can include
|
|
* repeated parameters.
|
|
* @package SimpleTest
|
|
* @subpackage WebTester
|
|
*/
|
|
class SimpleGetEncoding extends SimpleEncoding {
|
|
|
|
/**
|
|
* Starts empty.
|
|
* @param array $query Hash of parameters.
|
|
* Multiple values are
|
|
* as lists on a single key.
|
|
* @access public
|
|
*/
|
|
function __construct($query = false) {
|
|
parent::__construct($query);
|
|
}
|
|
|
|
/**
|
|
* HTTP request method.
|
|
* @return string Always GET.
|
|
* @access public
|
|
*/
|
|
function getMethod() {
|
|
return 'GET';
|
|
}
|
|
|
|
/**
|
|
* Writes no extra headers.
|
|
* @param SimpleSocket $socket Socket to write to.
|
|
* @access public
|
|
*/
|
|
function writeHeadersTo(&$socket) {
|
|
}
|
|
|
|
/**
|
|
* No data is sent to the socket as the data is encoded into
|
|
* the URL.
|
|
* @param SimpleSocket $socket Socket to write to.
|
|
* @access public
|
|
*/
|
|
function writeTo(&$socket) {
|
|
}
|
|
|
|
/**
|
|
* Renders the query string as a URL encoded
|
|
* request part for attaching to a URL.
|
|
* @return string Part of URL.
|
|
* @access public
|
|
*/
|
|
function asUrlRequest() {
|
|
return $this->encode();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bundle of URL parameters for a HEAD request.
|
|
* @package SimpleTest
|
|
* @subpackage WebTester
|
|
*/
|
|
class SimpleHeadEncoding extends SimpleGetEncoding {
|
|
|
|
/**
|
|
* Starts empty.
|
|
* @param array $query Hash of parameters.
|
|
* Multiple values are
|
|
* as lists on a single key.
|
|
* @access public
|
|
*/
|
|
function __construct($query = false) {
|
|
parent::__construct($query);
|
|
}
|
|
|
|
/**
|
|
* HTTP request method.
|
|
* @return string Always HEAD.
|
|
* @access public
|
|
*/
|
|
function getMethod() {
|
|
return 'HEAD';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bundle of URL parameters for a DELETE request.
|
|
* @package SimpleTest
|
|
* @subpackage WebTester
|
|
*/
|
|
class SimpleDeleteEncoding extends SimpleGetEncoding {
|
|
|
|
/**
|
|
* Starts empty.
|
|
* @param array $query Hash of parameters.
|
|
* Multiple values are
|
|
* as lists on a single key.
|
|
* @access public
|
|
*/
|
|
function __construct($query = false) {
|
|
parent::__construct($query);
|
|
}
|
|
|
|
/**
|
|
* HTTP request method.
|
|
* @return string Always DELETE.
|
|
* @access public
|
|
*/
|
|
function getMethod() {
|
|
return 'DELETE';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bundles an entity-body for transporting
|
|
* a raw content payload with the request.
|
|
* @package SimpleTest
|
|
* @subpackage WebTester
|
|
*/
|
|
class SimpleEntityEncoding extends SimpleEncoding {
|
|
private $content_type;
|
|
private $body;
|
|
|
|
function __construct($query = false, $content_type = false) {
|
|
$this->content_type = $content_type;
|
|
if (is_string($query)) {
|
|
$this->body = $query;
|
|
parent::__construct();
|
|
} else {
|
|
parent::__construct($query);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the media type of the entity body
|
|
* @return string
|
|
* @access public
|
|
*/
|
|
function getContentType() {
|
|
if (!$this->content_type) {
|
|
return ($this->body) ? 'text/plain' : 'application/x-www-form-urlencoded';
|
|
}
|
|
return $this->content_type;
|
|
}
|
|
|
|
/**
|
|
* Dispatches the form headers down the socket.
|
|
* @param SimpleSocket $socket Socket to write to.
|
|
* @access public
|
|
*/
|
|
function writeHeadersTo(&$socket) {
|
|
$socket->write("Content-Length: " . (integer)strlen($this->encode()) . "\r\n");
|
|
$socket->write("Content-Type: " . $this->getContentType() . "\r\n");
|
|
}
|
|
|
|
/**
|
|
* Dispatches the form data down the socket.
|
|
* @param SimpleSocket $socket Socket to write to.
|
|
* @access public
|
|
*/
|
|
function writeTo(&$socket) {
|
|
$socket->write($this->encode());
|
|
}
|
|
|
|
/**
|
|
* Renders the request body
|
|
* @return Encoded entity body
|
|
* @access protected
|
|
*/
|
|
protected function encode() {
|
|
return ($this->body) ? $this->body : parent::encode();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bundle of POST parameters. Can include
|
|
* repeated parameters.
|
|
* @package SimpleTest
|
|
* @subpackage WebTester
|
|
*/
|
|
class SimplePostEncoding extends SimpleEntityEncoding {
|
|
|
|
/**
|
|
* Starts empty.
|
|
* @param array $query Hash of parameters.
|
|
* Multiple values are
|
|
* as lists on a single key.
|
|
* @access public
|
|
*/
|
|
function __construct($query = false, $content_type = false) {
|
|
if (is_array($query) and $this->hasMoreThanOneLevel($query)) {
|
|
$query = $this->rewriteArrayWithMultipleLevels($query);
|
|
}
|
|
parent::__construct($query, $content_type);
|
|
}
|
|
|
|
function hasMoreThanOneLevel($query) {
|
|
foreach ($query as $key => $value) {
|
|
if (is_array($value)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function rewriteArrayWithMultipleLevels($query) {
|
|
$query_ = array();
|
|
foreach ($query as $key => $value) {
|
|
if (is_array($value)) {
|
|
foreach ($value as $sub_key => $sub_value) {
|
|
$query_[$key."[".$sub_key."]"] = $sub_value;
|
|
}
|
|
} else {
|
|
$query_[$key] = $value;
|
|
}
|
|
}
|
|
if ($this->hasMoreThanOneLevel($query_)) {
|
|
$query_ = $this->rewriteArrayWithMultipleLevels($query_);
|
|
}
|
|
|
|
return $query_;
|
|
}
|
|
|
|
/**
|
|
* HTTP request method.
|
|
* @return string Always POST.
|
|
* @access public
|
|
*/
|
|
function getMethod() {
|
|
return 'POST';
|
|
}
|
|
|
|
/**
|
|
* Renders the query string as a URL encoded
|
|
* request part for attaching to a URL.
|
|
* @return string Part of URL.
|
|
* @access public
|
|
*/
|
|
function asUrlRequest() {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Encoded entity body for a PUT request.
|
|
* @package SimpleTest
|
|
* @subpackage WebTester
|
|
*/
|
|
class SimplePutEncoding extends SimpleEntityEncoding {
|
|
|
|
/**
|
|
* Starts empty.
|
|
* @param array $query Hash of parameters.
|
|
* Multiple values are
|
|
* as lists on a single key.
|
|
* @access public
|
|
*/
|
|
function __construct($query = false, $content_type = false) {
|
|
parent::__construct($query, $content_type);
|
|
}
|
|
|
|
/**
|
|
* HTTP request method.
|
|
* @return string Always PUT.
|
|
* @access public
|
|
*/
|
|
function getMethod() {
|
|
return 'PUT';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bundle of POST parameters in the multipart
|
|
* format. Can include file uploads.
|
|
* @package SimpleTest
|
|
* @subpackage WebTester
|
|
*/
|
|
class SimpleMultipartEncoding extends SimplePostEncoding {
|
|
private $boundary;
|
|
|
|
/**
|
|
* Starts empty.
|
|
* @param array $query Hash of parameters.
|
|
* Multiple values are
|
|
* as lists on a single key.
|
|
* @access public
|
|
*/
|
|
function __construct($query = false, $boundary = false) {
|
|
parent::__construct($query);
|
|
$this->boundary = ($boundary === false ? uniqid('st') : $boundary);
|
|
}
|
|
|
|
/**
|
|
* Dispatches the form headers down the socket.
|
|
* @param SimpleSocket $socket Socket to write to.
|
|
* @access public
|
|
*/
|
|
function writeHeadersTo(&$socket) {
|
|
$socket->write("Content-Length: " . (integer)strlen($this->encode()) . "\r\n");
|
|
$socket->write("Content-Type: multipart/form-data; boundary=" . $this->boundary . "\r\n");
|
|
}
|
|
|
|
/**
|
|
* Dispatches the form data down the socket.
|
|
* @param SimpleSocket $socket Socket to write to.
|
|
* @access public
|
|
*/
|
|
function writeTo(&$socket) {
|
|
$socket->write($this->encode());
|
|
}
|
|
|
|
/**
|
|
* Renders the query string as a URL encoded
|
|
* request part.
|
|
* @return string Part of URL.
|
|
* @access public
|
|
*/
|
|
function encode() {
|
|
$stream = '';
|
|
foreach ($this->getAll() as $pair) {
|
|
$stream .= "--" . $this->boundary . "\r\n";
|
|
$stream .= $pair->asMime() . "\r\n";
|
|
}
|
|
$stream .= "--" . $this->boundary . "--\r\n";
|
|
return $stream;
|
|
}
|
|
}
|
|
?>
|