<?php /** * base include file for SimpleTest * @package SimpleTest * @subpackage WebTester * @version $Id$ */ /**#@+ * include other SimpleTest class files */ require_once(dirname(__FILE__) . '/socket.php'); /**#@-*/ /** * Single post parameter. * @package SimpleTest * @subpackage WebTester */ class SimpleEncodedPair { protected $_key; protected $_value; /** * Stashes the data for rendering later. * @param string $key Form element name. * @param string $value Data to send. */ function SimpleEncodedPair($key, $value) { $this->_key = $key; $this->_value = $value; } /** * The pair as a single string. * @return string Encoded pair. * @access public */ function asRequest() { return $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 { protected $_key; protected $_content; protected $_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 SimpleAttachment($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 */ 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 */ 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 { protected $_request; /** * Starts empty. * @param array $query Hash of parameters. * Multiple values are * as lists on a single key. * @access public */ function SimpleEncoding($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 */ 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 */ 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 SimpleGetEncoding($query = false) { $this->SimpleEncoding($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 SimpleHeadEncoding($query = false) { $this->SimpleGetEncoding($query); } /** * HTTP request method. * @return string Always HEAD. * @access public */ function getMethod() { return 'HEAD'; } } /** * Bundle of POST parameters. Can include * repeated parameters. * @package SimpleTest * @subpackage WebTester */ class SimplePostEncoding extends SimpleEncoding { /** * Starts empty. * @param array $query Hash of parameters. * Multiple values are * as lists on a single key. * @access public */ function SimplePostEncoding($query = false) { $this->SimpleEncoding($query); } /** * HTTP request method. * @return string Always POST. * @access public */ function getMethod() { return 'POST'; } /** * 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: application/x-www-form-urlencoded\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 for attaching to a URL. * @return string Part of URL. * @access public */ function asUrlRequest() { return ''; } } /** * Bundle of POST parameters in the multipart * format. Can include file uploads. * @package SimpleTest * @subpackage WebTester */ class SimpleMultipartEncoding extends SimplePostEncoding { protected $_boundary; /** * Starts empty. * @param array $query Hash of parameters. * Multiple values are * as lists on a single key. * @access public */ function SimpleMultipartEncoding($query = false, $boundary = false) { $this->SimplePostEncoding($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->_request as $pair) { $stream .= "--" . $this->_boundary . "\r\n"; $stream .= $pair->asMime() . "\r\n"; } $stream .= "--" . $this->_boundary . "--\r\n"; return $stream; } } ?>