mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
MINOR Readded sapphire/thirdparty modules without svn:externals
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/branches/2.3@99765 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
add3165333
commit
da691ecb0c
296
thirdparty/jsmin/JSMin.php
vendored
Normal file
296
thirdparty/jsmin/JSMin.php
vendored
Normal file
@ -0,0 +1,296 @@
|
||||
<?php
|
||||
/**
|
||||
* jsmin.php - PHP implementation of Douglas Crockford's JSMin.
|
||||
*
|
||||
* This is pretty much a direct port of jsmin.c to PHP with just a few
|
||||
* PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
|
||||
* outputs to stdout, this library accepts a string as input and returns another
|
||||
* string as output.
|
||||
*
|
||||
* PHP 5 or higher is required.
|
||||
*
|
||||
* Permission is hereby granted to use this version of the library under the
|
||||
* same terms as jsmin.c, which has the following license:
|
||||
*
|
||||
* --
|
||||
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||
*
|
||||
* 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 shall be used for Good, not Evil.
|
||||
*
|
||||
* 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.
|
||||
* --
|
||||
*
|
||||
* @package JSMin
|
||||
* @author Ryan Grove <ryan@wonko.com>
|
||||
* @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
|
||||
* @copyright 2007 Ryan Grove <ryan@wonko.com> (PHP port)
|
||||
* @license http://opensource.org/licenses/mit-license.php MIT License
|
||||
* @version 1.1.0 (2007-06-01)
|
||||
* @link http://code.google.com/p/jsmin-php/
|
||||
*/
|
||||
|
||||
class JSMin {
|
||||
const ORD_LF = 10;
|
||||
const ORD_SPACE = 32;
|
||||
|
||||
protected $a = '';
|
||||
protected $b = '';
|
||||
protected $input = '';
|
||||
protected $inputIndex = 0;
|
||||
protected $inputLength = 0;
|
||||
protected $lookAhead = null;
|
||||
protected $output = array();
|
||||
|
||||
// -- Public Static Methods --------------------------------------------------
|
||||
|
||||
public static function minify($js) {
|
||||
$jsmin = new JSMin($js);
|
||||
return $jsmin->min();
|
||||
}
|
||||
|
||||
// -- Public Instance Methods ------------------------------------------------
|
||||
|
||||
public function __construct($input) {
|
||||
$this->input = str_replace("\r\n", "\n", $input);
|
||||
$this->inputLength = strlen($this->input);
|
||||
}
|
||||
|
||||
// -- Protected Instance Methods ---------------------------------------------
|
||||
|
||||
protected function action($d) {
|
||||
switch($d) {
|
||||
case 1:
|
||||
$this->output[] = $this->a;
|
||||
|
||||
case 2:
|
||||
$this->a = $this->b;
|
||||
|
||||
if ($this->a === "'" || $this->a === '"') {
|
||||
for (;;) {
|
||||
$this->output[] = $this->a;
|
||||
$this->a = $this->get();
|
||||
|
||||
if ($this->a === $this->b) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ord($this->a) <= self::ORD_LF) {
|
||||
throw new JSMinException('Unterminated string literal.');
|
||||
}
|
||||
|
||||
if ($this->a === '\\') {
|
||||
$this->output[] = $this->a;
|
||||
$this->a = $this->get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case 3:
|
||||
$this->b = $this->next();
|
||||
|
||||
if ($this->b === '/' && (
|
||||
$this->a === '(' || $this->a === ',' || $this->a === '=' ||
|
||||
$this->a === ':' || $this->a === '[' || $this->a === '!' ||
|
||||
$this->a === '&' || $this->a === '|' || $this->a === '?')) {
|
||||
|
||||
$this->output[] = $this->a;
|
||||
$this->output[] = $this->b;
|
||||
|
||||
for (;;) {
|
||||
$this->a = $this->get();
|
||||
|
||||
if ($this->a === '/') {
|
||||
break;
|
||||
}
|
||||
elseif ($this->a === '\\') {
|
||||
$this->output[] = $this->a;
|
||||
$this->a = $this->get();
|
||||
}
|
||||
elseif (ord($this->a) <= self::ORD_LF) {
|
||||
throw new JSMinException('Unterminated regular expression '.
|
||||
'literal.');
|
||||
}
|
||||
|
||||
$this->output[] = $this->a;
|
||||
}
|
||||
|
||||
$this->b = $this->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function get() {
|
||||
$c = $this->lookAhead;
|
||||
$this->lookAhead = null;
|
||||
|
||||
if ($c === null) {
|
||||
if ($this->inputIndex < $this->inputLength) {
|
||||
$c = $this->input[$this->inputIndex];
|
||||
$this->inputIndex += 1;
|
||||
}
|
||||
else {
|
||||
$c = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($c === "\r") {
|
||||
return "\n";
|
||||
}
|
||||
|
||||
if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
|
||||
return $c;
|
||||
}
|
||||
|
||||
return ' ';
|
||||
}
|
||||
|
||||
protected function isAlphaNum($c) {
|
||||
return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
|
||||
}
|
||||
|
||||
protected function min() {
|
||||
$this->a = "\n";
|
||||
$this->action(3);
|
||||
|
||||
while ($this->a !== null) {
|
||||
switch ($this->a) {
|
||||
case ' ':
|
||||
if ($this->isAlphaNum($this->b)) {
|
||||
$this->action(1);
|
||||
}
|
||||
else {
|
||||
$this->action(2);
|
||||
}
|
||||
break;
|
||||
|
||||
case "\n":
|
||||
switch ($this->b) {
|
||||
case '{':
|
||||
case '[':
|
||||
case '(':
|
||||
case '+':
|
||||
case '-':
|
||||
$this->action(1);
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
$this->action(3);
|
||||
break;
|
||||
|
||||
default:
|
||||
if ($this->isAlphaNum($this->b)) {
|
||||
$this->action(1);
|
||||
}
|
||||
else {
|
||||
$this->action(2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
switch ($this->b) {
|
||||
case ' ':
|
||||
if ($this->isAlphaNum($this->a)) {
|
||||
$this->action(1);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->action(3);
|
||||
break;
|
||||
|
||||
case "\n":
|
||||
switch ($this->a) {
|
||||
case '}':
|
||||
case ']':
|
||||
case ')':
|
||||
case '+':
|
||||
case '-':
|
||||
case '"':
|
||||
case "'":
|
||||
$this->action(1);
|
||||
break;
|
||||
|
||||
default:
|
||||
if ($this->isAlphaNum($this->a)) {
|
||||
$this->action(1);
|
||||
}
|
||||
else {
|
||||
$this->action(3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->action(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return implode('', $this->output);
|
||||
}
|
||||
|
||||
protected function next() {
|
||||
$c = $this->get();
|
||||
|
||||
if ($c === '/') {
|
||||
switch($this->peek()) {
|
||||
case '/':
|
||||
for (;;) {
|
||||
$c = $this->get();
|
||||
|
||||
if (ord($c) <= self::ORD_LF) {
|
||||
return $c;
|
||||
}
|
||||
}
|
||||
|
||||
case '*':
|
||||
$this->get();
|
||||
|
||||
for (;;) {
|
||||
switch($this->get()) {
|
||||
case '*':
|
||||
if ($this->peek() === '/') {
|
||||
$this->get();
|
||||
return ' ';
|
||||
}
|
||||
break;
|
||||
|
||||
case null:
|
||||
throw new JSMinException('Unterminated comment.');
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return $c;
|
||||
}
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
protected function peek() {
|
||||
$this->lookAhead = $this->get();
|
||||
return $this->lookAhead;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Exceptions ---------------------------------------------------------------
|
||||
class JSMinException extends Exception {}
|
||||
?>
|
806
thirdparty/json/JSON.php
vendored
Normal file
806
thirdparty/json/JSON.php
vendored
Normal file
@ -0,0 +1,806 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Converts to and from JSON format.
|
||||
*
|
||||
* JSON (JavaScript Object Notation) is a lightweight data-interchange
|
||||
* format. It is easy for humans to read and write. It is easy for machines
|
||||
* to parse and generate. It is based on a subset of the JavaScript
|
||||
* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
|
||||
* This feature can also be found in Python. JSON is a text format that is
|
||||
* completely language independent but uses conventions that are familiar
|
||||
* to programmers of the C-family of languages, including C, C++, C#, Java,
|
||||
* JavaScript, Perl, TCL, and many others. These properties make JSON an
|
||||
* ideal data-interchange language.
|
||||
*
|
||||
* This package provides a simple encoder and decoder for JSON notation. It
|
||||
* is intended for use with client-side Javascript applications that make
|
||||
* use of HTTPRequest to perform server communication functions - data can
|
||||
* be encoded into JSON notation for use in a client-side javascript, or
|
||||
* decoded from incoming Javascript requests. JSON format is native to
|
||||
* Javascript, and can be directly eval()'ed with no further parsing
|
||||
* overhead
|
||||
*
|
||||
* All strings should be in ASCII or UTF-8 format!
|
||||
*
|
||||
* LICENSE: Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met: Redistributions of source code must retain the
|
||||
* above copyright notice, this list of conditions and the following
|
||||
* disclaimer. 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``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 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
|
||||
* @package Services_JSON
|
||||
* @author Michal Migurski <mike-json@teczno.com>
|
||||
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
|
||||
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
|
||||
* @copyright 2005 Michal Migurski
|
||||
* @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
|
||||
* @license http://www.opensource.org/licenses/bsd-license.php
|
||||
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
|
||||
*/
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_SLICE', 1);
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_IN_STR', 2);
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_IN_ARR', 3);
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_IN_OBJ', 4);
|
||||
|
||||
/**
|
||||
* Marker constant for Services_JSON::decode(), used to flag stack state
|
||||
*/
|
||||
define('SERVICES_JSON_IN_CMT', 5);
|
||||
|
||||
/**
|
||||
* Behavior switch for Services_JSON::decode()
|
||||
*/
|
||||
define('SERVICES_JSON_LOOSE_TYPE', 16);
|
||||
|
||||
/**
|
||||
* Behavior switch for Services_JSON::decode()
|
||||
*/
|
||||
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
|
||||
|
||||
/**
|
||||
* Converts to and from JSON format.
|
||||
*
|
||||
* Brief example of use:
|
||||
*
|
||||
* <code>
|
||||
* // create a new instance of Services_JSON
|
||||
* $json = new Services_JSON();
|
||||
*
|
||||
* // convert a complexe value to JSON notation, and send it to the browser
|
||||
* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
|
||||
* $output = $json->encode($value);
|
||||
*
|
||||
* print($output);
|
||||
* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
|
||||
*
|
||||
* // accept incoming POST data, assumed to be in JSON notation
|
||||
* $input = file_get_contents('php://input', 1000000);
|
||||
* $value = $json->decode($input);
|
||||
* </code>
|
||||
*/
|
||||
class Services_JSON
|
||||
{
|
||||
/**
|
||||
* constructs a new JSON instance
|
||||
*
|
||||
* @param int $use object behavior flags; combine with boolean-OR
|
||||
*
|
||||
* possible values:
|
||||
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
|
||||
* "{...}" syntax creates associative arrays
|
||||
* instead of objects in decode().
|
||||
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
|
||||
* Values which can't be encoded (e.g. resources)
|
||||
* appear as NULL instead of throwing errors.
|
||||
* By default, a deeply-nested resource will
|
||||
* bubble up with an error, so all return values
|
||||
* from encode() should be checked with isError()
|
||||
*/
|
||||
function Services_JSON($use = 0)
|
||||
{
|
||||
$this->use = $use;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a string from one UTF-16 char to one UTF-8 char
|
||||
*
|
||||
* Normally should be handled by mb_convert_encoding, but
|
||||
* provides a slower PHP-only method for installations
|
||||
* that lack the multibye string extension.
|
||||
*
|
||||
* @param string $utf16 UTF-16 character
|
||||
* @return string UTF-8 character
|
||||
* @access private
|
||||
*/
|
||||
function utf162utf8($utf16)
|
||||
{
|
||||
// oh please oh please oh please oh please oh please
|
||||
if(function_exists('mb_convert_encoding')) {
|
||||
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
|
||||
}
|
||||
|
||||
$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
|
||||
|
||||
switch(true) {
|
||||
case ((0x7F & $bytes) == $bytes):
|
||||
// this case should never be reached, because we are in ASCII range
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr(0x7F & $bytes);
|
||||
|
||||
case (0x07FF & $bytes) == $bytes:
|
||||
// return a 2-byte UTF-8 character
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr(0xC0 | (($bytes >> 6) & 0x1F))
|
||||
. chr(0x80 | ($bytes & 0x3F));
|
||||
|
||||
case (0xFFFF & $bytes) == $bytes:
|
||||
// return a 3-byte UTF-8 character
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr(0xE0 | (($bytes >> 12) & 0x0F))
|
||||
. chr(0x80 | (($bytes >> 6) & 0x3F))
|
||||
. chr(0x80 | ($bytes & 0x3F));
|
||||
}
|
||||
|
||||
// ignoring UTF-32 for now, sorry
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a string from one UTF-8 char to one UTF-16 char
|
||||
*
|
||||
* Normally should be handled by mb_convert_encoding, but
|
||||
* provides a slower PHP-only method for installations
|
||||
* that lack the multibye string extension.
|
||||
*
|
||||
* @param string $utf8 UTF-8 character
|
||||
* @return string UTF-16 character
|
||||
* @access private
|
||||
*/
|
||||
function utf82utf16($utf8)
|
||||
{
|
||||
// oh please oh please oh please oh please oh please
|
||||
if(function_exists('mb_convert_encoding')) {
|
||||
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
|
||||
}
|
||||
|
||||
switch(strlen($utf8)) {
|
||||
case 1:
|
||||
// this case should never be reached, because we are in ASCII range
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return $utf8;
|
||||
|
||||
case 2:
|
||||
// return a UTF-16 character from a 2-byte UTF-8 char
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr(0x07 & (ord($utf8{0}) >> 2))
|
||||
. chr((0xC0 & (ord($utf8{0}) << 6))
|
||||
| (0x3F & ord($utf8{1})));
|
||||
|
||||
case 3:
|
||||
// return a UTF-16 character from a 3-byte UTF-8 char
|
||||
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
return chr((0xF0 & (ord($utf8{0}) << 4))
|
||||
| (0x0F & (ord($utf8{1}) >> 2)))
|
||||
. chr((0xC0 & (ord($utf8{1}) << 6))
|
||||
| (0x7F & ord($utf8{2})));
|
||||
}
|
||||
|
||||
// ignoring UTF-32 for now, sorry
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* encodes an arbitrary variable into JSON format
|
||||
*
|
||||
* @param mixed $var any number, boolean, string, array, or object to be encoded.
|
||||
* see argument 1 to Services_JSON() above for array-parsing behavior.
|
||||
* if var is a strng, note that encode() always expects it
|
||||
* to be in ASCII or UTF-8 format!
|
||||
*
|
||||
* @return mixed JSON string representation of input var or an error if a problem occurs
|
||||
* @access public
|
||||
*/
|
||||
function encode($var)
|
||||
{
|
||||
switch (gettype($var)) {
|
||||
case 'boolean':
|
||||
return $var ? 'true' : 'false';
|
||||
|
||||
case 'NULL':
|
||||
return 'null';
|
||||
|
||||
case 'integer':
|
||||
return (int) $var;
|
||||
|
||||
case 'double':
|
||||
case 'float':
|
||||
return (float) $var;
|
||||
|
||||
case 'string':
|
||||
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
|
||||
$ascii = '';
|
||||
$strlen_var = strlen($var);
|
||||
|
||||
/*
|
||||
* Iterate over every character in the string,
|
||||
* escaping with a slash or encoding to UTF-8 where necessary
|
||||
*/
|
||||
for ($c = 0; $c < $strlen_var; ++$c) {
|
||||
|
||||
$ord_var_c = ord($var{$c});
|
||||
|
||||
switch (true) {
|
||||
case $ord_var_c == 0x08:
|
||||
$ascii .= '\b';
|
||||
break;
|
||||
case $ord_var_c == 0x09:
|
||||
$ascii .= '\t';
|
||||
break;
|
||||
case $ord_var_c == 0x0A:
|
||||
$ascii .= '\n';
|
||||
break;
|
||||
case $ord_var_c == 0x0C:
|
||||
$ascii .= '\f';
|
||||
break;
|
||||
case $ord_var_c == 0x0D:
|
||||
$ascii .= '\r';
|
||||
break;
|
||||
|
||||
case $ord_var_c == 0x22:
|
||||
case $ord_var_c == 0x2F:
|
||||
case $ord_var_c == 0x5C:
|
||||
// double quote, slash, slosh
|
||||
$ascii .= '\\'.$var{$c};
|
||||
break;
|
||||
|
||||
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
|
||||
// characters U-00000000 - U-0000007F (same as ASCII)
|
||||
$ascii .= $var{$c};
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xE0) == 0xC0):
|
||||
// characters U-00000080 - U-000007FF, mask 110XXXXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c, ord($var{$c + 1}));
|
||||
$c += 1;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xF0) == 0xE0):
|
||||
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c,
|
||||
ord($var{$c + 1}),
|
||||
ord($var{$c + 2}));
|
||||
$c += 2;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xF8) == 0xF0):
|
||||
// characters U-00010000 - U-001FFFFF, mask 11110XXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c,
|
||||
ord($var{$c + 1}),
|
||||
ord($var{$c + 2}),
|
||||
ord($var{$c + 3}));
|
||||
$c += 3;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xFC) == 0xF8):
|
||||
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c,
|
||||
ord($var{$c + 1}),
|
||||
ord($var{$c + 2}),
|
||||
ord($var{$c + 3}),
|
||||
ord($var{$c + 4}));
|
||||
$c += 4;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
|
||||
case (($ord_var_c & 0xFE) == 0xFC):
|
||||
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$char = pack('C*', $ord_var_c,
|
||||
ord($var{$c + 1}),
|
||||
ord($var{$c + 2}),
|
||||
ord($var{$c + 3}),
|
||||
ord($var{$c + 4}),
|
||||
ord($var{$c + 5}));
|
||||
$c += 5;
|
||||
$utf16 = $this->utf82utf16($char);
|
||||
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return '"'.$ascii.'"';
|
||||
|
||||
case 'array':
|
||||
/*
|
||||
* As per JSON spec if any array key is not an integer
|
||||
* we must treat the the whole array as an object. We
|
||||
* also try to catch a sparsely populated associative
|
||||
* array with numeric keys here because some JS engines
|
||||
* will create an array with empty indexes up to
|
||||
* max_index which can cause memory issues and because
|
||||
* the keys, which may be relevant, will be remapped
|
||||
* otherwise.
|
||||
*
|
||||
* As per the ECMA and JSON specification an object may
|
||||
* have any string as a property. Unfortunately due to
|
||||
* a hole in the ECMA specification if the key is a
|
||||
* ECMA reserved word or starts with a digit the
|
||||
* parameter is only accessible using ECMAScript's
|
||||
* bracket notation.
|
||||
*/
|
||||
|
||||
// treat as a JSON object
|
||||
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
|
||||
$properties = array_map(array($this, 'name_value'),
|
||||
array_keys($var),
|
||||
array_values($var));
|
||||
|
||||
foreach($properties as $property) {
|
||||
if(Services_JSON::isError($property)) {
|
||||
return $property;
|
||||
}
|
||||
}
|
||||
|
||||
return '{' . join(',', $properties) . '}';
|
||||
}
|
||||
|
||||
// treat it like a regular array
|
||||
$elements = array_map(array($this, 'encode'), $var);
|
||||
|
||||
foreach($elements as $element) {
|
||||
if(Services_JSON::isError($element)) {
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
|
||||
return '[' . join(',', $elements) . ']';
|
||||
|
||||
case 'object':
|
||||
$vars = get_object_vars($var);
|
||||
|
||||
$properties = array_map(array($this, 'name_value'),
|
||||
array_keys($vars),
|
||||
array_values($vars));
|
||||
|
||||
foreach($properties as $property) {
|
||||
if(Services_JSON::isError($property)) {
|
||||
return $property;
|
||||
}
|
||||
}
|
||||
|
||||
return '{' . join(',', $properties) . '}';
|
||||
|
||||
default:
|
||||
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
|
||||
? 'null'
|
||||
: new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* array-walking function for use in generating JSON-formatted name-value pairs
|
||||
*
|
||||
* @param string $name name of key to use
|
||||
* @param mixed $value reference to an array element to be encoded
|
||||
*
|
||||
* @return string JSON-formatted name-value pair, like '"name":value'
|
||||
* @access private
|
||||
*/
|
||||
function name_value($name, $value)
|
||||
{
|
||||
$encoded_value = $this->encode($value);
|
||||
|
||||
if(Services_JSON::isError($encoded_value)) {
|
||||
return $encoded_value;
|
||||
}
|
||||
|
||||
return $this->encode(strval($name)) . ':' . $encoded_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* reduce a string by removing leading and trailing comments and whitespace
|
||||
*
|
||||
* @param $str string string value to strip of comments and whitespace
|
||||
*
|
||||
* @return string string value stripped of comments and whitespace
|
||||
* @access private
|
||||
*/
|
||||
function reduce_string($str)
|
||||
{
|
||||
$str = preg_replace(array(
|
||||
|
||||
// eliminate single line comments in '// ...' form
|
||||
'#^\s*//(.+)$#m',
|
||||
|
||||
// eliminate multi-line comments in '/* ... */' form, at start of string
|
||||
'#^\s*/\*(.+)\*/#Us',
|
||||
|
||||
// eliminate multi-line comments in '/* ... */' form, at end of string
|
||||
'#/\*(.+)\*/\s*$#Us'
|
||||
|
||||
), '', $str);
|
||||
|
||||
// eliminate extraneous space
|
||||
return trim($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* decodes a JSON string into appropriate variable
|
||||
*
|
||||
* @param string $str JSON-formatted string
|
||||
*
|
||||
* @return mixed number, boolean, string, array, or object
|
||||
* corresponding to given JSON input string.
|
||||
* See argument 1 to Services_JSON() above for object-output behavior.
|
||||
* Note that decode() always returns strings
|
||||
* in ASCII or UTF-8 format!
|
||||
* @access public
|
||||
*/
|
||||
function decode($str)
|
||||
{
|
||||
$str = $this->reduce_string($str);
|
||||
|
||||
switch (strtolower($str)) {
|
||||
case 'true':
|
||||
return true;
|
||||
|
||||
case 'false':
|
||||
return false;
|
||||
|
||||
case 'null':
|
||||
return null;
|
||||
|
||||
default:
|
||||
$m = array();
|
||||
|
||||
if (is_numeric($str)) {
|
||||
// Lookie-loo, it's a number
|
||||
|
||||
// This would work on its own, but I'm trying to be
|
||||
// good about returning integers where appropriate:
|
||||
// return (float)$str;
|
||||
|
||||
// Return float or int, as appropriate
|
||||
return ((float)$str == (integer)$str)
|
||||
? (integer)$str
|
||||
: (float)$str;
|
||||
|
||||
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
|
||||
// STRINGS RETURNED IN UTF-8 FORMAT
|
||||
$delim = substr($str, 0, 1);
|
||||
$chrs = substr($str, 1, -1);
|
||||
$utf8 = '';
|
||||
$strlen_chrs = strlen($chrs);
|
||||
|
||||
for ($c = 0; $c < $strlen_chrs; ++$c) {
|
||||
|
||||
$substr_chrs_c_2 = substr($chrs, $c, 2);
|
||||
$ord_chrs_c = ord($chrs{$c});
|
||||
|
||||
switch (true) {
|
||||
case $substr_chrs_c_2 == '\b':
|
||||
$utf8 .= chr(0x08);
|
||||
++$c;
|
||||
break;
|
||||
case $substr_chrs_c_2 == '\t':
|
||||
$utf8 .= chr(0x09);
|
||||
++$c;
|
||||
break;
|
||||
case $substr_chrs_c_2 == '\n':
|
||||
$utf8 .= chr(0x0A);
|
||||
++$c;
|
||||
break;
|
||||
case $substr_chrs_c_2 == '\f':
|
||||
$utf8 .= chr(0x0C);
|
||||
++$c;
|
||||
break;
|
||||
case $substr_chrs_c_2 == '\r':
|
||||
$utf8 .= chr(0x0D);
|
||||
++$c;
|
||||
break;
|
||||
|
||||
case $substr_chrs_c_2 == '\\"':
|
||||
case $substr_chrs_c_2 == '\\\'':
|
||||
case $substr_chrs_c_2 == '\\\\':
|
||||
case $substr_chrs_c_2 == '\\/':
|
||||
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
|
||||
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
|
||||
$utf8 .= $chrs{++$c};
|
||||
}
|
||||
break;
|
||||
|
||||
case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
|
||||
// single, escaped unicode character
|
||||
$utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
|
||||
. chr(hexdec(substr($chrs, ($c + 4), 2)));
|
||||
$utf8 .= $this->utf162utf8($utf16);
|
||||
$c += 5;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
|
||||
$utf8 .= $chrs{$c};
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xE0) == 0xC0:
|
||||
// characters U-00000080 - U-000007FF, mask 110XXXXX
|
||||
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 2);
|
||||
++$c;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xF0) == 0xE0:
|
||||
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 3);
|
||||
$c += 2;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xF8) == 0xF0:
|
||||
// characters U-00010000 - U-001FFFFF, mask 11110XXX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 4);
|
||||
$c += 3;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xFC) == 0xF8:
|
||||
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 5);
|
||||
$c += 4;
|
||||
break;
|
||||
|
||||
case ($ord_chrs_c & 0xFE) == 0xFC:
|
||||
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
||||
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
||||
$utf8 .= substr($chrs, $c, 6);
|
||||
$c += 5;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $utf8;
|
||||
|
||||
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
|
||||
// array, or object notation
|
||||
|
||||
if ($str{0} == '[') {
|
||||
$stk = array(SERVICES_JSON_IN_ARR);
|
||||
$arr = array();
|
||||
} else {
|
||||
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
||||
$stk = array(SERVICES_JSON_IN_OBJ);
|
||||
$obj = array();
|
||||
} else {
|
||||
$stk = array(SERVICES_JSON_IN_OBJ);
|
||||
$obj = new stdClass();
|
||||
}
|
||||
}
|
||||
|
||||
array_push($stk, array('what' => SERVICES_JSON_SLICE,
|
||||
'where' => 0,
|
||||
'delim' => false));
|
||||
|
||||
$chrs = substr($str, 1, -1);
|
||||
$chrs = $this->reduce_string($chrs);
|
||||
|
||||
if ($chrs == '') {
|
||||
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
||||
return $arr;
|
||||
|
||||
} else {
|
||||
return $obj;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//print("\nparsing {$chrs}\n");
|
||||
|
||||
$strlen_chrs = strlen($chrs);
|
||||
|
||||
for ($c = 0; $c <= $strlen_chrs; ++$c) {
|
||||
|
||||
$top = end($stk);
|
||||
$substr_chrs_c_2 = substr($chrs, $c, 2);
|
||||
|
||||
if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
|
||||
// found a comma that is not inside a string, array, etc.,
|
||||
// OR we've reached the end of the character list
|
||||
$slice = substr($chrs, $top['where'], ($c - $top['where']));
|
||||
array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
|
||||
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
||||
|
||||
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
||||
// we are in an array, so just push an element onto the stack
|
||||
array_push($arr, $this->decode($slice));
|
||||
|
||||
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
|
||||
// we are in an object, so figure
|
||||
// out the property name and set an
|
||||
// element in an associative array,
|
||||
// for now
|
||||
$parts = array();
|
||||
|
||||
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
|
||||
// "name":value pair
|
||||
$key = $this->decode($parts[1]);
|
||||
$val = $this->decode($parts[2]);
|
||||
|
||||
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
||||
$obj[$key] = $val;
|
||||
} else {
|
||||
$obj->$key = $val;
|
||||
}
|
||||
} elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
|
||||
// name:value pair, where name is unquoted
|
||||
$key = $parts[1];
|
||||
$val = $this->decode($parts[2]);
|
||||
|
||||
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
||||
$obj[$key] = $val;
|
||||
} else {
|
||||
$obj->$key = $val;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
|
||||
// found a quote, and we are not inside a string
|
||||
array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
|
||||
//print("Found start of string at {$c}\n");
|
||||
|
||||
} elseif (($chrs{$c} == $top['delim']) &&
|
||||
($top['what'] == SERVICES_JSON_IN_STR) &&
|
||||
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
|
||||
// found a quote, we're in a string, and it's not escaped
|
||||
// we know that it's not escaped becase there is _not_ an
|
||||
// odd number of backslashes at the end of the string so far
|
||||
array_pop($stk);
|
||||
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
|
||||
|
||||
} elseif (($chrs{$c} == '[') &&
|
||||
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
||||
// found a left-bracket, and we are in an array, object, or slice
|
||||
array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
|
||||
//print("Found start of array at {$c}\n");
|
||||
|
||||
} elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
|
||||
// found a right-bracket, and we're in an array
|
||||
array_pop($stk);
|
||||
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
||||
|
||||
} elseif (($chrs{$c} == '{') &&
|
||||
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
||||
// found a left-brace, and we are in an array, object, or slice
|
||||
array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
|
||||
//print("Found start of object at {$c}\n");
|
||||
|
||||
} elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
|
||||
// found a right-brace, and we're in an object
|
||||
array_pop($stk);
|
||||
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
||||
|
||||
} elseif (($substr_chrs_c_2 == '/*') &&
|
||||
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
||||
// found a comment start, and we are in an array, object, or slice
|
||||
array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
|
||||
$c++;
|
||||
//print("Found start of comment at {$c}\n");
|
||||
|
||||
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
|
||||
// found a comment end, and we're in one now
|
||||
array_pop($stk);
|
||||
$c++;
|
||||
|
||||
for ($i = $top['where']; $i <= $c; ++$i)
|
||||
$chrs = substr_replace($chrs, ' ', $i, 1);
|
||||
|
||||
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
||||
return $arr;
|
||||
|
||||
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
|
||||
return $obj;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Ultimately, this should just call PEAR::isError()
|
||||
*/
|
||||
function isError($data, $code = null)
|
||||
{
|
||||
if (class_exists('pear')) {
|
||||
return PEAR::isError($data, $code);
|
||||
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
|
||||
is_subclass_of($data, 'services_json_error'))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (class_exists('PEAR_Error')) {
|
||||
|
||||
class Services_JSON_Error extends PEAR_Error
|
||||
{
|
||||
function Services_JSON_Error($message = 'unknown error', $code = null,
|
||||
$mode = null, $options = null, $userinfo = null)
|
||||
{
|
||||
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/**
|
||||
* @todo Ultimately, this class shall be descended from PEAR_Error
|
||||
*/
|
||||
class Services_JSON_Error
|
||||
{
|
||||
function Services_JSON_Error($message = 'unknown error', $code = null,
|
||||
$mode = null, $options = null, $userinfo = null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
21
thirdparty/json/LICENSE
vendored
Normal file
21
thirdparty/json/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
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.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED ``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 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.
|
521
thirdparty/json/Test-JSON.php
vendored
Normal file
521
thirdparty/json/Test-JSON.php
vendored
Normal file
@ -0,0 +1,521 @@
|
||||
<?php
|
||||
// $Id: Test-JSON.php,v 1.28 2006/06/28 05:54:17 migurski Exp $
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
||||
|
||||
/**
|
||||
* Unit tests for Services_JSON.
|
||||
* @see JSON.php
|
||||
*
|
||||
* @category
|
||||
* @package Services_JSON
|
||||
* @author Michal Migurski <mike-json@teczno.com>
|
||||
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
|
||||
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
|
||||
* @copyright 2005 Michal Migurski
|
||||
* @version CVS: $Id: Test-JSON.php,v 1.28 2006/06/28 05:54:17 migurski Exp $
|
||||
* @license http://www.opensource.org/licenses/bsd-license.php
|
||||
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
|
||||
*/
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
require_once 'PHPUnit.php';
|
||||
require_once 'JSON.php';
|
||||
|
||||
class Services_JSON_EncDec_TestCase extends PHPUnit_TestCase {
|
||||
|
||||
function Services_JSON_EncDec_TestCase($name) {
|
||||
$this->PHPUnit_TestCase($name);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->json = new Services_JSON();
|
||||
|
||||
$obj = new stdClass();
|
||||
$obj->a_string = '"he":llo}:{world';
|
||||
$obj->an_array = array(1, 2, 3);
|
||||
$obj->obj = new stdClass();
|
||||
$obj->obj->a_number = 123;
|
||||
|
||||
$this->obj = $obj;
|
||||
$this->obj_j = '{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"obj":{"a_number":123}}';
|
||||
$this->obj_d = 'object with properties, nested object and arrays';
|
||||
|
||||
$this->arr = array(null, true, array(1, 2, 3), "hello\"],[world!");
|
||||
$this->arr_j = '[null,true,[1,2,3],"hello\"],[world!"]';
|
||||
$this->arr_d = 'array with elements and nested arrays';
|
||||
|
||||
$this->str1 = 'hello world';
|
||||
$this->str1_j = '"hello world"';
|
||||
$this->str1_j_ = "'hello world'";
|
||||
$this->str1_d = 'hello world';
|
||||
$this->str1_d_ = 'hello world, double quotes';
|
||||
|
||||
$this->str2 = "hello\t\"world\"";
|
||||
$this->str2_j = '"hello\\t\\"world\\""';
|
||||
$this->str2_d = 'hello world, with tab, double-quotes';
|
||||
|
||||
$this->str3 = "\\\r\n\t\"/";
|
||||
$this->str3_j = '"\\\\\\r\\n\\t\\"\\/"';
|
||||
$this->str3_d = 'backslash, return, newline, tab, double-quote';
|
||||
|
||||
$this->str4 = 'héllö wørłd';
|
||||
$this->str4_j = '"h\u00e9ll\u00f6 w\u00f8r\u0142d"';
|
||||
$this->str4_j_ = '"héllö wørłd"';
|
||||
$this->str4_d = 'hello world, with unicode';
|
||||
}
|
||||
|
||||
function test_to_JSON()
|
||||
{
|
||||
$this->assertEquals('null', $this->json->encode(null), 'type case: null');
|
||||
$this->assertEquals('true', $this->json->encode(true), 'type case: boolean true');
|
||||
$this->assertEquals('false', $this->json->encode(false), 'type case: boolean false');
|
||||
|
||||
$this->assertEquals('1', $this->json->encode(1), 'numeric case: 1');
|
||||
$this->assertEquals('-1', $this->json->encode(-1), 'numeric case: -1');
|
||||
$this->assertEquals('1.000000', $this->json->encode(1.0), 'numeric case: 1.0');
|
||||
$this->assertEquals('1.100000', $this->json->encode(1.1), 'numeric case: 1.1');
|
||||
|
||||
$this->assertEquals($this->str1_j, $this->json->encode($this->str1), "string case: {$this->str1_d}");
|
||||
$this->assertEquals($this->str2_j, $this->json->encode($this->str2), "string case: {$this->str2_d}");
|
||||
$this->assertEquals($this->str3_j, $this->json->encode($this->str3), "string case: {$this->str3_d}");
|
||||
$this->assertEquals($this->str4_j, $this->json->encode($this->str4), "string case: {$this->str4_d}");
|
||||
|
||||
$this->assertEquals($this->arr_j, $this->json->encode($this->arr), "array case: {$this->arr_d}");
|
||||
$this->assertEquals($this->obj_j, $this->json->encode($this->obj), "object case: {$this->obj_d}");
|
||||
}
|
||||
|
||||
function test_from_JSON()
|
||||
{
|
||||
$this->assertEquals(null, $this->json->decode('null'), 'type case: null');
|
||||
$this->assertEquals(true, $this->json->decode('true'), 'type case: boolean true');
|
||||
$this->assertEquals(false, $this->json->decode('false'), 'type case: boolean false');
|
||||
|
||||
$this->assertEquals(1, $this->json->decode('1'), 'numeric case: 1');
|
||||
$this->assertEquals(-1, $this->json->decode('-1'), 'numeric case: -1');
|
||||
$this->assertEquals(1.0, $this->json->decode('1.0'), 'numeric case: 1.0');
|
||||
$this->assertEquals(1.1, $this->json->decode('1.1'), 'numeric case: 1.1');
|
||||
|
||||
$this->assertEquals(11.0, $this->json->decode('1.1e1'), 'numeric case: 1.1e1');
|
||||
$this->assertEquals(11.0, $this->json->decode('1.10e+1'), 'numeric case: 1.10e+1');
|
||||
$this->assertEquals(0.11, $this->json->decode('1.1e-1'), 'numeric case: 1.1e-1');
|
||||
$this->assertEquals(-0.11, $this->json->decode('-1.1e-1'), 'numeric case: -1.1e-1');
|
||||
|
||||
$this->assertEquals($this->str1, $this->json->decode($this->str1_j), "string case: {$this->str1_d}");
|
||||
$this->assertEquals($this->str1, $this->json->decode($this->str1_j_), "string case: {$this->str1_d_}");
|
||||
$this->assertEquals($this->str2, $this->json->decode($this->str2_j), "string case: {$this->str2_d}");
|
||||
$this->assertEquals($this->str3, $this->json->decode($this->str3_j), "string case: {$this->str3_d}");
|
||||
$this->assertEquals($this->str4, $this->json->decode($this->str4_j), "string case: {$this->str4_d}");
|
||||
$this->assertEquals($this->str4, $this->json->decode($this->str4_j_), "string case: {$this->str4_d}");
|
||||
|
||||
$this->assertEquals($this->arr, $this->json->decode($this->arr_j), "array case: {$this->arr_d}");
|
||||
$this->assertEquals($this->obj, $this->json->decode($this->obj_j), "object case: {$this->obj_d}");
|
||||
}
|
||||
|
||||
function test_to_then_from_JSON()
|
||||
{
|
||||
$this->assertEquals(null, $this->json->decode($this->json->encode(null)), 'type case: null');
|
||||
$this->assertEquals(true, $this->json->decode($this->json->encode(true)), 'type case: boolean true');
|
||||
$this->assertEquals(false, $this->json->decode($this->json->encode(false)), 'type case: boolean false');
|
||||
|
||||
$this->assertEquals(1, $this->json->decode($this->json->encode(1)), 'numeric case: 1');
|
||||
$this->assertEquals(-1, $this->json->decode($this->json->encode(-1)), 'numeric case: -1');
|
||||
$this->assertEquals(1.0, $this->json->decode($this->json->encode(1.0)), 'numeric case: 1.0');
|
||||
$this->assertEquals(1.1, $this->json->decode($this->json->encode(1.1)), 'numeric case: 1.1');
|
||||
|
||||
$this->assertEquals($this->str1, $this->json->decode($this->json->encode($this->str1)), "string case: {$this->str1_d}");
|
||||
$this->assertEquals($this->str2, $this->json->decode($this->json->encode($this->str2)), "string case: {$this->str2_d}");
|
||||
$this->assertEquals($this->str3, $this->json->decode($this->json->encode($this->str3)), "string case: {$this->str3_d}");
|
||||
$this->assertEquals($this->str4, $this->json->decode($this->json->encode($this->str4)), "string case: {$this->str4_d}");
|
||||
|
||||
$this->assertEquals($this->arr, $this->json->decode($this->json->encode($this->arr)), "array case: {$this->arr_d}");
|
||||
$this->assertEquals($this->obj, $this->json->decode($this->json->encode($this->obj)), "object case: {$this->obj_d}");
|
||||
}
|
||||
|
||||
function test_from_then_to_JSON()
|
||||
{
|
||||
$this->assertEquals('null', $this->json->encode($this->json->decode('null')), 'type case: null');
|
||||
$this->assertEquals('true', $this->json->encode($this->json->decode('true')), 'type case: boolean true');
|
||||
$this->assertEquals('false', $this->json->encode($this->json->decode('false')), 'type case: boolean false');
|
||||
|
||||
$this->assertEquals('1', $this->json->encode($this->json->decode('1')), 'numeric case: 1');
|
||||
$this->assertEquals('-1', $this->json->encode($this->json->decode('-1')), 'numeric case: -1');
|
||||
$this->assertEquals('1.0', $this->json->encode($this->json->decode('1.0')), 'numeric case: 1.0');
|
||||
$this->assertEquals('1.1', $this->json->encode($this->json->decode('1.1')), 'numeric case: 1.1');
|
||||
|
||||
$this->assertEquals($this->str1_j, $this->json->encode($this->json->decode($this->str1_j)), "string case: {$this->str1_d}");
|
||||
$this->assertEquals($this->str2_j, $this->json->encode($this->json->decode($this->str2_j)), "string case: {$this->str2_d}");
|
||||
$this->assertEquals($this->str3_j, $this->json->encode($this->json->decode($this->str3_j)), "string case: {$this->str3_d}");
|
||||
$this->assertEquals($this->str4_j, $this->json->encode($this->json->decode($this->str4_j)), "string case: {$this->str4_d}");
|
||||
$this->assertEquals($this->str4_j, $this->json->encode($this->json->decode($this->str4_j_)), "string case: {$this->str4_d}");
|
||||
|
||||
$this->assertEquals($this->arr_j, $this->json->encode($this->json->decode($this->arr_j)), "array case: {$this->arr_d}");
|
||||
$this->assertEquals($this->obj_j, $this->json->encode($this->json->decode($this->obj_j)), "object case: {$this->obj_d}");
|
||||
}
|
||||
}
|
||||
|
||||
class Services_JSON_AssocArray_TestCase extends PHPUnit_TestCase {
|
||||
|
||||
function Services_JSON_AssocArray_TestCase($name) {
|
||||
$this->PHPUnit_TestCase($name);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->json_l = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
|
||||
$this->json_s = new Services_JSON();
|
||||
|
||||
$this->arr = array('car1'=> array('color'=> 'tan', 'model' => 'sedan'),
|
||||
'car2' => array('color' => 'red', 'model' => 'sports'));
|
||||
$this->arr_jo = '{"car1":{"color":"tan","model":"sedan"},"car2":{"color":"red","model":"sports"}}';
|
||||
$this->arr_d = 'associative array with nested associative arrays';
|
||||
|
||||
$this->arn = array(0=> array(0=> 'tan\\', 'model\\' => 'sedan'), 1 => array(0 => 'red', 'model' => 'sports'));
|
||||
$this->arn_ja = '[{"0":"tan\\\\","model\\\\":"sedan"},{"0":"red","model":"sports"}]';
|
||||
$this->arn_d = 'associative array with nested associative arrays, and some numeric keys thrown in';
|
||||
|
||||
$this->arrs = array (1 => 'one', 2 => 'two', 5 => 'five');
|
||||
$this->arrs_jo = '{"1":"one","2":"two","5":"five"}';
|
||||
$this->arrs_d = 'associative array numeric keys which are not fully populated in a range of 0 to length-1';
|
||||
}
|
||||
|
||||
function test_type()
|
||||
{
|
||||
$this->assertEquals('array', gettype($this->json_l->decode($this->arn_ja)), "loose type should be array");
|
||||
$this->assertEquals('array', gettype($this->json_s->decode($this->arn_ja)), "strict type should be array");
|
||||
}
|
||||
|
||||
function test_to_JSON()
|
||||
{
|
||||
// both strict and loose JSON should result in an object
|
||||
$this->assertEquals($this->arr_jo, $this->json_l->encode($this->arr), "array case - loose: {$this->arr_d}");
|
||||
$this->assertEquals($this->arr_jo, $this->json_s->encode($this->arr), "array case - strict: {$this->arr_d}");
|
||||
|
||||
// ...unless the input array has some numeric indeces, in which case the behavior is to degrade to a regular array
|
||||
$this->assertEquals($this->arn_ja, $this->json_s->encode($this->arn), "array case - strict: {$this->arn_d}");
|
||||
|
||||
// Test a sparsely populated numerically indexed associative array
|
||||
$this->assertEquals($this->arrs_jo, $this->json_l->encode($this->arrs), "sparse numeric assoc array: {$this->arrs_d}");
|
||||
}
|
||||
|
||||
function test_to_then_from_JSON()
|
||||
{
|
||||
// these tests motivated by a bug in which strings that end
|
||||
// with backslashes followed by quotes were incorrectly decoded.
|
||||
|
||||
foreach(array('\\"', '\\\\"', '\\"\\"', '\\""\\""', '\\\\"\\\\"') as $v) {
|
||||
$this->assertEquals(array($v), $this->json_l->decode($this->json_l->encode(array($v))));
|
||||
$this->assertEquals(array('a' => $v), $this->json_l->decode($this->json_l->encode(array('a' => $v))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Services_JSON_NestedArray_TestCase extends PHPUnit_TestCase {
|
||||
|
||||
function Services_JSON_NestedArray_TestCase($name) {
|
||||
$this->PHPUnit_TestCase($name);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
|
||||
|
||||
$this->str1 = '[{"this":"that"}]';
|
||||
$this->arr1 = array(array('this' => 'that'));
|
||||
|
||||
$this->str2 = '{"this":["that"]}';
|
||||
$this->arr2 = array('this' => array('that'));
|
||||
|
||||
$this->str3 = '{"params":[{"foo":["1"],"bar":"1"}]}';
|
||||
$this->arr3 = array('params' => array(array('foo' => array('1'), 'bar' => '1')));
|
||||
|
||||
$this->str4 = '{"0": {"foo": "bar", "baz": "winkle"}}';
|
||||
$this->arr4 = array('0' => array('foo' => 'bar', 'baz' => 'winkle'));
|
||||
|
||||
$this->str5 = '{"params":[{"options": {"old": [ ], "new": {"0": {"elements": {"old": [], "new": {"0": {"elementName": "aa", "isDefault": false, "elementRank": "0", "priceAdjust": "0", "partNumber": ""}}}, "optionName": "aa", "isRequired": false, "optionDesc": null}}}}]}';
|
||||
$this->arr5 = array (
|
||||
'params' => array (
|
||||
0 => array (
|
||||
'options' =>
|
||||
array (
|
||||
'old' => array(),
|
||||
'new' => array (
|
||||
0 => array (
|
||||
'elements' => array (
|
||||
'old' => array(),
|
||||
'new' => array (
|
||||
0 => array (
|
||||
'elementName' => 'aa',
|
||||
'isDefault' => false,
|
||||
'elementRank' => '0',
|
||||
'priceAdjust' => '0',
|
||||
'partNumber' => '',
|
||||
),
|
||||
),
|
||||
),
|
||||
'optionName' => 'aa',
|
||||
'isRequired' => false,
|
||||
'optionDesc' => NULL,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function test_type()
|
||||
{
|
||||
$this->assertEquals('array', gettype($this->json->decode($this->str1)), "loose type should be array");
|
||||
$this->assertEquals('array', gettype($this->json->decode($this->str2)), "loose type should be array");
|
||||
$this->assertEquals('array', gettype($this->json->decode($this->str3)), "loose type should be array");
|
||||
}
|
||||
|
||||
function test_from_JSON()
|
||||
{
|
||||
$this->assertEquals($this->arr1, $this->json->decode($this->str1), "simple compactly-nested array");
|
||||
$this->assertEquals($this->arr2, $this->json->decode($this->str2), "simple compactly-nested array");
|
||||
$this->assertEquals($this->arr3, $this->json->decode($this->str3), "complex compactly nested array");
|
||||
$this->assertEquals($this->arr4, $this->json->decode($this->str4), "complex compactly nested array");
|
||||
$this->assertEquals($this->arr5, $this->json->decode($this->str5), "super complex compactly nested array");
|
||||
}
|
||||
|
||||
function _test_from_JSON()
|
||||
{
|
||||
$super = '{"params":[{"options": {"old": {}, "new": {"0": {"elements": {"old": {}, "new": {"0": {"elementName": "aa", "isDefault": false, "elementRank": "0", "priceAdjust": "0", "partNumber": ""}}}, "optionName": "aa", "isRequired": false, "optionDesc": ""}}}}]}';
|
||||
print("trying {$super}...\n");
|
||||
print var_export($this->json->decode($super));
|
||||
}
|
||||
}
|
||||
|
||||
class Services_JSON_Object_TestCase extends PHPUnit_TestCase {
|
||||
|
||||
function Services_JSON_Object_TestCase($name) {
|
||||
$this->PHPUnit_TestCase($name);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->json_l = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
|
||||
$this->json_s = new Services_JSON();
|
||||
|
||||
$this->obj_j = '{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"obj":{"a_number":123}}';
|
||||
|
||||
$this->obj1->car1->color = 'tan';
|
||||
$this->obj1->car1->model = 'sedan';
|
||||
$this->obj1->car2->color = 'red';
|
||||
$this->obj1->car2->model = 'sports';
|
||||
$this->obj1_j = '{"car1":{"color":"tan","model":"sedan"},"car2":{"color":"red","model":"sports"}}';
|
||||
$this->obj1_d = 'Object with nested objects';
|
||||
}
|
||||
|
||||
function test_type()
|
||||
{
|
||||
$this->assertEquals('object', gettype($this->json_s->decode($this->obj_j)), "checking whether decoded type is object");
|
||||
$this->assertEquals('array', gettype($this->json_l->decode($this->obj_j)), "checking whether decoded type is array");
|
||||
}
|
||||
|
||||
function test_to_JSON()
|
||||
{
|
||||
$this->assertEquals($this->obj1_j, $this->json_s->encode($this->obj1), "object - strict: {$this->obj1_d}");
|
||||
$this->assertEquals($this->obj1_j, $this->json_l->encode($this->obj1), "object - loose: {$this->obj1_d}");
|
||||
}
|
||||
|
||||
function test_from_then_to_JSON()
|
||||
{
|
||||
$this->assertEquals($this->obj_j, $this->json_s->encode($this->json_s->decode($this->obj_j)), "object case");
|
||||
$this->assertEquals($this->obj_j, $this->json_l->encode($this->json_l->decode($this->obj_j)), "array case");
|
||||
}
|
||||
}
|
||||
|
||||
class Services_JSON_Spaces_Comments_TestCase extends PHPUnit_TestCase {
|
||||
|
||||
function Services_JSON_Spaces_Comments_TestCase($name) {
|
||||
$this->PHPUnit_TestCase($name);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
|
||||
|
||||
$this->obj_j = '{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"obj":{"a_number":123}}';
|
||||
|
||||
$this->obj_js = '{"a_string": "\"he\":llo}:{world",
|
||||
"an_array":[1, 2, 3],
|
||||
"obj": {"a_number":123}}';
|
||||
|
||||
$this->obj_jc1 = '{"a_string": "\"he\":llo}:{world",
|
||||
// here is a comment, hoorah
|
||||
"an_array":[1, 2, 3],
|
||||
"obj": {"a_number":123}}';
|
||||
|
||||
$this->obj_jc2 = '/* this here is the sneetch */ "the sneetch"
|
||||
// this has been the sneetch.';
|
||||
|
||||
$this->obj_jc3 = '{"a_string": "\"he\":llo}:{world",
|
||||
/* here is a comment, hoorah */
|
||||
"an_array":[1, 2, 3 /* and here is another */],
|
||||
"obj": {"a_number":123}}';
|
||||
|
||||
$this->obj_jc4 = '{\'a_string\': "\"he\":llo}:{world",
|
||||
/* here is a comment, hoorah */
|
||||
\'an_array\':[1, 2, 3 /* and here is another */],
|
||||
"obj": {"a_number":123}}';
|
||||
}
|
||||
|
||||
function test_spaces()
|
||||
{
|
||||
$this->assertEquals($this->json->decode($this->obj_j), $this->json->decode($this->obj_js), "checking whether notation with spaces works");
|
||||
}
|
||||
|
||||
function test_comments()
|
||||
{
|
||||
$this->assertEquals($this->json->decode($this->obj_j), $this->json->decode($this->obj_jc1), "checking whether notation with single line comments works");
|
||||
$this->assertEquals('the sneetch', $this->json->decode($this->obj_jc2), "checking whether notation with multiline comments works");
|
||||
$this->assertEquals($this->json->decode($this->obj_j), $this->json->decode($this->obj_jc3), "checking whether notation with multiline comments works");
|
||||
$this->assertEquals($this->json->decode($this->obj_j), $this->json->decode($this->obj_jc4), "checking whether notation with single-quotes and multiline comments works");
|
||||
}
|
||||
}
|
||||
|
||||
class Services_JSON_Empties_TestCase extends PHPUnit_TestCase {
|
||||
|
||||
function Services_JSON_Empties_TestCase($name) {
|
||||
$this->PHPUnit_TestCase($name);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->json_l = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
|
||||
$this->json_s = new Services_JSON();
|
||||
|
||||
$this->obj0_j = '{}';
|
||||
$this->arr0_j = '[]';
|
||||
|
||||
$this->obj1_j = '{ }';
|
||||
$this->arr1_j = '[ ]';
|
||||
|
||||
$this->obj2_j = '{ /* comment inside */ }';
|
||||
$this->arr2_j = '[ /* comment inside */ ]';
|
||||
}
|
||||
|
||||
function test_type()
|
||||
{
|
||||
$this->assertEquals('array', gettype($this->json_l->decode($this->arr0_j)), "should be array");
|
||||
$this->assertEquals('object', gettype($this->json_s->decode($this->obj0_j)), "should be object");
|
||||
|
||||
$this->assertEquals(0, count($this->json_l->decode($this->arr0_j)), "should be empty array");
|
||||
$this->assertEquals(0, count(get_object_vars($this->json_s->decode($this->obj0_j))), "should be empty object");
|
||||
|
||||
$this->assertEquals('array', gettype($this->json_l->decode($this->arr1_j)), "should be array, even with space");
|
||||
$this->assertEquals('object', gettype($this->json_s->decode($this->obj1_j)), "should be object, even with space");
|
||||
|
||||
$this->assertEquals(0, count($this->json_l->decode($this->arr1_j)), "should be empty array, even with space");
|
||||
$this->assertEquals(0, count(get_object_vars($this->json_s->decode($this->obj1_j))), "should be empty object, even with space");
|
||||
|
||||
$this->assertEquals('array', gettype($this->json_l->decode($this->arr2_j)), "should be array, despite comment");
|
||||
$this->assertEquals('object', gettype($this->json_s->decode($this->obj2_j)), "should be object, despite comment");
|
||||
|
||||
$this->assertEquals(0, count($this->json_l->decode($this->arr2_j)), "should be empty array, despite comment");
|
||||
$this->assertEquals(0, count(get_object_vars($this->json_s->decode($this->obj2_j))), "should be empty object, despite commentt");
|
||||
}
|
||||
}
|
||||
|
||||
class Services_JSON_UnquotedKeys_TestCase extends PHPUnit_TestCase {
|
||||
|
||||
function Services_JSON_UnquotedKeys_TestCase($name) {
|
||||
$this->PHPUnit_TestCase($name);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
|
||||
|
||||
$this->arn = array(0=> array(0=> 'tan', 'model' => 'sedan'), 1 => array(0 => 'red', 'model' => 'sports'));
|
||||
$this->arn_ja = '[{0:"tan","model":"sedan"},{"0":"red",model:"sports"}]';
|
||||
$this->arn_d = 'associative array with unquoted keys, nested associative arrays, and some numeric keys thrown in';
|
||||
|
||||
$this->arrs = array (1 => 'one', 2 => 'two', 5 => 'fi"ve');
|
||||
$this->arrs_jo = '{"1":"one",2:"two","5":\'fi"ve\'}';
|
||||
$this->arrs_d = 'associative array with unquoted keys, single-quoted values, numeric keys which are not fully populated in a range of 0 to length-1';
|
||||
}
|
||||
|
||||
function test_from_JSON()
|
||||
{
|
||||
// ...unless the input array has some numeric indeces, in which case the behavior is to degrade to a regular array
|
||||
$this->assertEquals($this->arn, $this->json->decode($this->arn_ja), "array case - strict: {$this->arn_d}");
|
||||
|
||||
// Test a sparsely populated numerically indexed associative array
|
||||
$this->assertEquals($this->arrs, $this->json->decode($this->arrs_jo), "sparse numeric assoc array: {$this->arrs_d}");
|
||||
}
|
||||
}
|
||||
|
||||
class Services_JSON_ErrorSuppression_TestCase extends PHPUnit_TestCase {
|
||||
|
||||
function Services_JSON_ErrorSuppression_TestCase($name) {
|
||||
$this->PHPUnit_TestCase($name);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
$this->json = new Services_JSON();
|
||||
$this->json_ = new Services_JSON(SERVICES_JSON_SUPPRESS_ERRORS);
|
||||
|
||||
$this->res = tmpfile();
|
||||
$this->res_j_ = 'null';
|
||||
$this->res_d = 'naked resource';
|
||||
|
||||
$this->arr = array('a', 1, tmpfile());
|
||||
$this->arr_j_ = '["a",1,null]';
|
||||
$this->arr_d = 'array with string, number and resource';
|
||||
|
||||
$obj = new stdClass();
|
||||
$obj->a_string = '"he":llo}:{world';
|
||||
$obj->an_array = array(1, 2, 3);
|
||||
$obj->resource = tmpfile();
|
||||
|
||||
$this->obj = $obj;
|
||||
$this->obj_j_ = '{"a_string":"\"he\":llo}:{world","an_array":[1,2,3],"resource":null}';
|
||||
$this->obj_d = 'object with properties, array, and nested resource';
|
||||
}
|
||||
|
||||
function test_to_JSON()
|
||||
{
|
||||
$this->assertTrue(Services_JSON::isError($this->json->encode($this->res)), "resource case: {$this->res_d}");
|
||||
$this->assertTrue(Services_JSON::isError($this->json->encode($this->arr)), "array case: {$this->arr_d}");
|
||||
$this->assertTrue(Services_JSON::isError($this->json->encode($this->obj)), "object case: {$this->obj_d}");
|
||||
}
|
||||
|
||||
function test_to_JSON_suppressed()
|
||||
{
|
||||
$this->assertEquals($this->res_j_, $this->json_->encode($this->res), "resource case: {$this->res_d}");
|
||||
$this->assertEquals($this->arr_j_, $this->json_->encode($this->arr), "array case: {$this->arr_d}");
|
||||
$this->assertEquals($this->obj_j_, $this->json_->encode($this->obj), "object case: {$this->obj_d}");
|
||||
}
|
||||
}
|
||||
|
||||
$suite = new PHPUnit_TestSuite('Services_JSON_EncDec_TestCase');
|
||||
$result = PHPUnit::run($suite);
|
||||
echo $result->toString();
|
||||
|
||||
$suite = new PHPUnit_TestSuite('Services_JSON_AssocArray_TestCase');
|
||||
$result = PHPUnit::run($suite);
|
||||
echo $result->toString();
|
||||
|
||||
$suite = new PHPUnit_TestSuite('Services_JSON_NestedArray_TestCase');
|
||||
$result = PHPUnit::run($suite);
|
||||
echo $result->toString();
|
||||
|
||||
$suite = new PHPUnit_TestSuite('Services_JSON_Object_TestCase');
|
||||
$result = PHPUnit::run($suite);
|
||||
echo $result->toString();
|
||||
|
||||
$suite = new PHPUnit_TestSuite('Services_JSON_Spaces_Comments_TestCase');
|
||||
$result = PHPUnit::run($suite);
|
||||
echo $result->toString();
|
||||
|
||||
$suite = new PHPUnit_TestSuite('Services_JSON_Empties_TestCase');
|
||||
$result = PHPUnit::run($suite);
|
||||
echo $result->toString();
|
||||
|
||||
$suite = new PHPUnit_TestSuite('Services_JSON_UnquotedKeys_TestCase');
|
||||
$result = PHPUnit::run($suite);
|
||||
echo $result->toString();
|
||||
|
||||
$suite = new PHPUnit_TestSuite('Services_JSON_ErrorSuppression_TestCase');
|
||||
$result = PHPUnit::run($suite);
|
||||
echo $result->toString();
|
||||
|
||||
?>
|
26
thirdparty/simplepie/LICENSE.txt
vendored
Normal file
26
thirdparty/simplepie/LICENSE.txt
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
Copyright (c) 2004-2007, Ryan Parman and Geoffrey Sneddon.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are
|
||||
permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of
|
||||
conditions and the following disclaimer.
|
||||
|
||||
* 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.
|
||||
|
||||
* Neither the name of the SimplePie Team nor the names of its contributors may 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 HOLDERS
|
||||
AND 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.
|
30
thirdparty/simplepie/README.txt
vendored
Normal file
30
thirdparty/simplepie/README.txt
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
SIMPLEPIE
|
||||
http://simplepie.org
|
||||
By Ryan Parman and Geoffrey Sneddon
|
||||
|
||||
BSD-LICENSED
|
||||
http://www.opensource.org/licenses/bsd-license.php
|
||||
|
||||
WHAT COMES IN THE PACKAGE?
|
||||
1) simplepie.inc - The SimplePie library. This is all that's required for your pages.
|
||||
2) README.txt - This document.
|
||||
3) LICENSE.txt - A copy of the BSD license.
|
||||
4) compatibility_test - The SimplePie compatibility test that checks your server for required settings.
|
||||
5) demo - A basic feed reader demo that shows off some of SimplePie's more noticable features.
|
||||
6) idn - A third-party library that SimplePie can optionally use to understand Internationalized Domain Names (IDNs).
|
||||
7) test - SimplePie's unit test suite. This is only available in SVN builds.
|
||||
|
||||
TO START THE DEMO:
|
||||
1) Upload this package to your webserver.
|
||||
2) Make sure that the cache folder inside of the demo folder is server-writable.
|
||||
3) Navigate your browser to the demo folder.
|
||||
|
||||
SUPPORT:
|
||||
For further setup and install documentation, function references, etc., visit:
|
||||
http://simplepie.org/wiki/
|
||||
|
||||
For bug reports, feature requests and other support, visit:
|
||||
http://simplepie.org/support/
|
||||
|
||||
For more insight on SimplePie development, visit:
|
||||
http://simplepie.org/development/
|
5413
thirdparty/simplepie/SimplePie.php
vendored
Executable file
5413
thirdparty/simplepie/SimplePie.php
vendored
Executable file
@ -0,0 +1,5413 @@
|
||||
<?php
|
||||
/**
|
||||
* A PHP-Based RSS and Atom Feed Framework
|
||||
* Takes the hard work out of managing a complete RSS/Atom solution.
|
||||
* Version: "Lemon Meringue"
|
||||
* Updated: 3 November 2006
|
||||
* Copyright: 2004-2006 Ryan Parman, Geoffrey Sneddon
|
||||
* http://simplepie.org
|
||||
* LICENSE: GNU Lesser General Public License 2.1 (LGPL)
|
||||
* Please submit all bug reports and feature requests to the SimplePie forums. http://simplepie.org/support/
|
||||
* @package sapphire
|
||||
* @subpackage integration
|
||||
*/
|
||||
class SimplePie
|
||||
{
|
||||
// SimplePie Info
|
||||
var $name = 'SimplePie';
|
||||
var $version = '1.0 b3.1';
|
||||
var $build = '20061103';
|
||||
var $url = 'http://simplepie.org/';
|
||||
var $useragent;
|
||||
var $linkback;
|
||||
|
||||
// Other objects, instances created here so we can set options on them
|
||||
var $sanitize;
|
||||
|
||||
// Options
|
||||
var $rss_url;
|
||||
var $file;
|
||||
var $timeout = 10;
|
||||
var $xml_dump = false;
|
||||
var $enable_cache = true;
|
||||
var $max_minutes = 60;
|
||||
var $cache_location = './cache';
|
||||
var $order_by_date = true;
|
||||
var $input_encoding = false;
|
||||
var $cache_class = 'SimplePie_Cache';
|
||||
var $locator_class = 'SimplePie_Locator';
|
||||
var $parser_class = 'SimplePie_Parser';
|
||||
var $file_class = 'SimplePie_File';
|
||||
var $force_fsockopen = false;
|
||||
var $cache_name_type = 'sha1';
|
||||
|
||||
// Misc. variables
|
||||
var $data;
|
||||
var $error;
|
||||
|
||||
function SimplePie($feed_url = null, $cache_location = null, $cache_max_minutes = null)
|
||||
{
|
||||
// Couple of variables built up from other variables
|
||||
$this->useragent = $this->name . '/' . $this->version . ' (Feed Parser; ' . $this->url . '; Allow like Gecko) Build/' . $this->build;
|
||||
$this->linkback = '<a href="' . $this->url . '" title="' . $this->name . ' ' . $this->version . '">' . $this->name . '</a>';
|
||||
|
||||
// Other objects, instances created here so we can set options on them
|
||||
$this->sanitize = new SimplePie_Sanitize;
|
||||
|
||||
// Set options if they're passed to the constructor
|
||||
if (!is_null($feed_url))
|
||||
{
|
||||
$this->feed_url($feed_url);
|
||||
}
|
||||
|
||||
if (!is_null($cache_location))
|
||||
{
|
||||
$this->cache_location($cache_location);
|
||||
}
|
||||
|
||||
if (!is_null($cache_max_minutes))
|
||||
{
|
||||
$this->cache_max_minutes($cache_max_minutes);
|
||||
}
|
||||
|
||||
// If we've passed an xmldump variable in the URL, snap into XMLdump mode
|
||||
if (isset($_GET['xmldump']))
|
||||
{
|
||||
$this->enable_xmldump(true);
|
||||
}
|
||||
|
||||
// Only init the script if we're passed a feed URL
|
||||
if (!is_null($feed_url))
|
||||
{
|
||||
return $this->init();
|
||||
}
|
||||
}
|
||||
|
||||
function feed_url($url)
|
||||
{
|
||||
$this->rss_url = SimplePie_Misc::fix_protocol($url, 1);
|
||||
}
|
||||
|
||||
function set_file(&$file)
|
||||
{
|
||||
if (is_a($file, 'SimplePie_File'))
|
||||
{
|
||||
$this->rss_url = $file->url;
|
||||
$this->file =& $file;
|
||||
}
|
||||
}
|
||||
|
||||
function set_timeout($timeout = 10)
|
||||
{
|
||||
$this->timeout = (int) $timeout;
|
||||
}
|
||||
|
||||
function set_raw_data($data)
|
||||
{
|
||||
$this->raw_data = trim((string) $data);
|
||||
}
|
||||
|
||||
function enable_xmldump($enable = false)
|
||||
{
|
||||
$this->xml_dump = (bool) $enable;
|
||||
}
|
||||
|
||||
function enable_caching($enable = true)
|
||||
{
|
||||
$this->enable_cache = (bool) $enable;
|
||||
}
|
||||
|
||||
function cache_max_minutes($minutes = 60)
|
||||
{
|
||||
$this->max_minutes = (float) $minutes;
|
||||
}
|
||||
|
||||
function cache_location($location = './cache')
|
||||
{
|
||||
$this->cache_location = (string) $location;
|
||||
}
|
||||
|
||||
function order_by_date($enable = true)
|
||||
{
|
||||
$this->order_by_date = (bool) $enable;
|
||||
}
|
||||
|
||||
function input_encoding($encoding = false)
|
||||
{
|
||||
if ($encoding)
|
||||
{
|
||||
$this->input_encoding = (string) $encoding;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->input_encoding = false;
|
||||
}
|
||||
}
|
||||
|
||||
function set_cache_class($class = 'SimplePie_Cache')
|
||||
{
|
||||
if (SimplePie_Misc::is_a_class($class, 'SimplePie_Cache'))
|
||||
{
|
||||
$this->cache_class = $class;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function set_locator_class($class = 'SimplePie_Locator')
|
||||
{
|
||||
if (SimplePie_Misc::is_a_class($class, 'SimplePie_Locator'))
|
||||
{
|
||||
$this->locator_class = $class;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function set_parser_class($class = 'SimplePie_Parser')
|
||||
{
|
||||
if (SimplePie_Misc::is_a_class($class, 'SimplePie_Parser'))
|
||||
{
|
||||
$this->parser_class = $class;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function set_file_class($class = 'SimplePie_File')
|
||||
{
|
||||
if (SimplePie_Misc::is_a_class($class, 'SimplePie_File'))
|
||||
{
|
||||
$this->file_class = $class;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function set_sanitize_class($object = 'SimplePie_Sanitize')
|
||||
{
|
||||
if (class_exists($object))
|
||||
{
|
||||
$this->sanitize = new $object;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function set_useragent($ua)
|
||||
{
|
||||
$this->useragent = (string) $ua;
|
||||
}
|
||||
|
||||
function force_fsockopen($enable = false)
|
||||
{
|
||||
$this->force_fsockopen = (bool) $enable;
|
||||
}
|
||||
|
||||
function set_cache_name_type($type = 'sha1')
|
||||
{
|
||||
$type = strtolower(trim($type));
|
||||
switch ($type)
|
||||
{
|
||||
case 'crc32':
|
||||
$this->cache_name_type = 'crc32';
|
||||
break;
|
||||
|
||||
case 'md5':
|
||||
$this->cache_name_type = 'md5';
|
||||
break;
|
||||
|
||||
case 'rawurlencode':
|
||||
$this->cache_name_type = 'rawurlencode';
|
||||
break;
|
||||
|
||||
case 'urlencode':
|
||||
$this->cache_name_type = 'urlencode';
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->cache_name_type = 'sha1';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function bypass_image_hotlink($get = false)
|
||||
{
|
||||
$this->sanitize->bypass_image_hotlink($get);
|
||||
}
|
||||
|
||||
function bypass_image_hotlink_page($page = false)
|
||||
{
|
||||
$this->sanitize->bypass_image_hotlink_page($page);
|
||||
}
|
||||
|
||||
function replace_headers($enable = false)
|
||||
{
|
||||
$this->sanitize->replace_headers($enable);
|
||||
}
|
||||
|
||||
function remove_div($enable = true)
|
||||
{
|
||||
$this->sanitize->remove_div($enable);
|
||||
}
|
||||
|
||||
function strip_ads($enable = false)
|
||||
{
|
||||
$this->sanitize->strip_ads($enable);
|
||||
}
|
||||
|
||||
function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'), $encode = null)
|
||||
{
|
||||
$this->sanitize->strip_htmltags($tags);
|
||||
if (!is_null($encode))
|
||||
{
|
||||
$this->sanitize->encode_instead_of_strip($tags);
|
||||
}
|
||||
}
|
||||
|
||||
function encode_instead_of_strip($enable = true)
|
||||
{
|
||||
$this->sanitize->encode_instead_of_strip($enable);
|
||||
}
|
||||
|
||||
function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur'))
|
||||
{
|
||||
$this->sanitize->strip_attributes($attribs);
|
||||
}
|
||||
|
||||
function output_encoding($encoding = 'UTF-8')
|
||||
{
|
||||
$this->sanitize->output_encoding($encoding);
|
||||
}
|
||||
|
||||
function set_item_class($class = 'SimplePie_Item')
|
||||
{
|
||||
return $this->sanitize->set_item_class($class);
|
||||
}
|
||||
|
||||
function set_author_class($class = 'SimplePie_Author')
|
||||
{
|
||||
return $this->sanitize->set_author_class($class);
|
||||
}
|
||||
|
||||
function set_enclosure_class($class = 'SimplePie_Enclosure')
|
||||
{
|
||||
return $this->sanitize->set_enclosure_class($class);
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
if (!(function_exists('version_compare') && ((version_compare(phpversion(), '4.3.2', '>=') && version_compare(phpversion(), '5', '<')) || version_compare(phpversion(), '5.0.3', '>='))) || !extension_loaded('xml') || !extension_loaded('pcre'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ($this->sanitize->bypass_image_hotlink && !empty($_GET[$this->sanitize->bypass_image_hotlink]))
|
||||
{
|
||||
if (get_magic_quotes_gpc())
|
||||
{
|
||||
$_GET[$this->sanitize->bypass_image_hotlink] = stripslashes($_GET[$this->sanitize->bypass_image_hotlink]);
|
||||
}
|
||||
SimplePie_Misc::display_file($_GET[$this->sanitize->bypass_image_hotlink], 10, $this->useragent);
|
||||
}
|
||||
|
||||
if (isset($_GET['js']))
|
||||
{
|
||||
$embed = <<<EOT
|
||||
function embed_odeo(link) {
|
||||
document.writeln('<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url='+link+'"></embed>');
|
||||
}
|
||||
|
||||
function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
|
||||
if (placeholder != '') {
|
||||
document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
|
||||
}
|
||||
else {
|
||||
document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" src="'+link+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="true" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
|
||||
}
|
||||
}
|
||||
|
||||
function embed_flash(bgcolor, width, height, link, loop, type) {
|
||||
document.writeln('<embed src="'+link+'" pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash" type="'+type+'" quality="high" width="'+width+'" height="'+height+'" bgcolor="'+bgcolor+'" loop="'+loop+'"></embed>');
|
||||
}
|
||||
|
||||
function embed_wmedia(width, height, link) {
|
||||
document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
|
||||
}
|
||||
EOT;
|
||||
|
||||
if (function_exists('ob_gzhandler'))
|
||||
{
|
||||
ob_start('ob_gzhandler');
|
||||
}
|
||||
header('Content-type: text/javascript; charset: UTF-8');
|
||||
header('Cache-Control: must-revalidate');
|
||||
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 86400) . ' GMT');
|
||||
echo $embed;
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!empty($this->rss_url) || !empty($this->raw_data))
|
||||
{
|
||||
$this->data = array();
|
||||
$cache = false;
|
||||
|
||||
if (!empty($this->rss_url))
|
||||
{
|
||||
// Decide whether to enable caching
|
||||
if ($this->enable_cache && preg_match('/^http(s)?:\/\//i', $this->rss_url))
|
||||
{
|
||||
$cache = new $this->cache_class($this->cache_location, call_user_func($this->cache_name_type, $this->rss_url), 'spc');
|
||||
}
|
||||
// If it's enabled and we don't want an XML dump, use the cache
|
||||
if ($cache && !$this->xml_dump)
|
||||
{
|
||||
// Load the Cache
|
||||
$this->data = $cache->load();
|
||||
if (!empty($this->data))
|
||||
{
|
||||
// If we've hit a collision just rerun it with caching disabled
|
||||
if (isset($this->data['url']) && $this->data['url'] != $this->rss_url)
|
||||
{
|
||||
$cache = false;
|
||||
}
|
||||
// If we've got a feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL
|
||||
else if (!empty($this->data['feed_url']))
|
||||
{
|
||||
if ($this->data['feed_url'] == $this->data['url'])
|
||||
{
|
||||
$cache->unlink();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->feed_url($this->data['feed_url']);
|
||||
return $this->init();
|
||||
}
|
||||
}
|
||||
// If the cache is new enough
|
||||
else if ($cache->mtime() + $this->max_minutes * 60 < time())
|
||||
{
|
||||
// If we have last-modified and/or etag set
|
||||
if (!empty($this->data['last-modified']) || !empty($this->data['etag']))
|
||||
{
|
||||
$headers = array();
|
||||
if (!empty($this->data['last-modified']))
|
||||
{
|
||||
$headers['if-modified-since'] = $this->data['last-modified'];
|
||||
}
|
||||
if (!empty($this->data['etag']))
|
||||
{
|
||||
$headers['if-none-match'] = $this->data['etag'];
|
||||
}
|
||||
$file = new $this->file_class($this->rss_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen);
|
||||
if ($file->success)
|
||||
{
|
||||
$headers = $file->headers();
|
||||
if ($headers['status']['code'] == 304)
|
||||
{
|
||||
$cache->touch();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($file);
|
||||
}
|
||||
}
|
||||
// If we don't have last-modified or etag set, just clear the cache
|
||||
else
|
||||
{
|
||||
$cache->unlink();
|
||||
}
|
||||
}
|
||||
// If the cache is still valid, just return true
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// If the cache is empty, delete it
|
||||
else
|
||||
{
|
||||
$cache->unlink();
|
||||
}
|
||||
}
|
||||
$this->data = array();
|
||||
// If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it.
|
||||
if (!isset($file))
|
||||
{
|
||||
if (is_a($this->file, 'SimplePie_File') && $this->file->url == $this->rss_url)
|
||||
{
|
||||
$file =& $this->file;
|
||||
}
|
||||
else
|
||||
{
|
||||
$file = new $this->file_class($this->rss_url, $this->timeout, 5, null, $this->useragent, $this->force_fsockopen);
|
||||
}
|
||||
}
|
||||
// If the file connection has an error, set SimplePie::error to that and quit
|
||||
if (!$file->success)
|
||||
{
|
||||
$this->error = $file->error;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the supplied URL is a feed, if it isn't, look for it.
|
||||
$locate = new $this->locator_class($file, $this->timeout, $this->useragent);
|
||||
if (!$locate->is_feed($file))
|
||||
{
|
||||
$feed = $locate->find();
|
||||
if ($feed)
|
||||
{
|
||||
if ($cache && !$cache->save(array('url' => $this->rss_url, 'feed_url' => $feed)))
|
||||
{
|
||||
$this->error = "$cache->name is not writeable";
|
||||
SimplePie_Misc::error($this->error, E_USER_WARNING, __FILE__, __LINE__);
|
||||
}
|
||||
$this->rss_url = $feed;
|
||||
return $this->init();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->error = "A feed could not be found at $this->rss_url";
|
||||
SimplePie_Misc::error($this->error, E_USER_WARNING, __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$headers = $file->headers();
|
||||
$data = trim($file->body());
|
||||
$file->close();
|
||||
unset($file);
|
||||
}
|
||||
else
|
||||
{
|
||||
$data = $this->raw_data;
|
||||
}
|
||||
|
||||
// First check to see if input has been overridden.
|
||||
if (!empty($this->input_encoding))
|
||||
{
|
||||
$encoding = $this->input_encoding;
|
||||
}
|
||||
// Second try HTTP headers
|
||||
else if (!empty($headers['content-type']) && preg_match('/charset\s*=\s*([^;]*)/i', $headers['content-type'], $charset))
|
||||
{
|
||||
$encoding = $charset[1];
|
||||
}
|
||||
// Then prolog, if at the very start of the document
|
||||
else if (preg_match('/^<\?xml(.*)?>/msiU', $data, $prolog) && preg_match('/encoding\s*=\s*("([^"]*)"|\'([^\']*)\')/Ui', $prolog[1], $encoding))
|
||||
{
|
||||
$encoding = substr($encoding[1], 1, -1);
|
||||
}
|
||||
// UTF-32 Big Endian BOM
|
||||
else if (strpos($data, sprintf('%c%c%c%c', 0x00, 0x00, 0xFE, 0xFF)) === 0)
|
||||
{
|
||||
$encoding = 'UTF-32be';
|
||||
}
|
||||
// UTF-32 Little Endian BOM
|
||||
else if (strpos($data, sprintf('%c%c%c%c', 0xFF, 0xFE, 0x00, 0x00)) === 0)
|
||||
{
|
||||
$encoding = 'UTF-32';
|
||||
}
|
||||
// UTF-16 Big Endian BOM
|
||||
else if (strpos($data, sprintf('%c%c', 0xFE, 0xFF)) === 0)
|
||||
{
|
||||
$encoding = 'UTF-16be';
|
||||
}
|
||||
// UTF-16 Little Endian BOM
|
||||
else if (strpos($data, sprintf('%c%c', 0xFF, 0xFE)) === 0)
|
||||
{
|
||||
$encoding = 'UTF-16le';
|
||||
}
|
||||
// UTF-8 BOM
|
||||
else if (strpos($data, sprintf('%c%c%c', 0xEF, 0xBB, 0xBF)) === 0)
|
||||
{
|
||||
$encoding = 'UTF-8';
|
||||
}
|
||||
// Fallback to the default
|
||||
else
|
||||
{
|
||||
$encoding = null;
|
||||
}
|
||||
|
||||
// Change the encoding to UTF-8 (as we always use UTF-8 internally)
|
||||
$data = SimplePie_Misc::change_encoding($data, $encoding, 'UTF-8');
|
||||
|
||||
// Start parsing
|
||||
$data = new $this->parser_class($data, 'UTF-8', $this->xml_dump);
|
||||
// If we want the XML, just output that and quit
|
||||
if ($this->xml_dump)
|
||||
{
|
||||
header('Content-type: text/xml; charset=UTF-8');
|
||||
echo $data->data;
|
||||
exit;
|
||||
}
|
||||
// If it's parsed fine
|
||||
else if (!$data->error_code)
|
||||
{
|
||||
// Parse the data, and make it sane
|
||||
$this->sanitize->parse_data_array($data->data, $this->rss_url);
|
||||
unset($data);
|
||||
// Get the sane data
|
||||
$this->data['feedinfo'] = $this->sanitize->feedinfo;
|
||||
unset($this->sanitize->feedinfo);
|
||||
$this->data['info'] = $this->sanitize->info;
|
||||
unset($this->sanitize->info);
|
||||
$this->data['items'] = $this->sanitize->items;
|
||||
unset($this->sanitize->items);
|
||||
$this->data['feedinfo']['encoding'] = $this->sanitize->output_encoding;
|
||||
$this->data['url'] = $this->rss_url;
|
||||
|
||||
// Store the headers that we need
|
||||
if (!empty($headers['last-modified']))
|
||||
{
|
||||
$this->data['last-modified'] = $headers['last-modified'];
|
||||
}
|
||||
if (!empty($headers['etag']))
|
||||
{
|
||||
$this->data['etag'] = $headers['etag'];
|
||||
}
|
||||
|
||||
// If we want to order it by date, check if all items have a date, and then sort it
|
||||
if ($this->order_by_date && !empty($this->data['items']))
|
||||
{
|
||||
$do_sort = true;
|
||||
foreach ($this->data['items'] as $item)
|
||||
{
|
||||
if (!$item->get_date('U'))
|
||||
{
|
||||
$do_sort = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($do_sort)
|
||||
{
|
||||
usort($this->data['items'], create_function('$a, $b', 'if ($a->get_date(\'U\') == $b->get_date(\'U\')) return 1; return ($a->get_date(\'U\') < $b->get_date(\'U\')) ? 1 : -1;'));
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the file if caching is enabled
|
||||
if ($cache && !$cache->save($this->data))
|
||||
{
|
||||
$this->error = "$cache->name is not writeable";
|
||||
SimplePie_Misc::error($this->error, E_USER_WARNING, __FILE__, __LINE__);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// If we have an error, just set SimplePie::error to it and quit
|
||||
else
|
||||
{
|
||||
$this->error = "XML error: $data->error_string at line $data->current_line, column $data->current_column";
|
||||
SimplePie_Misc::error($this->error, E_USER_WARNING, __FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function get_encoding()
|
||||
{
|
||||
if (!empty($this->data['feedinfo']['encoding']))
|
||||
{
|
||||
return $this->data['feedinfo']['encoding'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function handle_content_type($mime = 'text/html')
|
||||
{
|
||||
if (!headers_sent())
|
||||
{
|
||||
$header = "Content-type: $mime;";
|
||||
if ($this->get_encoding())
|
||||
{
|
||||
$header .= ' charset=' . $this->get_encoding();
|
||||
}
|
||||
else
|
||||
{
|
||||
$header .= ' charset=UTF-8';
|
||||
}
|
||||
header($header);
|
||||
}
|
||||
}
|
||||
|
||||
function get_type()
|
||||
{
|
||||
if (!empty($this->data['feedinfo']['type']))
|
||||
{
|
||||
return $this->data['feedinfo']['type'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_version()
|
||||
{
|
||||
if (!empty($this->data['feedinfo']['version']))
|
||||
{
|
||||
return $this->data['feedinfo']['version'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_favicon($check = false, $alternate = null)
|
||||
{
|
||||
if (!empty($this->data['info']['link']['alternate'][0]))
|
||||
{
|
||||
$favicon = SimplePie_Misc::absolutize_url('/favicon.ico', $this->get_feed_link());
|
||||
|
||||
if ($check)
|
||||
{
|
||||
$file = new $this->file_class($favicon, $this->timeout/10, 5, null, $this->useragent, $this->force_fsockopen);
|
||||
$headers = $file->headers();
|
||||
$file->close();
|
||||
|
||||
if ($headers['status']['code'] == 200)
|
||||
{
|
||||
return $favicon;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return $favicon;
|
||||
}
|
||||
}
|
||||
if (!is_null($alternate))
|
||||
{
|
||||
return $alternate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_url()
|
||||
{
|
||||
if (!empty($this->rss_url))
|
||||
{
|
||||
return $this->rss_url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_feed()
|
||||
{
|
||||
if (!empty($this->rss_url))
|
||||
{
|
||||
return SimplePie_Misc::fix_protocol($this->rss_url, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_outlook()
|
||||
{
|
||||
if (!empty($this->rss_url))
|
||||
{
|
||||
return 'outlook' . SimplePie_Misc::fix_protocol($this->rss_url, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_podcast()
|
||||
{
|
||||
if (!empty($this->rss_url))
|
||||
{
|
||||
return SimplePie_Misc::fix_protocol($this->rss_url, 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_aol()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://feeds.my.aol.com/add.jsp?url=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_bloglines()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://www.bloglines.com/sub/' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_eskobo()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://www.eskobo.com/?AddToMyPage=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_feedfeeds()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://www.feedfeeds.com/add?feed=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_feedlounge()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://my.feedlounge.com/external/subscribe?url=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_feedster()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://www.feedster.com/myfeedster.php?action=addrss&confirm=no&rssurl=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_google()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://fusion.google.com/add?feedurl=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_gritwire()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://my.gritwire.com/feeds/addExternalFeed.aspx?FeedUrl=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_msn()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
$url = 'http://my.msn.com/addtomymsn.armx?id=rss&ut=' . rawurlencode($this->subscribe_url());
|
||||
if ($this->get_feed_link())
|
||||
{
|
||||
$url .= '&ru=' . rawurlencode($this->get_feed_link());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_netvibes()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://www.netvibes.com/subscribe.php?url=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_newsburst()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://www.newsburst.com/Source/?add=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_newsgator()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://www.newsgator.com/ngs/subscriber/subext.aspx?url=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_odeo()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://www.odeo.com/listen/subscribe?feed=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_pluck()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://client.pluck.com/pluckit/prompt.aspx?GCID=C12286x053&a=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_podnova()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://www.podnova.com/index_your_podcasts.srf?action=add&url=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_rojo()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://www.rojo.com/add-subscription?resource=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe_yahoo()
|
||||
{
|
||||
if ($this->subscribe_url())
|
||||
{
|
||||
return 'http://add.my.yahoo.com/rss?url=' . rawurlencode($this->subscribe_url());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_feed_title()
|
||||
{
|
||||
if (!empty($this->data['info']['title']))
|
||||
{
|
||||
return $this->data['info']['title'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_feed_link()
|
||||
{
|
||||
if (!empty($this->data['info']['link']['alternate'][0]))
|
||||
{
|
||||
return $this->data['info']['link']['alternate'][0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_feed_links()
|
||||
{
|
||||
if (!empty($this->data['info']['link']))
|
||||
{
|
||||
return $this->data['info']['link'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_feed_description()
|
||||
{
|
||||
if (!empty($this->data['info']['description']))
|
||||
{
|
||||
return $this->data['info']['description'];
|
||||
}
|
||||
else if (!empty($this->data['info']['dc:description']))
|
||||
{
|
||||
return $this->data['info']['dc:description'];
|
||||
}
|
||||
else if (!empty($this->data['info']['tagline']))
|
||||
{
|
||||
return $this->data['info']['tagline'];
|
||||
}
|
||||
else if (!empty($this->data['info']['subtitle']))
|
||||
{
|
||||
return $this->data['info']['subtitle'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_feed_copyright()
|
||||
{
|
||||
if (!empty($this->data['info']['copyright']))
|
||||
{
|
||||
return $this->data['info']['copyright'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_feed_language()
|
||||
{
|
||||
if (!empty($this->data['info']['language']))
|
||||
{
|
||||
return $this->data['info']['language'];
|
||||
}
|
||||
else if (!empty($this->data['info']['xml:lang']))
|
||||
{
|
||||
return $this->data['info']['xml:lang'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_image_exist()
|
||||
{
|
||||
if (!empty($this->data['info']['image']['url']) || !empty($this->data['info']['image']['logo']))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_image_title()
|
||||
{
|
||||
if (!empty($this->data['info']['image']['title']))
|
||||
{
|
||||
return $this->data['info']['image']['title'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_image_url()
|
||||
{
|
||||
if (!empty($this->data['info']['image']['url']))
|
||||
{
|
||||
return $this->data['info']['image']['url'];
|
||||
}
|
||||
else if (!empty($this->data['info']['image']['logo']))
|
||||
{
|
||||
return $this->data['info']['image']['logo'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_image_link()
|
||||
{
|
||||
if (!empty($this->data['info']['image']['link']))
|
||||
{
|
||||
return $this->data['info']['image']['link'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_image_width()
|
||||
{
|
||||
if (!empty($this->data['info']['image']['width']))
|
||||
{
|
||||
return $this->data['info']['image']['width'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_image_height()
|
||||
{
|
||||
if (!empty($this->data['info']['image']['height']))
|
||||
{
|
||||
return $this->data['info']['image']['height'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_item_quantity($max = 0)
|
||||
{
|
||||
if (!empty($this->data['items']))
|
||||
{
|
||||
$qty = sizeof($this->data['items']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$qty = 0;
|
||||
}
|
||||
if ($max == 0)
|
||||
{
|
||||
return $qty;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ($qty > $max) ? $max : $qty;
|
||||
}
|
||||
}
|
||||
|
||||
function get_item($key = 0)
|
||||
{
|
||||
if (!empty($this->data['items'][$key]))
|
||||
{
|
||||
return $this->data['items'][$key];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_items($start = 0, $end = 0)
|
||||
{
|
||||
if ($this->get_item_quantity() > 0)
|
||||
{
|
||||
if ($end == 0)
|
||||
{
|
||||
return array_slice($this->data['items'], $start);
|
||||
}
|
||||
else
|
||||
{
|
||||
return array_slice($this->data['items'], $start, $end);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage integration
|
||||
*/
|
||||
class SimplePie_Item
|
||||
{
|
||||
var $data;
|
||||
|
||||
function SimplePie_Item($data)
|
||||
{
|
||||
$this->data =& $data;
|
||||
}
|
||||
|
||||
function get_id()
|
||||
{
|
||||
if (!empty($this->data['guid']['data']))
|
||||
{
|
||||
return $this->data['guid']['data'];
|
||||
}
|
||||
else if (!empty($this->data['id']))
|
||||
{
|
||||
return $this->data['id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_title()
|
||||
{
|
||||
if (!empty($this->data['title']))
|
||||
{
|
||||
return $this->data['title'];
|
||||
}
|
||||
else if (!empty($this->data['dc:title']))
|
||||
{
|
||||
return $this->data['dc:title'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_description()
|
||||
{
|
||||
if (!empty($this->data['content']))
|
||||
{
|
||||
return $this->data['content'];
|
||||
}
|
||||
else if (!empty($this->data['encoded']))
|
||||
{
|
||||
return $this->data['encoded'];
|
||||
}
|
||||
else if (!empty($this->data['summary']))
|
||||
{
|
||||
return $this->data['summary'];
|
||||
}
|
||||
else if (!empty($this->data['description']))
|
||||
{
|
||||
return $this->data['description'];
|
||||
}
|
||||
else if (!empty($this->data['dc:description']))
|
||||
{
|
||||
return $this->data['dc:description'];
|
||||
}
|
||||
else if (!empty($this->data['longdesc']))
|
||||
{
|
||||
return $this->data['longdesc'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_category($key = 0)
|
||||
{
|
||||
$categories = $this->get_categories();
|
||||
if (!empty($categories[$key]))
|
||||
{
|
||||
return $categories[$key];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_categories()
|
||||
{
|
||||
$categories = array();
|
||||
if (!empty($this->data['category']))
|
||||
{
|
||||
$categories = array_merge($categories, $this->data['category']);
|
||||
}
|
||||
if (!empty($this->data['subject']))
|
||||
{
|
||||
$categories = array_merge($categories, $this->data['subject']);
|
||||
}
|
||||
if (!empty($this->data['term']))
|
||||
{
|
||||
$categories = array_merge($categories, $this->data['term']);
|
||||
}
|
||||
if (!empty($categories))
|
||||
{
|
||||
return array_unique($categories);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_author($key = 0)
|
||||
{
|
||||
$authors = $this->get_authors();
|
||||
if (!empty($authors[$key]))
|
||||
{
|
||||
return $authors[$key];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_authors()
|
||||
{
|
||||
$authors = array();
|
||||
if (!empty($this->data['author']))
|
||||
{
|
||||
$authors = array_merge($authors, $this->data['author']);
|
||||
}
|
||||
if (!empty($this->data['creator']))
|
||||
{
|
||||
$authors = array_merge($authors, $this->data['creator']);
|
||||
}
|
||||
if (!empty($authors))
|
||||
{
|
||||
return array_unique($authors);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_date($date_format = 'j F Y, g:i a')
|
||||
{
|
||||
if (!empty($this->data['pubdate']))
|
||||
{
|
||||
return date($date_format, $this->data['pubdate']);
|
||||
}
|
||||
else if (!empty($this->data['dc:date']))
|
||||
{
|
||||
return date($date_format, $this->data['dc:date']);
|
||||
}
|
||||
else if (!empty($this->data['issued']))
|
||||
{
|
||||
return date($date_format, $this->data['issued']);
|
||||
}
|
||||
else if (!empty($this->data['published']))
|
||||
{
|
||||
return date($date_format, $this->data['published']);
|
||||
}
|
||||
else if (!empty($this->data['modified']))
|
||||
{
|
||||
return date($date_format, $this->data['modified']);
|
||||
}
|
||||
else if (!empty($this->data['updated']))
|
||||
{
|
||||
return date($date_format, $this->data['updated']);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_permalink()
|
||||
{
|
||||
$link = $this->get_link(0);
|
||||
$enclosure = $this->get_enclosure(0);
|
||||
if (!empty($link))
|
||||
{
|
||||
return $link;
|
||||
}
|
||||
else if (!empty($enclosure))
|
||||
{
|
||||
return $enclosure->get_link();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_link($key = 0, $rel = 'alternate')
|
||||
{
|
||||
$links = $this->get_links($rel);
|
||||
if (!empty($links[$key]))
|
||||
{
|
||||
return $links[$key];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_links($rel = 'alternate')
|
||||
{
|
||||
if ($rel == 'alternate')
|
||||
{
|
||||
$links = array();
|
||||
if (!empty($this->data['link'][$rel]))
|
||||
{
|
||||
$links = $this->data['link'][$rel];
|
||||
}
|
||||
if (!empty($this->data['guid']['data']) && $this->data['guid']['permalink'] == true)
|
||||
{
|
||||
$links[] = $this->data['guid']['data'];
|
||||
}
|
||||
return $links;
|
||||
}
|
||||
else if (!empty($this->data['link'][$rel]))
|
||||
{
|
||||
return $this->data['link'][$rel];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_enclosure($key = 0)
|
||||
{
|
||||
$enclosures = $this->get_enclosures();
|
||||
if (!empty($enclosures[$key]))
|
||||
{
|
||||
return $enclosures[$key];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_enclosures()
|
||||
{
|
||||
$enclosures = array();
|
||||
$links = $this->get_links('enclosure');
|
||||
if (!empty($this->data['enclosures']))
|
||||
{
|
||||
$enclosures = array_merge($enclosures, $this->data['enclosures']);
|
||||
}
|
||||
if (!empty($links))
|
||||
{
|
||||
$enclosures = array_merge($enclosures, $links);
|
||||
}
|
||||
if (!empty($enclosures))
|
||||
{
|
||||
return array_unique($enclosures);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_blinklist()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
$url = 'http://www.blinklist.com/index.php?Action=Blink/addblink.php&Description=&Url=' . rawurlencode($this->get_permalink());
|
||||
if ($this->get_title())
|
||||
{
|
||||
$url .= '&Title=' . rawurlencode($this->get_title());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_blogmarks()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
$url = 'http://blogmarks.net/my/new.php?mini=1&simple=1&url=' . rawurlencode($this->get_permalink());
|
||||
if ($this->get_title())
|
||||
{
|
||||
$url .= '&title=' . rawurlencode($this->get_title());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_delicious()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
$url = 'http://del.icio.us/post/?v=3&url=' . rawurlencode($this->get_permalink());
|
||||
if ($this->get_title())
|
||||
{
|
||||
$url .= '&title=' . rawurlencode($this->get_title());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_digg()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
return 'http://digg.com/submit?phase=2&URL=' . rawurlencode($this->get_permalink());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_furl()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
$url = 'http://www.furl.net/storeIt.jsp?u=' . rawurlencode($this->get_permalink());
|
||||
if ($this->get_title())
|
||||
{
|
||||
$url .= '&t=' . rawurlencode($this->get_title());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_magnolia()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
$url = 'http://ma.gnolia.com/bookmarklet/add?url=' . rawurlencode($this->get_permalink());
|
||||
if ($this->get_title())
|
||||
{
|
||||
$url .= '&title=' . rawurlencode($this->get_title());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_myweb20()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
$url = 'http://myweb2.search.yahoo.com/myresults/bookmarklet?u=' . rawurlencode($this->get_permalink());
|
||||
if ($this->get_title())
|
||||
{
|
||||
$url .= '&t=' . rawurlencode($this->get_title());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_newsvine()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
$url = 'http://www.newsvine.com/_wine/save?u=' . rawurlencode($this->get_permalink());
|
||||
if ($this->get_title())
|
||||
{
|
||||
$url .= '&h=' . rawurlencode($this->get_title());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_reddit()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
$url = 'http://reddit.com/submit?url=' . rawurlencode($this->get_permalink());
|
||||
if ($this->get_title())
|
||||
{
|
||||
$url .= '&title=' . rawurlencode($this->get_title());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_segnalo()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
$url = 'http://segnalo.com/post.html.php?url=' . rawurlencode($this->get_permalink());
|
||||
if ($this->get_title())
|
||||
{
|
||||
$url .= '&title=' . rawurlencode($this->get_title());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_simpy()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
$url = 'http://www.simpy.com/simpy/LinkAdd.do?href=' . rawurlencode($this->get_permalink());
|
||||
if ($this->get_title())
|
||||
{
|
||||
$url .= '&title=' . rawurlencode($this->get_title());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_smarking()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
return 'http://smarking.com/editbookmark/?url=' . rawurlencode($this->get_permalink());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_spurl()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
$url = 'http://www.spurl.net/spurl.php?v=3&url=' . rawurlencode($this->get_permalink());
|
||||
if ($this->get_title())
|
||||
{
|
||||
$url .= '&title=' . rawurlencode($this->get_title());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function add_to_wists()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
$url = 'http://wists.com/r.php?c=&r=' . rawurlencode($this->get_permalink());
|
||||
if ($this->get_title())
|
||||
{
|
||||
$url .= '&title=' . rawurlencode($this->get_title());
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function search_technorati()
|
||||
{
|
||||
if ($this->get_permalink())
|
||||
{
|
||||
return 'http://www.technorati.com/search/' . rawurlencode($this->get_permalink());
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage integration
|
||||
*/
|
||||
class SimplePie_Author
|
||||
{
|
||||
var $name;
|
||||
var $link;
|
||||
var $email;
|
||||
|
||||
// Constructor, used to input the data
|
||||
function SimplePie_Author($name, $link, $email)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->link = $link;
|
||||
$this->email = $email;
|
||||
}
|
||||
|
||||
function get_name()
|
||||
{
|
||||
if (!empty($this->name))
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_link()
|
||||
{
|
||||
if (!empty($this->link))
|
||||
{
|
||||
return $this->link;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_email()
|
||||
{
|
||||
if (!empty($this->email))
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage integration
|
||||
*/
|
||||
class SimplePie_Enclosure
|
||||
{
|
||||
var $link;
|
||||
var $type;
|
||||
var $length;
|
||||
|
||||
// Constructor, used to input the data
|
||||
function SimplePie_Enclosure($link, $type, $length)
|
||||
{
|
||||
$this->link = $link;
|
||||
$this->type = $type;
|
||||
$this->length = $length;
|
||||
}
|
||||
|
||||
function get_link()
|
||||
{
|
||||
if (!empty($this->link))
|
||||
{
|
||||
if (class_exists('idna_convert'))
|
||||
{
|
||||
$idn = new idna_convert;
|
||||
$this->link = $idn->encode($this->link);
|
||||
}
|
||||
return $this->link;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_extension()
|
||||
{
|
||||
if (!empty($this->link))
|
||||
{
|
||||
return pathinfo($this->link, PATHINFO_EXTENSION);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_type()
|
||||
{
|
||||
if (!empty($this->type))
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_length()
|
||||
{
|
||||
if (!empty($this->length))
|
||||
{
|
||||
return $this->length;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function get_size()
|
||||
{
|
||||
$length = $this->get_length();
|
||||
if (!empty($length))
|
||||
{
|
||||
return round($length/1048576, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function native_embed($options='')
|
||||
{
|
||||
return $this->embed($options, true);
|
||||
}
|
||||
|
||||
function embed($options = '', $native = false)
|
||||
{
|
||||
// Set up defaults
|
||||
$audio = '';
|
||||
$video = '';
|
||||
$alt = '';
|
||||
$altclass = '';
|
||||
$loop = 'false';
|
||||
$width = 'auto';
|
||||
$height = 'auto';
|
||||
$bgcolor = '#ffffff';
|
||||
|
||||
// Process options and reassign values as necessary
|
||||
if (is_array($options))
|
||||
{
|
||||
extract($options);
|
||||
}
|
||||
else
|
||||
{
|
||||
$options = explode(',', $options);
|
||||
foreach($options as $option)
|
||||
{
|
||||
$opt = explode(':', $option, 2);
|
||||
if (isset($opt[0], $opt[1]))
|
||||
{
|
||||
$opt[0] = trim($opt[0]);
|
||||
$opt[1] = trim($opt[1]);
|
||||
switch ($opt[0])
|
||||
{
|
||||
case 'audio':
|
||||
$audio = $opt[1];
|
||||
break;
|
||||
|
||||
case 'video':
|
||||
$video = $opt[1];
|
||||
break;
|
||||
|
||||
case 'alt':
|
||||
$alt = $opt[1];
|
||||
break;
|
||||
|
||||
case 'altclass':
|
||||
$altclass = $opt[1];
|
||||
break;
|
||||
|
||||
case 'loop':
|
||||
$loop = $opt[1];
|
||||
break;
|
||||
|
||||
case 'width':
|
||||
$width = $opt[1];
|
||||
break;
|
||||
|
||||
case 'height':
|
||||
$height = $opt[1];
|
||||
break;
|
||||
|
||||
case 'bgcolor':
|
||||
$bgcolor = $opt[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$type = strtolower($this->get_type());
|
||||
|
||||
// If we encounter an unsupported mime-type, check the file extension and guess intelligently.
|
||||
if (!in_array($type, array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mpeg', 'audio/x-mpeg', 'audio/mp3', 'x-audio/mp3', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video', 'application/x-shockwave-flash', 'application/futuresplash', 'application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx')))
|
||||
{
|
||||
switch (strtolower($this->get_extension()))
|
||||
{
|
||||
// Audio mime-types
|
||||
case 'aac':
|
||||
case 'adts':
|
||||
$type = 'audio/acc';
|
||||
break;
|
||||
|
||||
case 'aif':
|
||||
case 'aifc':
|
||||
case 'aiff':
|
||||
case 'cdda':
|
||||
$type = 'audio/aiff';
|
||||
break;
|
||||
|
||||
case 'bwf':
|
||||
$type = 'audio/wav';
|
||||
break;
|
||||
|
||||
case 'kar':
|
||||
case 'mid':
|
||||
case 'midi':
|
||||
case 'smf':
|
||||
$type = 'audio/midi';
|
||||
break;
|
||||
|
||||
case 'm4a':
|
||||
$type = 'audio/x-m4a';
|
||||
break;
|
||||
|
||||
case 'mp3':
|
||||
case 'swa':
|
||||
$type = 'audio/mp3';
|
||||
break;
|
||||
|
||||
case 'wav':
|
||||
$type = 'audio/wav';
|
||||
break;
|
||||
|
||||
case 'wax':
|
||||
$type = 'audio/x-ms-wax';
|
||||
break;
|
||||
|
||||
case 'wma':
|
||||
$type = 'audio/x-ms-wma';
|
||||
break;
|
||||
|
||||
// Video mime-types
|
||||
case '3gp':
|
||||
case '3gpp':
|
||||
$type = 'video/3gpp';
|
||||
break;
|
||||
|
||||
case '3g2':
|
||||
case '3gp2':
|
||||
$type = 'video/3gpp2';
|
||||
break;
|
||||
|
||||
case 'asf':
|
||||
$type = 'video/x-ms-asf';
|
||||
break;
|
||||
|
||||
case 'm1a':
|
||||
case 'm1s':
|
||||
case 'm1v':
|
||||
case 'm15':
|
||||
case 'm75':
|
||||
case 'mp2':
|
||||
case 'mpa':
|
||||
case 'mpeg':
|
||||
case 'mpg':
|
||||
case 'mpm':
|
||||
case 'mpv':
|
||||
$type = 'video/mpeg';
|
||||
break;
|
||||
|
||||
case 'm4v':
|
||||
$type = 'video/x-m4v';
|
||||
break;
|
||||
|
||||
case 'mov':
|
||||
case 'qt':
|
||||
$type = 'video/quicktime';
|
||||
break;
|
||||
|
||||
case 'mp4':
|
||||
case 'mpg4':
|
||||
$type = 'video/mp4';
|
||||
break;
|
||||
|
||||
case 'sdv':
|
||||
$type = 'video/sd-video';
|
||||
break;
|
||||
|
||||
case 'wm':
|
||||
$type = 'video/x-ms-wm';
|
||||
break;
|
||||
|
||||
case 'wmv':
|
||||
$type = 'video/x-ms-wmv';
|
||||
break;
|
||||
|
||||
case 'wvx':
|
||||
$type = 'video/x-ms-wvx';
|
||||
break;
|
||||
|
||||
// Flash mime-types
|
||||
case 'spl':
|
||||
$type = 'application/futuresplash';
|
||||
break;
|
||||
|
||||
case 'swf':
|
||||
$type = 'application/x-shockwave-flash';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$mime = explode('/', $type, 2);
|
||||
$mime = $mime[0];
|
||||
|
||||
// Process values for 'auto'
|
||||
if ($width == 'auto')
|
||||
{
|
||||
if ($mime == 'video')
|
||||
{
|
||||
$width = '320';
|
||||
}
|
||||
else
|
||||
{
|
||||
$width = '100%';
|
||||
}
|
||||
}
|
||||
if ($height == 'auto')
|
||||
{
|
||||
if ($mime == 'audio')
|
||||
{
|
||||
$height = 0;
|
||||
}
|
||||
else if ($mime == 'video')
|
||||
{
|
||||
$height = 240;
|
||||
}
|
||||
else
|
||||
{
|
||||
$height = 256;
|
||||
}
|
||||
}
|
||||
|
||||
// Set proper placeholder value
|
||||
if ($mime == 'audio')
|
||||
{
|
||||
$placeholder = $audio;
|
||||
}
|
||||
else if ($mime == 'video')
|
||||
{
|
||||
$placeholder = $video;
|
||||
}
|
||||
|
||||
$embed = '';
|
||||
|
||||
// Make sure the JS library is included
|
||||
// (I know it'll be included multiple times, but I can't think of a better way to do this automatically)
|
||||
if (!$native)
|
||||
{
|
||||
$embed .= '<script type="text/javascript" src="?js"></script>';
|
||||
}
|
||||
|
||||
// Odeo Feed MP3's
|
||||
if (substr(strtolower($this->get_link()), 0, 15) == 'http://odeo.com') {
|
||||
if ($native)
|
||||
{
|
||||
$embed .= '<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url=' . $this->get_link() . '"></embed>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$embed .= '<script type="text/javascript">embed_odeo("' . $this->get_link() . '");</script>';
|
||||
}
|
||||
}
|
||||
|
||||
// QuickTime 7 file types. Need to test with QuickTime 6.
|
||||
else if (in_array($type, array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mpeg', 'audio/x-mpeg', 'audio/mp3', 'x-audio/mp3', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video')))
|
||||
{
|
||||
$height += 16;
|
||||
if ($native)
|
||||
{
|
||||
if ($placeholder != "") {
|
||||
$embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" href=\"" . $this->get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://www.apple.com/quicktime/download/\"></embed>";
|
||||
}
|
||||
else {
|
||||
$embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" src=\"" . $this->get_link() . "\" width=\"$width+\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://www.apple.com/quicktime/download/\"></embed>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
|
||||
}
|
||||
}
|
||||
|
||||
// Flash
|
||||
else if (in_array($type, array('application/x-shockwave-flash', 'application/futuresplash')))
|
||||
{
|
||||
if ($native)
|
||||
{
|
||||
$embed .= "<embed src=\"" . $this->get_link() . "\" pluginspage=\"http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\"></embed>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
|
||||
}
|
||||
}
|
||||
|
||||
// Windows Media
|
||||
else if (in_array($type, array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx')))
|
||||
{
|
||||
$height += 45;
|
||||
if ($native)
|
||||
{
|
||||
$embed .= "<embed type=\"application/x-mplayer2\" src=\"" . $this->get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\"></embed>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
|
||||
}
|
||||
}
|
||||
|
||||
// Everything else
|
||||
else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
|
||||
|
||||
return $embed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage integration
|
||||
*/
|
||||
class SimplePie_File
|
||||
{
|
||||
var $url;
|
||||
var $useragent;
|
||||
var $success = true;
|
||||
var $headers = array();
|
||||
var $body;
|
||||
var $fp;
|
||||
var $redirects = 0;
|
||||
var $error;
|
||||
var $method;
|
||||
|
||||
function SimplePie_File($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
|
||||
{
|
||||
if (class_exists('idna_convert'))
|
||||
{
|
||||
$idn = new idna_convert;
|
||||
$url = $idn->encode($url);
|
||||
}
|
||||
$this->url = $url;
|
||||
$this->useragent = $useragent;
|
||||
if (preg_match('/^http(s)?:\/\//i', $url))
|
||||
{
|
||||
if (empty($useragent))
|
||||
{
|
||||
$useragent = ini_get('user_agent');
|
||||
$this->useragent = $useragent;
|
||||
}
|
||||
if (!is_array($headers))
|
||||
{
|
||||
$headers = array();
|
||||
}
|
||||
if (extension_loaded('curl') && version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>=') && !$force_fsockopen)
|
||||
{
|
||||
$this->method = 'curl';
|
||||
$fp = curl_init();
|
||||
$headers2 = array();
|
||||
foreach ($headers as $key => $value)
|
||||
{
|
||||
$headers2[] = "$key: $value";
|
||||
}
|
||||
curl_setopt($fp, CURLOPT_ENCODING, '');
|
||||
curl_setopt($fp, CURLOPT_URL, $url);
|
||||
curl_setopt($fp, CURLOPT_HEADER, 1);
|
||||
curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
|
||||
curl_setopt($fp, CURLOPT_REFERER, $url);
|
||||
curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
|
||||
curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
|
||||
if (!ini_get('open_basedir') && !ini_get('safe_mode'))
|
||||
{
|
||||
curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
|
||||
}
|
||||
|
||||
$this->headers = trim(curl_exec($fp));
|
||||
if (curl_errno($fp) == 23 || curl_errno($fp) == 61)
|
||||
{
|
||||
curl_setopt($fp, CURLOPT_ENCODING, 'none');
|
||||
$this->headers = trim(curl_exec($fp));
|
||||
}
|
||||
if (curl_errno($fp))
|
||||
{
|
||||
$this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
|
||||
$this->success = false;
|
||||
return false;
|
||||
}
|
||||
$info = curl_getinfo($fp);
|
||||
$this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 2);
|
||||
if (count($this->headers) == $info['redirect_count'] + 1)
|
||||
{
|
||||
$this->headers = array_pop($this->headers);
|
||||
$this->body = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->body = array_pop($this->headers);
|
||||
$this->headers = array_pop($this->headers);
|
||||
}
|
||||
$this->headers = $this->parse_headers($this->headers);
|
||||
if (($this->headers['status']['code'] == 301 || $this->headers['status']['code'] == 302 || $this->headers['status']['code'] == 303 || $this->headers['status']['code'] == 307) && !empty($this->headers['location']) && $this->redirects < $redirects)
|
||||
{
|
||||
$this->redirects++;
|
||||
return $this->SimplePie_File($this->headers['location'], $timeout, $redirects, $headers, $useragent, $force_fsockopen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->method = 'fsockopen';
|
||||
$url_parts = parse_url($url);
|
||||
if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) == 'https')
|
||||
{
|
||||
$url_parts['host'] = "ssl://$url_parts[host]";
|
||||
$url_parts['port'] = 443;
|
||||
}
|
||||
if (!isset($url_parts['port']))
|
||||
{
|
||||
$url_parts['port'] = 80;
|
||||
}
|
||||
$this->fp = fsockopen($url_parts['host'], $url_parts['port'], $errno, $errstr, $timeout);
|
||||
if (!$this->fp)
|
||||
{
|
||||
$this->error = 'fsockopen error: ' . $errstr;
|
||||
$this->success = false;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream_set_timeout($this->fp, $timeout);
|
||||
$get = (isset($url_parts['query'])) ? "$url_parts[path]?$url_parts[query]" : $url_parts['path'];
|
||||
$out = "GET $get HTTP/1.0\r\n";
|
||||
$out .= "Host: $url_parts[host]\r\n";
|
||||
$out .= "User-Agent: $useragent\r\n";
|
||||
if (function_exists('gzinflate'))
|
||||
{
|
||||
$out .= "Accept-Encoding: gzip,deflate\r\n";
|
||||
}
|
||||
|
||||
if (!empty($url_parts['user']) && !empty($url_parts['pass']))
|
||||
{
|
||||
$out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
|
||||
}
|
||||
foreach ($headers as $key => $value)
|
||||
{
|
||||
$out .= "$key: $value\r\n";
|
||||
}
|
||||
$out .= "Connection: Close\r\n\r\n";
|
||||
fwrite($this->fp, $out);
|
||||
|
||||
$info = stream_get_meta_data($this->fp);
|
||||
$data = '';
|
||||
while (strpos($data, "\r\n\r\n") === false && !$info['timed_out'])
|
||||
{
|
||||
$data .= fgets($this->fp, 128);
|
||||
$info = stream_get_meta_data($this->fp);
|
||||
}
|
||||
if (!$info['timed_out'])
|
||||
{
|
||||
$this->headers = $this->parse_headers($data);
|
||||
if (($this->headers['status']['code'] == 301 || $this->headers['status']['code'] == 302 || $this->headers['status']['code'] == 303 || $this->headers['status']['code'] == 307) && !empty($this->headers['location']) && $this->redirects < $redirects)
|
||||
{
|
||||
$this->redirects++;
|
||||
return $this->SimplePie_File($this->headers['location'], $timeout, $redirects, $headers, $useragent, $force_fsockopen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->close();
|
||||
$this->error = 'fsocket timed out';
|
||||
$this->success = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->headers['status']['code'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->method = 'fopen';
|
||||
if ($this->fp = fopen($url, 'r'))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->error = 'fopen could not open the file';
|
||||
$this->success = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function headers()
|
||||
{
|
||||
return $this->headers;
|
||||
}
|
||||
|
||||
function body()
|
||||
{
|
||||
if (is_null($this->body))
|
||||
{
|
||||
if ($this->fp)
|
||||
{
|
||||
$info = stream_get_meta_data($this->fp);
|
||||
$this->body = '';
|
||||
while (!$info['eof'] && !$info['timed_out'])
|
||||
{
|
||||
$this->body .= fread($this->fp, 1024);
|
||||
$info = stream_get_meta_data($this->fp);
|
||||
}
|
||||
if (!$info['timed_out'])
|
||||
{
|
||||
$this->body = trim($this->body);
|
||||
if ($this->method == 'fsockopen' && !empty($this->headers['content-encoding']) && ($this->headers['content-encoding'] == 'gzip' || $this->headers['content-encoding'] == 'deflate'))
|
||||
{
|
||||
if (substr($this->body, 0, 8) == "\x1f\x8b\x08\x00\x00\x00\x00\x00")
|
||||
{
|
||||
$this->body = substr($this->body, 10);
|
||||
}
|
||||
$this->body = gzinflate($this->body);
|
||||
}
|
||||
$this->close();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $this->body;
|
||||
}
|
||||
|
||||
function close()
|
||||
{
|
||||
if (!is_null($this->fp))
|
||||
{
|
||||
if (fclose($this->fp))
|
||||
{
|
||||
$this->fp = null;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function parse_headers($headers)
|
||||
{
|
||||
$headers = explode("\r\n", trim($headers));
|
||||
$status = array_shift($headers);
|
||||
foreach ($headers as $header)
|
||||
{
|
||||
$data = explode(':', $header, 2);
|
||||
$head[strtolower(trim($data[0]))] = trim($data[1]);
|
||||
}
|
||||
if (preg_match('/HTTP\/[0-9\.]+ ([0-9]+)(.*)$/i', $status, $matches))
|
||||
{
|
||||
if (isset($head['status']))
|
||||
{
|
||||
unset($head['status']);
|
||||
}
|
||||
$head['status']['code'] = $matches[1];
|
||||
$head['status']['name'] = trim($matches[2]);
|
||||
}
|
||||
return $head;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage integration
|
||||
*/
|
||||
class SimplePie_Cache
|
||||
{
|
||||
var $location;
|
||||
var $filename;
|
||||
var $extension;
|
||||
var $name;
|
||||
|
||||
function SimplePie_Cache($location, $filename, $extension)
|
||||
{
|
||||
$this->location = $location;
|
||||
$this->filename = rawurlencode($filename);
|
||||
$this->extension = rawurlencode($extension);
|
||||
$this->name = "$location/$this->filename.$this->extension";
|
||||
}
|
||||
|
||||
function save($data)
|
||||
{
|
||||
if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
|
||||
{
|
||||
$fp = fopen($this->name, 'w');
|
||||
if ($fp)
|
||||
{
|
||||
fwrite($fp, serialize($data));
|
||||
fclose($fp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function load()
|
||||
{
|
||||
if (file_exists($this->name) && is_readable($this->name))
|
||||
{
|
||||
return unserialize(file_get_contents($this->name));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function mtime()
|
||||
{
|
||||
if (file_exists($this->name))
|
||||
{
|
||||
return filemtime($this->name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function touch()
|
||||
{
|
||||
if (file_exists($this->name))
|
||||
{
|
||||
return touch($this->name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function unlink()
|
||||
{
|
||||
if (file_exists($this->name))
|
||||
{
|
||||
return unlink($this->name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage integration
|
||||
*/
|
||||
class SimplePie_Misc
|
||||
{
|
||||
function absolutize_url($relative, $base)
|
||||
{
|
||||
$relative = trim($relative);
|
||||
$base = trim($base);
|
||||
if (!empty($relative))
|
||||
{
|
||||
$relative = SimplePie_Misc::parse_url($relative, false);
|
||||
$relative = array('scheme' => $relative[2], 'authority' => $relative[3], 'path' => $relative[5], 'query' => $relative[7], 'fragment' => $relative[9]);
|
||||
if (!empty($relative['scheme']))
|
||||
{
|
||||
$target = $relative;
|
||||
}
|
||||
else if (!empty($base))
|
||||
{
|
||||
$base = SimplePie_Misc::parse_url($base, false);
|
||||
$base = array('scheme' => $base[2], 'authority' => $base[3], 'path' => $base[5], 'query' => $base[7], 'fragment' => $base[9]);
|
||||
$target['scheme'] = $base['scheme'];
|
||||
if (!empty($relative['authority']))
|
||||
{
|
||||
$target = array_merge($relative, $target);
|
||||
}
|
||||
else
|
||||
{
|
||||
$target['authority'] = $base['authority'];
|
||||
if (!empty($relative['path']))
|
||||
{
|
||||
if (strpos($relative['path'], '/') === 0)
|
||||
{
|
||||
$target['path'] = $relative['path'];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!empty($base['path']))
|
||||
{
|
||||
$target['path'] = dirname("$base[path].") . '/' . $relative['path'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$target['path'] = '/' . $relative['path'];
|
||||
}
|
||||
}
|
||||
if (!empty($relative['query']))
|
||||
{
|
||||
$target['query'] = $relative['query'];
|
||||
}
|
||||
$input = $target['path'];
|
||||
$target['path'] = '';
|
||||
while (!empty($input))
|
||||
{
|
||||
if (strpos($input, '../') === 0)
|
||||
{
|
||||
$input = substr($input, 3);
|
||||
}
|
||||
else if (strpos($input, './') === 0)
|
||||
{
|
||||
$input = substr($input, 2);
|
||||
}
|
||||
else if (strpos($input, '/./') === 0)
|
||||
{
|
||||
$input = substr_replace($input, '/', 0, 3);
|
||||
}
|
||||
else if (strpos($input, '/.') === 0 && SimplePie_Misc::strendpos($input, '/.') === 0)
|
||||
{
|
||||
$input = substr_replace($input, '/', -2);
|
||||
}
|
||||
else if (strpos($input, '/../') === 0)
|
||||
{
|
||||
$input = substr_replace($input, '/', 0, 4);
|
||||
$target['path'] = preg_replace('/(\/)?([^\/]+)$/msiU', '', $target['path']);
|
||||
}
|
||||
else if (strpos($input, '/..') === 0 && SimplePie_Misc::strendpos($input, '/..') === 0)
|
||||
{
|
||||
$input = substr_replace($input, '/', 0, 3);
|
||||
$target['path'] = preg_replace('/(\/)?([^\/]+)$/msiU', '', $target['path']);
|
||||
}
|
||||
else if ($input == '.' || $input == '..')
|
||||
{
|
||||
$input = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (preg_match('/^(.+)(\/|$)/msiU', $input, $match))
|
||||
{
|
||||
$target['path'] .= $match[1];
|
||||
$input = substr_replace($input, '', 0, strlen($match[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!empty($base['path']))
|
||||
{
|
||||
$target['path'] = $base['path'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$target['path'] = '/';
|
||||
}
|
||||
if (!empty($relative['query']))
|
||||
{
|
||||
$target['query'] = $relative['query'];
|
||||
}
|
||||
else if (!empty($base['query']))
|
||||
{
|
||||
$target['query'] = $base['query'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($relative['fragment']))
|
||||
{
|
||||
$target['fragment'] = $relative['fragment'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$return = '';
|
||||
if (!empty($target['scheme']))
|
||||
{
|
||||
$return .= "$target[scheme]:";
|
||||
}
|
||||
if (!empty($target['authority']))
|
||||
{
|
||||
$return .= $target['authority'];
|
||||
}
|
||||
if (!empty($target['path']))
|
||||
{
|
||||
$return .= $target['path'];
|
||||
}
|
||||
if (!empty($target['query']))
|
||||
{
|
||||
$return .= "?$target[query]";
|
||||
}
|
||||
if (!empty($target['fragment']))
|
||||
{
|
||||
$return .= "#$target[fragment]";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$return = $base;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
function strendpos($haystack, $needle)
|
||||
{
|
||||
return strlen($haystack) - strpos($haystack, $needle) - strlen($needle);
|
||||
}
|
||||
|
||||
function get_element($realname, $string)
|
||||
{
|
||||
$return = array();
|
||||
$name = preg_quote($realname, '/');
|
||||
preg_match_all("/<($name)((\s*((\w+:)?\w+)\s*=\s*(\"([^\"]*)\"|'([^']*)'|(.*)))*)\s*((\/)?>|>(.*)<\/$name>)/msiU", $string, $matches, PREG_SET_ORDER);
|
||||
for ($i = 0; $i < count($matches); $i++)
|
||||
{
|
||||
$return[$i]['tag'] = $realname;
|
||||
$return[$i]['full'] = $matches[$i][0];
|
||||
if (strlen($matches[$i][10]) <= 2)
|
||||
{
|
||||
$return[$i]['self_closing'] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$return[$i]['self_closing'] = false;
|
||||
$return[$i]['content'] = $matches[$i][12];
|
||||
}
|
||||
$return[$i]['attribs'] = array();
|
||||
if (!empty($matches[$i][2]))
|
||||
{
|
||||
preg_match_all('/((\w+:)?\w+)\s*=\s*("([^"]*)"|\'([^\']*)\'|(\S+))\s/msiU', ' ' . $matches[$i][2] . ' ', $attribs, PREG_SET_ORDER);
|
||||
for ($j = 0; $j < count($attribs); $j++)
|
||||
{
|
||||
$return[$i]['attribs'][strtoupper($attribs[$j][1])]['data'] = $attribs[$j][count($attribs[$j])-1];
|
||||
$first = substr($attribs[$j][2], 0, 1);
|
||||
$return[$i]['attribs'][strtoupper($attribs[$j][1])]['split'] = ($first == '"' || $first == "'") ? $first : '"';
|
||||
}
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
function element_implode($element)
|
||||
{
|
||||
$full = "<$element[tag]";
|
||||
foreach ($element['attribs'] as $key => $value)
|
||||
{
|
||||
$key = strtolower($key);
|
||||
$full .= " $key=$value[split]$value[data]$value[split]";
|
||||
}
|
||||
if ($element['self_closing'])
|
||||
{
|
||||
$full .= ' />';
|
||||
}
|
||||
else
|
||||
{
|
||||
$full .= ">$element[content]</$element[tag]>";
|
||||
}
|
||||
return $full;
|
||||
}
|
||||
|
||||
function error($message, $level, $file, $line)
|
||||
{
|
||||
switch ($level)
|
||||
{
|
||||
case E_USER_ERROR:
|
||||
$note = 'PHP Error';
|
||||
break;
|
||||
case E_USER_WARNING:
|
||||
$note = 'PHP Warning';
|
||||
break;
|
||||
case E_USER_NOTICE:
|
||||
$note = 'PHP Notice';
|
||||
break;
|
||||
default:
|
||||
$note = 'Unknown Error';
|
||||
break;
|
||||
}
|
||||
error_log("$note: $message in $file on line $line", 0);
|
||||
return $message;
|
||||
}
|
||||
|
||||
function display_file($url, $timeout = 10, $useragent = null)
|
||||
{
|
||||
$file = new SimplePie_File($url, $timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $useragent);
|
||||
$headers = $file->headers();
|
||||
if ($file->body() !== false)
|
||||
{
|
||||
header('Content-type: ' . $headers['content-type']);
|
||||
echo $file->body();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
function fix_protocol($url, $http = 1)
|
||||
{
|
||||
$parsed = SimplePie_Misc::parse_url($url);
|
||||
if (!empty($parsed['scheme']) && strtolower($parsed['scheme']) != 'http' && strtolower($parsed['scheme']) != 'https')
|
||||
{
|
||||
return SimplePie_Misc::fix_protocol("$parsed[authority]$parsed[path]$parsed[query]$parsed[fragment]", $http);
|
||||
}
|
||||
if (!file_exists($url) && empty($parsed['scheme']))
|
||||
{
|
||||
return SimplePie_Misc::fix_protocol("http://$url", $http);
|
||||
}
|
||||
|
||||
if ($http == 2 && !empty($parsed['scheme']))
|
||||
{
|
||||
return "feed:$url";
|
||||
}
|
||||
else if ($http == 3 && strtolower($parsed['scheme']) == 'http')
|
||||
{
|
||||
return substr_replace($url, 'podcast', 0, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
function parse_url($url, $parse_match = true)
|
||||
{
|
||||
preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/i', $url, $match);
|
||||
if (empty($match[0]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ($i = 6; $i < 10; $i++)
|
||||
{
|
||||
if (!isset($match[$i]))
|
||||
{
|
||||
$match[$i] = '';
|
||||
}
|
||||
}
|
||||
if ($parse_match)
|
||||
{
|
||||
$match = array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[6], 'fragment' => $match[8]);
|
||||
}
|
||||
return $match;
|
||||
}
|
||||
}
|
||||
|
||||
function change_encoding($data, $input, $output)
|
||||
{
|
||||
$input = SimplePie_Misc::encoding($input);
|
||||
$output = SimplePie_Misc::encoding($output);
|
||||
|
||||
if ($input != $output)
|
||||
{
|
||||
if (function_exists('iconv') && $input['use_iconv'] && $output['use_iconv'] && iconv($input['encoding'], "$output[encoding]//TRANSLIT", $data))
|
||||
{
|
||||
return iconv($input['encoding'], "$output[encoding]//TRANSLIT", $data);
|
||||
}
|
||||
else if (function_exists('iconv') && $input['use_iconv'] && $output['use_iconv'] && iconv($input['encoding'], $output['encoding'], $data))
|
||||
{
|
||||
return iconv($input['encoding'], $output['encoding'], $data);
|
||||
}
|
||||
else if (function_exists('mb_convert_encoding') && $input['use_mbstring'] && $output['use_mbstring'])
|
||||
{
|
||||
return mb_convert_encoding($data, $output['encoding'], $input['encoding']);
|
||||
}
|
||||
else if ($input['encoding'] == 'ISO-8859-1' && $output['encoding'] == 'UTF-8')
|
||||
{
|
||||
return utf8_encode($data);
|
||||
}
|
||||
else if ($input['encoding'] == 'UTF-8' && $output['encoding'] == 'ISO-8859-1')
|
||||
{
|
||||
return utf8_decode($data);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
function encoding($encoding)
|
||||
{
|
||||
$return['use_mbstring'] = false;
|
||||
$return['use_iconv'] = false;
|
||||
switch (strtolower($encoding))
|
||||
{
|
||||
|
||||
// 7bit
|
||||
case '7bit':
|
||||
case '7-bit':
|
||||
$return['encoding'] = '7bit';
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// 8bit
|
||||
case '8bit':
|
||||
case '8-bit':
|
||||
$return['encoding'] = '8bit';
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ARMSCII-8
|
||||
case 'armscii-8':
|
||||
case 'armscii':
|
||||
$return['encoding'] = 'ARMSCII-8';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// ASCII
|
||||
case 'us-ascii':
|
||||
case 'ascii':
|
||||
$return['encoding'] = 'US-ASCII';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// BASE64
|
||||
case 'base64':
|
||||
case 'base-64':
|
||||
$return['encoding'] = 'BASE64';
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// Big5 - Traditional Chinese, mainly used in Taiwan
|
||||
case 'big5':
|
||||
case '950':
|
||||
$return['encoding'] = 'BIG5';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// Big5 with Hong Kong extensions, Traditional Chinese
|
||||
case 'big5-hkscs':
|
||||
$return['encoding'] = 'BIG5-HKSCS';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// byte2be
|
||||
case 'byte2be':
|
||||
$return['encoding'] = 'byte2be';
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// byte2le
|
||||
case 'byte2le':
|
||||
$return['encoding'] = 'byte2le';
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// byte4be
|
||||
case 'byte4be':
|
||||
$return['encoding'] = 'byte4be';
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// byte4le
|
||||
case 'byte4le':
|
||||
$return['encoding'] = 'byte4le';
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// EUC-CN
|
||||
case 'euc-cn':
|
||||
case 'euccn':
|
||||
$return['encoding'] = 'EUC-CN';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// EUC-JISX0213
|
||||
case 'euc-jisx0213':
|
||||
case 'eucjisx0213':
|
||||
$return['encoding'] = 'EUC-JISX0213';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// EUC-JP
|
||||
case 'euc-jp':
|
||||
case 'eucjp':
|
||||
$return['encoding'] = 'EUC-JP';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// EUCJP-win
|
||||
case 'euc-jp-win':
|
||||
case 'eucjp-win':
|
||||
case 'eucjpwin':
|
||||
$return['encoding'] = 'EUCJP-win';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// EUC-KR
|
||||
case 'euc-kr':
|
||||
case 'euckr':
|
||||
$return['encoding'] = 'EUC-KR';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// EUC-TW
|
||||
case 'euc-tw':
|
||||
case 'euctw':
|
||||
$return['encoding'] = 'EUC-TW';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// GB18030 - Simplified Chinese, national standard character set
|
||||
case 'gb18030-2000':
|
||||
case 'gb18030':
|
||||
$return['encoding'] = 'GB18030';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// GB2312 - Simplified Chinese, national standard character set
|
||||
case 'gb2312':
|
||||
case '936':
|
||||
$return['encoding'] = 'GB2312';
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// GBK
|
||||
case 'gbk':
|
||||
$return['encoding'] = 'GBK';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Georgian-Academy
|
||||
case 'georgian-academy':
|
||||
$return['encoding'] = 'Georgian-Academy';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Georgian-PS
|
||||
case 'georgian-ps':
|
||||
$return['encoding'] = 'Georgian-PS';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// HTML-ENTITIES
|
||||
case 'html-entities':
|
||||
case 'htmlentities':
|
||||
$return['encoding'] = 'HTML-ENTITIES';
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// HZ
|
||||
case 'hz':
|
||||
$return['encoding'] = 'HZ';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-2022-CN
|
||||
case 'iso-2022-cn':
|
||||
case 'iso2022-cn':
|
||||
case 'iso2022cn':
|
||||
$return['encoding'] = 'ISO-2022-CN';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// ISO-2022-CN-EXT
|
||||
case 'iso-2022-cn-ext':
|
||||
case 'iso2022-cn-ext':
|
||||
case 'iso2022cn-ext':
|
||||
case 'iso2022cnext':
|
||||
$return['encoding'] = 'ISO-2022-CN';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// ISO-2022-JP
|
||||
case 'iso-2022-jp':
|
||||
case 'iso2022-jp':
|
||||
case 'iso2022jp':
|
||||
$return['encoding'] = 'ISO-2022-JP';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-2022-JP-1
|
||||
case 'iso-2022-jp-1':
|
||||
case 'iso2022-jp-1':
|
||||
case 'iso2022jp-1':
|
||||
case 'iso2022jp1':
|
||||
$return['encoding'] = 'ISO-2022-JP-1';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// ISO-2022-JP-2
|
||||
case 'iso-2022-jp-2':
|
||||
case 'iso2022-jp-2':
|
||||
case 'iso2022jp-2':
|
||||
case 'iso2022jp2':
|
||||
$return['encoding'] = 'ISO-2022-JP-2';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// ISO-2022-JP-3
|
||||
case 'iso-2022-jp-3':
|
||||
case 'iso2022-jp-3':
|
||||
case 'iso2022jp-3':
|
||||
case 'iso2022jp3':
|
||||
$return['encoding'] = 'ISO-2022-JP-3';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// ISO-2022-KR
|
||||
case 'iso-2022-kr':
|
||||
case 'iso2022-kr':
|
||||
case 'iso2022kr':
|
||||
$return['encoding'] = 'ISO-2022-KR';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-1
|
||||
case 'iso-8859-1':
|
||||
case 'iso8859-1':
|
||||
$return['encoding'] = 'ISO-8859-1';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-2
|
||||
case 'iso-8859-2':
|
||||
case 'iso8859-2':
|
||||
$return['encoding'] = 'ISO-8859-2';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-3
|
||||
case 'iso-8859-3':
|
||||
case 'iso8859-3':
|
||||
$return['encoding'] = 'ISO-8859-3';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-4
|
||||
case 'iso-8859-4':
|
||||
case 'iso8859-4':
|
||||
$return['encoding'] = 'ISO-8859-4';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-5
|
||||
case 'iso-8859-5':
|
||||
case 'iso8859-5':
|
||||
$return['encoding'] = 'ISO-8859-5';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-6
|
||||
case 'iso-8859-6':
|
||||
case 'iso8859-6':
|
||||
$return['encoding'] = 'ISO-8859-6';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-7
|
||||
case 'iso-8859-7':
|
||||
case 'iso8859-7':
|
||||
$return['encoding'] = 'ISO-8859-7';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-8
|
||||
case 'iso-8859-8':
|
||||
case 'iso8859-8':
|
||||
$return['encoding'] = 'ISO-8859-8';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-9
|
||||
case 'iso-8859-9':
|
||||
case 'iso8859-9':
|
||||
$return['encoding'] = 'ISO-8859-9';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-10
|
||||
case 'iso-8859-10':
|
||||
case 'iso8859-10':
|
||||
$return['encoding'] = 'ISO-8859-10';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// mbstring/iconv functions don't appear to support 11 & 12
|
||||
|
||||
// ISO-8859-13
|
||||
case 'iso-8859-13':
|
||||
case 'iso8859-13':
|
||||
$return['encoding'] = 'ISO-8859-13';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-14
|
||||
case 'iso-8859-14':
|
||||
case 'iso8859-14':
|
||||
$return['encoding'] = 'ISO-8859-14';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-15
|
||||
case 'iso-8859-15':
|
||||
case 'iso8859-15':
|
||||
$return['encoding'] = 'ISO-8859-15';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// ISO-8859-16
|
||||
case 'iso-8859-16':
|
||||
case 'iso8859-16':
|
||||
$return['encoding'] = 'ISO-8859-16';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// JIS
|
||||
case 'jis':
|
||||
$return['encoding'] = 'JIS';
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// JOHAB - Korean
|
||||
case 'johab':
|
||||
$return['encoding'] = 'JOHAB';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Russian
|
||||
case 'koi8-r':
|
||||
case 'koi8r':
|
||||
$return['encoding'] = 'KOI8-R';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// Turkish
|
||||
case 'koi8-t':
|
||||
case 'koi8t':
|
||||
$return['encoding'] = 'KOI8-T';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Ukrainian
|
||||
case 'koi8-u':
|
||||
case 'koi8u':
|
||||
$return['encoding'] = 'KOI8-U';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Russian+Ukrainian
|
||||
case 'koi8-ru':
|
||||
case 'koi8ru':
|
||||
$return['encoding'] = 'KOI8-RU';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Macintosh (Mac OS Classic)
|
||||
case 'macintosh':
|
||||
$return['encoding'] = 'Macintosh';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MacArabic (Mac OS Classic)
|
||||
case 'macarabic':
|
||||
$return['encoding'] = 'MacArabic';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MacCentralEurope (Mac OS Classic)
|
||||
case 'maccentraleurope':
|
||||
$return['encoding'] = 'MacCentralEurope';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MacCroatian (Mac OS Classic)
|
||||
case 'maccroatian':
|
||||
$return['encoding'] = 'MacCroatian';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MacCyrillic (Mac OS Classic)
|
||||
case 'maccyrillic':
|
||||
$return['encoding'] = 'MacCyrillic';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MacGreek (Mac OS Classic)
|
||||
case 'macgreek':
|
||||
$return['encoding'] = 'MacGreek';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MacHebrew (Mac OS Classic)
|
||||
case 'machebrew':
|
||||
$return['encoding'] = 'MacHebrew';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MacIceland (Mac OS Classic)
|
||||
case 'maciceland':
|
||||
$return['encoding'] = 'MacIceland';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MacRoman (Mac OS Classic)
|
||||
case 'macroman':
|
||||
$return['encoding'] = 'MacRoman';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MacRomania (Mac OS Classic)
|
||||
case 'macromania':
|
||||
$return['encoding'] = 'MacRomania';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MacThai (Mac OS Classic)
|
||||
case 'macthai':
|
||||
$return['encoding'] = 'MacThai';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MacTurkish (Mac OS Classic)
|
||||
case 'macturkish':
|
||||
$return['encoding'] = 'MacTurkish';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MacUkraine (Mac OS Classic)
|
||||
case 'macukraine':
|
||||
$return['encoding'] = 'MacUkraine';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// MuleLao-1
|
||||
case 'mulelao-1':
|
||||
case 'mulelao1':
|
||||
$return['encoding'] = 'MuleLao-1';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Shift_JIS
|
||||
case 'shift_jis':
|
||||
case 'sjis':
|
||||
case '932':
|
||||
$return['encoding'] = 'Shift_JIS';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// Shift_JISX0213
|
||||
case 'shift-jisx0213':
|
||||
case 'shiftjisx0213':
|
||||
$return['encoding'] = 'Shift_JISX0213';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// SJIS-win
|
||||
case 'sjis-win':
|
||||
case 'sjiswin':
|
||||
case 'shift_jis-win':
|
||||
$return['encoding'] = 'SJIS-win';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// TCVN - Vietnamese
|
||||
case 'tcvn':
|
||||
$return['encoding'] = 'TCVN';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// TDS565 - Turkish
|
||||
case 'tds565':
|
||||
$return['encoding'] = 'TDS565';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// TIS-620 Thai
|
||||
case 'tis-620':
|
||||
case 'tis620':
|
||||
$return['encoding'] = 'TIS-620';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UCS-2
|
||||
case 'ucs-2':
|
||||
case 'ucs2':
|
||||
case 'utf-16':
|
||||
case 'utf16':
|
||||
$return['encoding'] = 'UCS-2';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UCS-2BE
|
||||
case 'ucs-2be':
|
||||
case 'ucs2be':
|
||||
case 'utf-16be':
|
||||
case 'utf16be':
|
||||
$return['encoding'] = 'UCS-2BE';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UCS-2LE
|
||||
case 'ucs-2le':
|
||||
case 'ucs2le':
|
||||
case 'utf-16le':
|
||||
case 'utf16le':
|
||||
$return['encoding'] = 'UCS-2LE';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UCS-2-INTERNAL
|
||||
case 'ucs-2-internal':
|
||||
case 'ucs2internal':
|
||||
$return['encoding'] = 'UCS-2-INTERNAL';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// UCS-4
|
||||
case 'ucs-4':
|
||||
case 'ucs4':
|
||||
case 'utf-32':
|
||||
case 'utf32':
|
||||
$return['encoding'] = 'UCS-4';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UCS-4BE
|
||||
case 'ucs-4be':
|
||||
case 'ucs4be':
|
||||
case 'utf-32be':
|
||||
case 'utf32be':
|
||||
$return['encoding'] = 'UCS-4BE';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UCS-4LE
|
||||
case 'ucs-4le':
|
||||
case 'ucs4le':
|
||||
case 'utf-32le':
|
||||
case 'utf32le':
|
||||
$return['encoding'] = 'UCS-4LE';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UCS-4-INTERNAL
|
||||
case 'ucs-4-internal':
|
||||
case 'ucs4internal':
|
||||
$return['encoding'] = 'UCS-4-INTERNAL';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// UCS-16
|
||||
case 'ucs-16':
|
||||
case 'ucs16':
|
||||
$return['encoding'] = 'UCS-16';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UCS-16BE
|
||||
case 'ucs-16be':
|
||||
case 'ucs16be':
|
||||
$return['encoding'] = 'UCS-16BE';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UCS-16LE
|
||||
case 'ucs-16le':
|
||||
case 'ucs16le':
|
||||
$return['encoding'] = 'UCS-16LE';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UCS-32
|
||||
case 'ucs-32':
|
||||
case 'ucs32':
|
||||
$return['encoding'] = 'UCS-32';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UCS-32BE
|
||||
case 'ucs-32be':
|
||||
case 'ucs32be':
|
||||
$return['encoding'] = 'UCS-32BE';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UCS-32LE
|
||||
case 'ucs-32le':
|
||||
case 'ucs32le':
|
||||
$return['encoding'] = 'UCS-32LE';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UTF-7
|
||||
case 'utf-7':
|
||||
case 'utf7':
|
||||
$return['encoding'] = 'UTF-7';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// UTF7-IMAP
|
||||
case 'utf-7-imap':
|
||||
case 'utf7-imap':
|
||||
case 'utf7imap':
|
||||
$return['encoding'] = 'UTF7-IMAP';
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// VISCII - Vietnamese ASCII
|
||||
case 'viscii':
|
||||
$return['encoding'] = 'VISCII';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Windows-specific Central & Eastern Europe
|
||||
case 'cp1250':
|
||||
case 'windows-1250':
|
||||
case 'win-1250':
|
||||
case '1250':
|
||||
$return['encoding'] = 'Windows-1250';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Windows-specific Cyrillic
|
||||
case 'cp1251':
|
||||
case 'windows-1251':
|
||||
case 'win-1251':
|
||||
case '1251':
|
||||
$return['encoding'] = 'Windows-1251';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// Windows-specific Western Europe
|
||||
case 'cp1252':
|
||||
case 'windows-1252':
|
||||
case '1252':
|
||||
$return['encoding'] = 'Windows-1252';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
|
||||
// Windows-specific Greek
|
||||
case 'cp1253':
|
||||
case 'windows-1253':
|
||||
case '1253':
|
||||
$return['encoding'] = 'Windows-1253';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Windows-specific Turkish
|
||||
case 'cp1254':
|
||||
case 'windows-1254':
|
||||
case '1254':
|
||||
$return['encoding'] = 'Windows-1254';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Windows-specific Hebrew
|
||||
case 'cp1255':
|
||||
case 'windows-1255':
|
||||
case '1255':
|
||||
$return['encoding'] = 'Windows-1255';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Windows-specific Arabic
|
||||
case 'cp1256':
|
||||
case 'windows-1256':
|
||||
case '1256':
|
||||
$return['encoding'] = 'Windows-1256';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Windows-specific Baltic
|
||||
case 'cp1257':
|
||||
case 'windows-1257':
|
||||
case '1257':
|
||||
$return['encoding'] = 'Windows-1257';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Windows-specific Vietnamese
|
||||
case 'cp1258':
|
||||
case 'windows-1258':
|
||||
case '1258':
|
||||
$return['encoding'] = 'Windows-1258';
|
||||
$return['use_iconv'] = true;
|
||||
break;
|
||||
|
||||
// Default to UTF-8
|
||||
default:
|
||||
$return['encoding'] = 'UTF-8';
|
||||
$return['use_iconv'] = true;
|
||||
$return['use_mbstring'] = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Then, return it.
|
||||
return $return;
|
||||
}
|
||||
|
||||
function get_curl_version()
|
||||
{
|
||||
$curl = 0;
|
||||
if (is_array(curl_version()))
|
||||
{
|
||||
$curl = curl_version();
|
||||
$curl = $curl['version'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$curl = curl_version();
|
||||
$curl = explode(' ', $curl);
|
||||
$curl = explode('/', $curl[0]);
|
||||
$curl = $curl[1];
|
||||
}
|
||||
return $curl;
|
||||
}
|
||||
|
||||
function is_a_class($class1, $class2)
|
||||
{
|
||||
if (class_exists($class1))
|
||||
{
|
||||
$classes = array(strtolower($class1));
|
||||
while ($class1 = get_parent_class($class1))
|
||||
{
|
||||
$classes[] = strtolower($class1);
|
||||
}
|
||||
return in_array(strtolower($class2), $classes);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage integration
|
||||
*/
|
||||
class SimplePie_Locator
|
||||
{
|
||||
var $useragent;
|
||||
var $timeout;
|
||||
var $file;
|
||||
var $local;
|
||||
var $elsewhere;
|
||||
var $file_class = 'SimplePie_File';
|
||||
|
||||
function SimplePie_Locator(&$file, $timeout = 10, $useragent = null, $file_class = 'SimplePie_File')
|
||||
{
|
||||
if (!is_a($file, 'SimplePie_File'))
|
||||
{
|
||||
$this->file = new $this->file_class($file, $timeout, $useragent);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->file =& $file;
|
||||
}
|
||||
$this->file_class = $file_class;
|
||||
$this->useragent = $useragent;
|
||||
$this->timeout = $timeout;
|
||||
}
|
||||
|
||||
|
||||
function find()
|
||||
{
|
||||
if ($this->is_feed($this->file))
|
||||
{
|
||||
return $this->file->url;
|
||||
}
|
||||
|
||||
$autodiscovery = $this->autodiscovery($this->file);
|
||||
if ($autodiscovery)
|
||||
{
|
||||
return $autodiscovery;
|
||||
}
|
||||
|
||||
if ($this->get_links($this->file))
|
||||
{
|
||||
if (!empty($this->local))
|
||||
{
|
||||
$extension_local = $this->extension($this->local);
|
||||
if ($extension_local)
|
||||
{
|
||||
return $extension_local;
|
||||
}
|
||||
|
||||
$body_local = $this->body($this->local);
|
||||
if ($body_local)
|
||||
{
|
||||
return $body_local;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($this->elsewhere))
|
||||
{
|
||||
$extension_elsewhere = $this->extension($this->elsewhere);
|
||||
if ($extension_elsewhere)
|
||||
{
|
||||
return $extension_elsewhere;
|
||||
}
|
||||
|
||||
$body_elsewhere = $this->body($this->elsewhere);
|
||||
if ($body_elsewhere)
|
||||
{
|
||||
return $body_elsewhere;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function is_feed(&$file)
|
||||
{
|
||||
if (!is_a($file, 'SimplePie_File'))
|
||||
{
|
||||
if (isset($this))
|
||||
{
|
||||
$file2 = new $this->file_class($file, $this->timeout, 5, null, $this->useragent);
|
||||
}
|
||||
else
|
||||
{
|
||||
$file2 = new $this->file_class($file);
|
||||
}
|
||||
$file2->body();
|
||||
$file2->close();
|
||||
}
|
||||
else
|
||||
{
|
||||
$file2 =& $file;
|
||||
}
|
||||
$body = preg_replace('/<\!-(.*)-\>/msiU', '', $file2->body());
|
||||
if (preg_match('/<(\w+\:)?rss/msiU', $body) || preg_match('/<(\w+\:)?RDF/mi', $body) || preg_match('/<(\w+\:)?feed/mi', $body))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function autodiscovery(&$file)
|
||||
{
|
||||
$links = SimplePie_Misc::get_element('link', $file->body());
|
||||
$done = array();
|
||||
foreach ($links as $link)
|
||||
{
|
||||
if (!empty($link['attribs']['TYPE']['data']) && !empty($link['attribs']['HREF']['data']) && !empty($link['attribs']['REL']['data']))
|
||||
{
|
||||
$rel = preg_split('/\s+/', strtolower(trim($link['attribs']['REL']['data'])));
|
||||
$type = preg_match('/^(application\/rss\+xml|application\/atom\+xml|application\/rdf\+xml|application\/xml\+rss|application\/xml\+atom|application\/xml\+rdf|application\/xml|application\/x\.atom\+xml|text\/xml)(;|$)/msiU', trim($link['attribs']['TYPE']['data']));
|
||||
$href = SimplePie_Misc::absolutize_url(trim($link['attribs']['HREF']['data']), $this->file->url);
|
||||
if (!in_array($href, $done) && in_array('alternate', $rel) && $type)
|
||||
{
|
||||
$feed = $this->is_feed($href);
|
||||
if ($feed)
|
||||
{
|
||||
return $href;
|
||||
}
|
||||
}
|
||||
$done[] = $href;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function get_links(&$file)
|
||||
{
|
||||
$links = SimplePie_Misc::get_element('a', $file->body());
|
||||
foreach ($links as $link)
|
||||
{
|
||||
if (!empty($link['attribs']['HREF']['data']))
|
||||
{
|
||||
$href = trim($link['attribs']['HREF']['data']);
|
||||
$parsed = SimplePie_Misc::parse_url($href);
|
||||
if (empty($parsed['scheme']) || $parsed['scheme'] != 'javascript')
|
||||
{
|
||||
$current = SimplePie_Misc::parse_url($this->file->url);
|
||||
if (empty($parsed['authority']) || $parsed['authority'] == $current['authority'])
|
||||
{
|
||||
$this->local[] = SimplePie_Misc::absolutize_url($href, $this->file->url);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->elsewhere[] = SimplePie_Misc::absolutize_url($href, $this->file->url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($this->local))
|
||||
{
|
||||
$this->local = array_unique($this->local);
|
||||
}
|
||||
if (!empty($this->elsewhere))
|
||||
{
|
||||
$this->elsewhere = array_unique($this->elsewhere);
|
||||
}
|
||||
if (!empty($this->local) || !empty($this->elsewhere))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function extension(&$array)
|
||||
{
|
||||
foreach ($array as $key => $value)
|
||||
{
|
||||
$value = SimplePie_Misc::absolutize_url($value, $this->file->url);
|
||||
if (in_array(strrchr($value, '.'), array('.rss', '.rdf', '.atom', '.xml')))
|
||||
{
|
||||
if ($this->is_feed($value))
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($array[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function body(&$array)
|
||||
{
|
||||
foreach ($array as $key => $value)
|
||||
{
|
||||
$value = SimplePie_Misc::absolutize_url($value, $this->file->url);
|
||||
if (preg_match('/(rss|rdf|atom|xml)/i', $value))
|
||||
{
|
||||
if ($this->is_feed($value))
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($array[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage integration
|
||||
*/
|
||||
class SimplePie_Parser
|
||||
{
|
||||
var $encoding;
|
||||
var $data;
|
||||
var $namespaces = array('xml' => 'HTTP://WWW.W3.ORG/XML/1998/NAMESPACE', 'atom' => 'ATOM', 'rss2' => 'RSS', 'rdf' => 'RDF', 'rss1' => 'RSS', 'dc' => 'DC', 'xhtml' => 'XHTML', 'content' => 'CONTENT');
|
||||
var $xml;
|
||||
var $error_code;
|
||||
var $error_string;
|
||||
var $current_line;
|
||||
var $current_column;
|
||||
var $current_byte;
|
||||
var $tag_name;
|
||||
var $inside_item;
|
||||
var $item_number = 0;
|
||||
var $inside_channel;
|
||||
var $author_number= 0;
|
||||
var $category_number = 0;
|
||||
var $enclosure_number = 0;
|
||||
var $link_number = 0;
|
||||
var $item_link_number = 0;
|
||||
var $inside_image;
|
||||
var $attribs;
|
||||
var $is_first;
|
||||
var $inside_author;
|
||||
|
||||
|
||||
function SimplePie_Parser($data, $encoding, $return_xml = false)
|
||||
{
|
||||
$this->encoding = $encoding;
|
||||
|
||||
// Strip BOM:
|
||||
// UTF-32 Big Endian BOM
|
||||
if (strpos($data, sprintf('%c%c%c%c', 0x00, 0x00, 0xFE, 0xFF)) === 0)
|
||||
{
|
||||
$data = substr($data, 4);
|
||||
}
|
||||
// UTF-32 Little Endian BOM
|
||||
else if (strpos($data, sprintf('%c%c%c%c', 0xFF, 0xFE, 0x00, 0x00)) === 0)
|
||||
{
|
||||
$data = substr($data, 4);
|
||||
}
|
||||
// UTF-16 Big Endian BOM
|
||||
else if (strpos($data, sprintf('%c%c', 0xFE, 0xFF)) === 0)
|
||||
{
|
||||
$data = substr($data, 2);
|
||||
}
|
||||
// UTF-16 Little Endian BOM
|
||||
else if (strpos($data, sprintf('%c%c', 0xFF, 0xFE)) === 0)
|
||||
{
|
||||
$data = substr($data, 2);
|
||||
}
|
||||
// UTF-8 BOM
|
||||
else if (strpos($data, sprintf('%c%c%c', 0xEF, 0xBB, 0xBF)) === 0)
|
||||
{
|
||||
$data = substr($data, 3);
|
||||
}
|
||||
|
||||
// Make sure the XML prolog is sane and has the correct encoding
|
||||
if (preg_match('/^<\?xml(.*)?>/msiU', $data, $prolog))
|
||||
{
|
||||
$data = substr_replace($data, '', 0, strlen($prolog[0]));
|
||||
}
|
||||
$data = "<?xml version='1.0' encoding='$encoding'?>\n" . $data;
|
||||
|
||||
// Put some data into CDATA blocks
|
||||
// If we're RSS
|
||||
if ((stristr($data, '<rss') || preg_match('/<([a-z0-9]+\:)?RDF/mi', $data)) && (preg_match('/<([a-z0-9]+\:)?channel/mi', $data) || preg_match('/<([a-z0-9]+\:)?item/mi', $data)))
|
||||
{
|
||||
$sp_elements = array(
|
||||
'author',
|
||||
'category',
|
||||
'copyright',
|
||||
'description',
|
||||
'docs',
|
||||
'generator',
|
||||
'guid',
|
||||
'language',
|
||||
'lastBuildDate',
|
||||
'link',
|
||||
'managingEditor',
|
||||
'pubDate',
|
||||
'title',
|
||||
'url',
|
||||
'webMaster',
|
||||
);
|
||||
}
|
||||
// Or if we're Atom
|
||||
else
|
||||
{
|
||||
$sp_elements = array(
|
||||
'content',
|
||||
'copyright',
|
||||
'name',
|
||||
'subtitle',
|
||||
'summary',
|
||||
'tagline',
|
||||
'title',
|
||||
);
|
||||
}
|
||||
foreach ($sp_elements as $full)
|
||||
{
|
||||
$data = preg_replace_callback("/<($full)((\s*((\w+:)?\w+)\s*=\s*(\"([^\"]*)\"|'([^']*)'))*)\s*(\/>|>(.*)<\/$full>)/msiU", array(&$this, 'add_cdata'), $data);
|
||||
}
|
||||
foreach ($sp_elements as $full)
|
||||
{
|
||||
// Deal with CDATA within CDATA (this can be caused by us inserting CDATA above)
|
||||
$data = preg_replace_callback("/<($full)((\s*((\w+:)?\w+)\s*=\s*(\"([^\"]*)\"|'([^']*)'))*)\s*(\/>|><!\[CDATA\[(.*)\]\]><\/$full>)/msiU", array(&$this, 'cdata_in_cdata'), $data);
|
||||
}
|
||||
|
||||
// Return the XML, if so desired
|
||||
if ($return_xml)
|
||||
{
|
||||
$this->data =& $data;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the parser
|
||||
$this->xml = xml_parser_create_ns($encoding);
|
||||
xml_parser_set_option($this->xml, XML_OPTION_SKIP_WHITE, 1);
|
||||
xml_set_object($this->xml, $this);
|
||||
xml_set_character_data_handler($this->xml, 'data_handler');
|
||||
xml_set_element_handler($this->xml, 'start_handler', 'end_handler');
|
||||
xml_set_start_namespace_decl_handler($this->xml, 'start_name_space');
|
||||
xml_set_end_namespace_decl_handler($this->xml, 'end_name_space');
|
||||
|
||||
// Parse!
|
||||
if (!xml_parse($this->xml, $data))
|
||||
{
|
||||
$this->data = null;
|
||||
$this->error_code = xml_get_error_code($this->xml);
|
||||
$this->error_string = xml_error_string($this->error_code);
|
||||
}
|
||||
$this->current_line = xml_get_current_line_number($this->xml);
|
||||
$this->current_column = xml_get_current_column_number($this->xml);
|
||||
$this->current_byte = xml_get_current_byte_index($this->xml);
|
||||
xml_parser_free($this->xml);
|
||||
return;
|
||||
}
|
||||
|
||||
function add_cdata($match)
|
||||
{
|
||||
if (isset($match[10]))
|
||||
{
|
||||
return "<$match[1]$match[2]><![CDATA[$match[10]]]></$match[1]>";
|
||||
}
|
||||
return $match[0];
|
||||
}
|
||||
|
||||
function cdata_in_cdata($match)
|
||||
{
|
||||
if (isset($match[10]))
|
||||
{
|
||||
$match[10] = preg_replace_callback('/<!\[CDATA\[(.*)\]\]>/msiU', array(&$this, 'real_cdata_in_cdata'), $match[10]);
|
||||
return "<$match[1]$match[2]><![CDATA[$match[10]]]></$match[1]>";
|
||||
}
|
||||
return $match[0];
|
||||
}
|
||||
|
||||
function real_cdata_in_cdata($match)
|
||||
{
|
||||
return htmlspecialchars($match[1], ENT_NOQUOTES);
|
||||
}
|
||||
|
||||
function do_add_content(&$array, $data)
|
||||
{
|
||||
if ($this->is_first)
|
||||
{
|
||||
$array['data'] = $data;
|
||||
$array['attribs'] = $this->attribs;
|
||||
}
|
||||
else
|
||||
{
|
||||
$array['data'] .= $data;
|
||||
}
|
||||
}
|
||||
|
||||
function start_handler($parser, $name, $attribs)
|
||||
{
|
||||
$this->tag_name = $name;
|
||||
$this->attribs = $attribs;
|
||||
$this->is_first = true;
|
||||
switch ($this->tag_name)
|
||||
{
|
||||
case 'ITEM':
|
||||
case $this->namespaces['rss2'] . ':ITEM':
|
||||
case $this->namespaces['rss1'] . ':ITEM':
|
||||
case 'ENTRY':
|
||||
case $this->namespaces['atom'] . ':ENTRY':
|
||||
$this->inside_item = true;
|
||||
$this->do_add_content($this->data['items'][$this->item_number], '');
|
||||
break;
|
||||
|
||||
case 'CHANNEL':
|
||||
case $this->namespaces['rss2'] . ':CHANNEL':
|
||||
case $this->namespaces['rss1'] . ':CHANNEL':
|
||||
$this->inside_channel = true;
|
||||
break;
|
||||
|
||||
case 'RSS':
|
||||
case $this->namespaces['rss2'] . ':RSS':
|
||||
$this->data['feedinfo']['type'] = 'RSS';
|
||||
$this->do_add_content($this->data['feeddata'], '');
|
||||
if (!empty($attribs['VERSION']))
|
||||
{
|
||||
$this->data['feedinfo']['version'] = trim($attribs['VERSION']);
|
||||
}
|
||||
break;
|
||||
|
||||
case $this->namespaces['rdf'] . ':RDF':
|
||||
$this->data['feedinfo']['type'] = 'RSS';
|
||||
$this->do_add_content($this->data['feeddata'], '');
|
||||
$this->data['feedinfo']['version'] = 1;
|
||||
break;
|
||||
|
||||
case 'FEED':
|
||||
case $this->namespaces['atom'] . ':FEED':
|
||||
$this->data['feedinfo']['type'] = 'Atom';
|
||||
$this->do_add_content($this->data['feeddata'], '');
|
||||
if (!empty($attribs['VERSION']))
|
||||
{
|
||||
$this->data['feedinfo']['version'] = trim($attribs['VERSION']);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'IMAGE':
|
||||
case $this->namespaces['rss2'] . ':IMAGE':
|
||||
case $this->namespaces['rss1'] . ':IMAGE':
|
||||
if ($this->inside_channel)
|
||||
{
|
||||
$this->inside_image = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($this->data['feedinfo']['type']) && $this->data['feedinfo']['type'] == 'Atom' && ($this->tag_name == 'AUTHOR' || $this->tag_name == $this->namespaces['atom'] . ':AUTHOR'))
|
||||
{
|
||||
$this->inside_author = true;
|
||||
}
|
||||
$this->data_handler($this->xml, '');
|
||||
}
|
||||
|
||||
function data_handler($parser, $data)
|
||||
{
|
||||
if ($this->inside_item)
|
||||
{
|
||||
switch ($this->tag_name)
|
||||
{
|
||||
case 'TITLE':
|
||||
case $this->namespaces['rss1'] . ':TITLE':
|
||||
case $this->namespaces['rss2'] . ':TITLE':
|
||||
case $this->namespaces['atom'] . ':TITLE':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['title'], $data);
|
||||
break;
|
||||
|
||||
case $this->namespaces['dc'] . ':TITLE':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['dc:title'], $data);
|
||||
break;
|
||||
|
||||
case 'CONTENT':
|
||||
case $this->namespaces['atom'] . ':CONTENT':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['content'], $data);
|
||||
break;
|
||||
|
||||
case $this->namespaces['content'] . ':ENCODED':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['encoded'], $data);
|
||||
break;
|
||||
|
||||
case 'SUMMARY':
|
||||
case $this->namespaces['atom'] . ':SUMMARY':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['summary'], $data);
|
||||
break;
|
||||
|
||||
case 'LONGDESC':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['longdesc'], $data);
|
||||
break;
|
||||
|
||||
case 'DESCRIPTION':
|
||||
case $this->namespaces['rss1'] . ':DESCRIPTION':
|
||||
case $this->namespaces['rss2'] . ':DESCRIPTION':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['description'], $data);
|
||||
break;
|
||||
|
||||
case $this->namespaces['dc'] . ':DESCRIPTION':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['dc:description'], $data);
|
||||
break;
|
||||
|
||||
case 'LINK':
|
||||
case $this->namespaces['rss1'] . ':LINK':
|
||||
case $this->namespaces['rss2'] . ':LINK':
|
||||
case $this->namespaces['atom'] . ':LINK':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['link'][$this->item_link_number], $data);
|
||||
break;
|
||||
|
||||
case 'ENCLOSURE':
|
||||
case $this->namespaces['rss1'] . ':ENCLOSURE':
|
||||
case $this->namespaces['rss2'] . ':ENCLOSURE':
|
||||
case $this->namespaces['atom'] . ':ENCLOSURE':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['enclosure'][$this->enclosure_number], $data);
|
||||
break;
|
||||
|
||||
case 'GUID':
|
||||
case $this->namespaces['rss1'] . ':GUID':
|
||||
case $this->namespaces['rss2'] . ':GUID':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['guid'], $data);
|
||||
break;
|
||||
|
||||
case 'ID':
|
||||
case $this->namespaces['atom'] . ':ID':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['id'], $data);
|
||||
break;
|
||||
|
||||
case 'PUBDATE':
|
||||
case $this->namespaces['rss1'] . ':PUBDATE':
|
||||
case $this->namespaces['rss2'] . ':PUBDATE':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['pubdate'], $data);
|
||||
break;
|
||||
|
||||
case $this->namespaces['dc'] . ':DATE':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['dc:date'], $data);
|
||||
break;
|
||||
|
||||
case 'ISSUED':
|
||||
case $this->namespaces['atom'] . ':ISSUED':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['issued'], $data);
|
||||
break;
|
||||
|
||||
case 'PUBLISHED':
|
||||
case $this->namespaces['atom'] . ':PUBLISHED':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['published'], $data);
|
||||
break;
|
||||
|
||||
case 'MODIFIED':
|
||||
case $this->namespaces['atom'] . ':MODIFIED':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['modified'], $data);
|
||||
break;
|
||||
|
||||
case 'UPDATED':
|
||||
case $this->namespaces['atom'] . ':UPDATED':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['updated'], $data);
|
||||
break;
|
||||
|
||||
case 'CATEGORY':
|
||||
case $this->namespaces['rss1'] . ':CATEGORY':
|
||||
case $this->namespaces['rss2'] . ':CATEGORY':
|
||||
case $this->namespaces['atom'] . ':CATEGORY':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['category'][$this->category_number], $data);
|
||||
break;
|
||||
|
||||
case $this->namespaces['dc'] . ':SUBJECT':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['subject'][$this->category_number], $data);
|
||||
break;
|
||||
|
||||
case $this->namespaces['dc'] . ':CREATOR':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['creator'][$this->author_number], $data);
|
||||
break;
|
||||
|
||||
case 'AUTHOR':
|
||||
case $this->namespaces['rss1'] . ':AUTHOR':
|
||||
case $this->namespaces['rss2'] . ':AUTHOR':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['author'][$this->author_number]['rss'], $data);
|
||||
break;
|
||||
}
|
||||
|
||||
if ($this->inside_author)
|
||||
{
|
||||
switch ($this->tag_name)
|
||||
{
|
||||
case 'NAME':
|
||||
case $this->namespaces['atom'] . ':NAME':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['author'][$this->author_number]['name'], $data);
|
||||
break;
|
||||
|
||||
case 'URL':
|
||||
case $this->namespaces['atom'] . ':URL':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['author'][$this->author_number]['url'], $data);
|
||||
break;
|
||||
|
||||
case 'URI':
|
||||
case $this->namespaces['atom'] . ':URI':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['author'][$this->author_number]['uri'], $data);
|
||||
break;
|
||||
|
||||
case 'HOMEPAGE':
|
||||
case $this->namespaces['atom'] . ':HOMEPAGE':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['author'][$this->author_number]['homepage'], $data);
|
||||
break;
|
||||
|
||||
case 'EMAIL':
|
||||
case $this->namespaces['atom'] . ':EMAIL':
|
||||
$this->do_add_content($this->data['items'][$this->item_number]['author'][$this->author_number]['email'], $data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (($this->inside_channel && !$this->inside_image) || (isset($this->data['feedinfo']['type']) && $this->data['feedinfo']['type'] == 'Atom'))
|
||||
{
|
||||
switch ($this->tag_name)
|
||||
{
|
||||
case 'TITLE':
|
||||
case $this->namespaces['rss1'] . ':TITLE':
|
||||
case $this->namespaces['rss2'] . ':TITLE':
|
||||
case $this->namespaces['atom'] . ':TITLE':
|
||||
$this->do_add_content($this->data['info']['title'], $data);
|
||||
break;
|
||||
|
||||
case 'LINK':
|
||||
case $this->namespaces['rss1'] . ':LINK':
|
||||
case $this->namespaces['rss2'] . ':LINK':
|
||||
case $this->namespaces['atom'] . ':LINK':
|
||||
$this->do_add_content($this->data['info']['link'][$this->link_number], $data);
|
||||
break;
|
||||
|
||||
case 'DESCRIPTION':
|
||||
case $this->namespaces['rss1'] . ':DESCRIPTION':
|
||||
case $this->namespaces['rss2'] . ':DESCRIPTION':
|
||||
$this->do_add_content($this->data['info']['description'], $data);
|
||||
break;
|
||||
|
||||
case $this->namespaces['dc'] . ':DESCRIPTION':
|
||||
$this->do_add_content($this->data['info']['dc:description'], $data);
|
||||
break;
|
||||
|
||||
case 'TAGLINE':
|
||||
case $this->namespaces['atom'] . ':TAGLINE':
|
||||
$this->do_add_content($this->data['info']['tagline'], $data);
|
||||
break;
|
||||
|
||||
case 'SUBTITLE':
|
||||
case $this->namespaces['atom'] . ':SUBTITLE':
|
||||
$this->do_add_content($this->data['info']['subtitle'], $data);
|
||||
break;
|
||||
|
||||
case 'COPYRIGHT':
|
||||
case $this->namespaces['rss1'] . ':COPYRIGHT':
|
||||
case $this->namespaces['rss2'] . ':COPYRIGHT':
|
||||
case $this->namespaces['atom'] . ':COPYRIGHT':
|
||||
$this->do_add_content($this->data['info']['copyright'], $data);
|
||||
break;
|
||||
|
||||
case 'LANGUAGE':
|
||||
case $this->namespaces['rss1'] . ':LANGUAGE':
|
||||
case $this->namespaces['rss2'] . ':LANGUAGE':
|
||||
$this->do_add_content($this->data['info']['language'], $data);
|
||||
break;
|
||||
|
||||
case 'LOGO':
|
||||
case $this->namespaces['atom'] . ':LOGO':
|
||||
$this->do_add_content($this->data['info']['logo'], $data);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
else if ($this->inside_channel && $this->inside_image)
|
||||
{
|
||||
switch ($this->tag_name)
|
||||
{
|
||||
case 'TITLE':
|
||||
case $this->namespaces['rss1'] . ':TITLE':
|
||||
case $this->namespaces['rss2'] . ':TITLE':
|
||||
$this->do_add_content($this->data['info']['image']['title'], $data);
|
||||
break;
|
||||
|
||||
case 'URL':
|
||||
case $this->namespaces['rss1'] . ':URL':
|
||||
case $this->namespaces['rss2'] . ':URL':
|
||||
$this->do_add_content($this->data['info']['image']['url'], $data);
|
||||
break;
|
||||
|
||||
case 'LINK':
|
||||
case $this->namespaces['rss1'] . ':LINK':
|
||||
case $this->namespaces['rss2'] . ':LINK':
|
||||
$this->do_add_content($this->data['info']['image']['link'], $data);
|
||||
break;
|
||||
|
||||
case 'WIDTH':
|
||||
case $this->namespaces['rss1'] . ':WIDTH':
|
||||
case $this->namespaces['rss2'] . ':WIDTH':
|
||||
$this->do_add_content($this->data['info']['image']['width'], $data);
|
||||
break;
|
||||
|
||||
case 'HEIGHT':
|
||||
case $this->namespaces['rss1'] . ':HEIGHT':
|
||||
case $this->namespaces['rss2'] . ':HEIGHT':
|
||||
$this->do_add_content($this->data['info']['image']['height'], $data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->is_first = false;
|
||||
}
|
||||
|
||||
function end_handler($parser, $name)
|
||||
{
|
||||
$this->tag_name = '';
|
||||
switch ($name)
|
||||
{
|
||||
case 'ITEM':
|
||||
case $this->namespaces['rss1'] . ':ITEM':
|
||||
case $this->namespaces['rss2'] . ':ITEM':
|
||||
case 'ENTRY':
|
||||
case $this->namespaces['atom'] . ':ENTRY':
|
||||
$this->inside_item = false;
|
||||
$this->item_number++;
|
||||
$this->author_number = 0;
|
||||
$this->category_number = 0;
|
||||
$this->enclosure_number = 0;
|
||||
$this->item_link_number = 0;
|
||||
break;
|
||||
|
||||
case 'CHANNEL':
|
||||
case $this->namespaces['rss1'] . ':CHANNEL':
|
||||
case $this->namespaces['rss2'] . ':CHANNEL':
|
||||
$this->inside_channel = false;
|
||||
break;
|
||||
|
||||
case 'IMAGE':
|
||||
case $this->namespaces['rss1'] . ':IMAGE':
|
||||
case $this->namespaces['rss2'] . ':IMAGE':
|
||||
$this->inside_image = false;
|
||||
break;
|
||||
|
||||
case 'AUTHOR':
|
||||
case $this->namespaces['rss1'] . ':AUTHOR':
|
||||
case $this->namespaces['rss2'] . ':AUTHOR':
|
||||
case $this->namespaces['atom'] . ':AUTHOR':
|
||||
$this->author_number++;
|
||||
$this->inside_author = false;
|
||||
break;
|
||||
|
||||
case 'CATEGORY':
|
||||
case $this->namespaces['rss1'] . ':CATEGORY':
|
||||
case $this->namespaces['rss2'] . ':CATEGORY':
|
||||
case $this->namespaces['atom'] . ':CATEGORY':
|
||||
case $this->namespaces['dc'] . ':SUBJECT':
|
||||
$this->category_number++;
|
||||
break;
|
||||
|
||||
case 'ENCLOSURE':
|
||||
case $this->namespaces['rss1'] . ':ENCLOSURE':
|
||||
case $this->namespaces['rss2'] . ':ENCLOSURE':
|
||||
$this->enclosure_number++;
|
||||
break;
|
||||
|
||||
case 'LINK':
|
||||
case $this->namespaces['rss1'] . ':LINK':
|
||||
case $this->namespaces['rss2'] . ':LINK':
|
||||
case $this->namespaces['atom'] . ':LINK':
|
||||
if ($this->inside_item)
|
||||
{
|
||||
$this->item_link_number++;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->link_number++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function start_name_space($parser, $prefix, $uri = null)
|
||||
{
|
||||
$prefix = strtoupper($prefix);
|
||||
$uri = strtoupper($uri);
|
||||
if ($prefix == 'ATOM' || $uri == 'HTTP://WWW.W3.ORG/2005/ATOM' || $uri == 'HTTP://PURL.ORG/ATOM/NS#')
|
||||
{
|
||||
$this->namespaces['atom'] = $uri;
|
||||
}
|
||||
else if ($prefix == 'RSS2' || $uri == 'HTTP://BACKEND.USERLAND.COM/RSS2')
|
||||
{
|
||||
$this->namespaces['rss2'] = $uri;
|
||||
}
|
||||
else if ($prefix == 'RDF' || $uri == 'HTTP://WWW.W3.ORG/1999/02/22-RDF-SYNTAX-NS#')
|
||||
{
|
||||
$this->namespaces['rdf'] = $uri;
|
||||
}
|
||||
else if ($prefix == 'RSS' || $uri == 'HTTP://PURL.ORG/RSS/1.0/' || $uri == 'HTTP://MY.NETSCAPE.COM/RDF/SIMPLE/0.9/')
|
||||
{
|
||||
$this->namespaces['rss1'] = $uri;
|
||||
}
|
||||
else if ($prefix == 'DC' || $uri == 'HTTP://PURL.ORG/DC/ELEMENTS/1.1/')
|
||||
{
|
||||
$this->namespaces['dc'] = $uri;
|
||||
}
|
||||
else if ($prefix == 'XHTML' || $uri == 'HTTP://WWW.W3.ORG/1999/XHTML')
|
||||
{
|
||||
$this->namespaces['xhtml'] = $uri;
|
||||
$this->xhtml_prefix = $prefix;
|
||||
}
|
||||
else if ($prefix == 'CONTENT' || $uri == 'HTTP://PURL.ORG/RSS/1.0/MODULES/CONTENT/')
|
||||
{
|
||||
$this->namespaces['content'] = $uri;
|
||||
}
|
||||
}
|
||||
|
||||
function end_name_space($parser, $prefix)
|
||||
{
|
||||
if ($key = array_search(strtoupper($prefix), $this->namespaces))
|
||||
{
|
||||
if ($key == 'atom')
|
||||
{
|
||||
$this->namespaces['atom'] = 'ATOM';
|
||||
}
|
||||
else if ($key == 'rss2')
|
||||
{
|
||||
$this->namespaces['rss2'] = 'RSS';
|
||||
}
|
||||
else if ($key == 'rdf')
|
||||
{
|
||||
$this->namespaces['rdf'] = 'RDF';
|
||||
}
|
||||
else if ($key == 'rss1')
|
||||
{
|
||||
$this->namespaces['rss1'] = 'RSS';
|
||||
}
|
||||
else if ($key == 'dc')
|
||||
{
|
||||
$this->namespaces['dc'] = 'DC';
|
||||
}
|
||||
else if ($key == 'xhtml')
|
||||
{
|
||||
$this->namespaces['xhtml'] = 'XHTML';
|
||||
$this->xhtml_prefix = 'XHTML';
|
||||
}
|
||||
else if ($key == 'content')
|
||||
{
|
||||
$this->namespaces['content'] = 'CONTENT';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage integration
|
||||
*/
|
||||
class SimplePie_Sanitize
|
||||
{
|
||||
// Private vars
|
||||
var $feedinfo;
|
||||
var $info;
|
||||
var $items;
|
||||
var $feed_xmlbase;
|
||||
var $item_xmlbase;
|
||||
var $attribs;
|
||||
var $cached_entities;
|
||||
var $cache_convert_entities;
|
||||
|
||||
// Options
|
||||
var $remove_div = true;
|
||||
var $strip_ads = false;
|
||||
var $replace_headers = false;
|
||||
var $bypass_image_hotlink = false;
|
||||
var $bypass_image_hotlink_page = false;
|
||||
var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
|
||||
var $encode_instead_of_strip = false;
|
||||
var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur');
|
||||
var $input_encoding = 'UTF-8';
|
||||
var $output_encoding = 'UTF-8';
|
||||
var $item_class = 'SimplePie_Item';
|
||||
var $author_class = 'SimplePie_Author';
|
||||
var $enclosure_class = 'SimplePie_Enclosure';
|
||||
|
||||
function remove_div($enable = true)
|
||||
{
|
||||
$this->remove_div = (bool) $enable;
|
||||
}
|
||||
|
||||
function strip_ads($enable = false)
|
||||
{
|
||||
$this->strip_ads = (bool) $enable;
|
||||
}
|
||||
|
||||
function replace_headers($enable = false)
|
||||
{
|
||||
$this->enable_headers = (bool) $enable;
|
||||
}
|
||||
|
||||
function bypass_image_hotlink($get = false)
|
||||
{
|
||||
if ($get)
|
||||
{
|
||||
$this->bypass_image_hotlink = (string) $get;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->bypass_image_hotlink = false;
|
||||
}
|
||||
}
|
||||
|
||||
function bypass_image_hotlink_page($page = false)
|
||||
{
|
||||
if ($page)
|
||||
{
|
||||
$this->bypass_image_hotlink_page = (string) $page;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->bypass_image_hotlink_page = false;
|
||||
}
|
||||
}
|
||||
|
||||
function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
|
||||
{
|
||||
if ($tags)
|
||||
{
|
||||
if (is_array($tags))
|
||||
{
|
||||
$this->strip_htmltags = $tags;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->strip_htmltags = explode(',', $tags);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->strip_htmltags = false;
|
||||
}
|
||||
}
|
||||
|
||||
function encode_instead_of_strip($enable = false)
|
||||
{
|
||||
$this->encode_instead_of_strip = (bool) $enable;
|
||||
}
|
||||
|
||||
function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur'))
|
||||
{
|
||||
if ($attribs)
|
||||
{
|
||||
if (is_array($attribs))
|
||||
{
|
||||
$this->strip_attributes = $attribs;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->strip_attributes = explode(',', $attribs);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->strip_attributes = false;
|
||||
}
|
||||
}
|
||||
|
||||
function input_encoding($encoding = 'UTF-8')
|
||||
{
|
||||
$this->input_encoding = (string) $encoding;
|
||||
}
|
||||
|
||||
function output_encoding($encoding = 'UTF-8')
|
||||
{
|
||||
$this->output_encoding = (string) $encoding;
|
||||
}
|
||||
|
||||
function set_item_class($class = 'SimplePie_Item')
|
||||
{
|
||||
if (SimplePie_Misc::is_a_class($class, 'SimplePie_Item'))
|
||||
{
|
||||
$this->item_class = $class;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function set_author_class($class = 'SimplePie_Author')
|
||||
{
|
||||
if (SimplePie_Misc::is_a_class($class, 'SimplePie_Author'))
|
||||
{
|
||||
$this->author_class = $class;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function set_enclosure_class($class = 'SimplePie_Enclosure')
|
||||
{
|
||||
if (SimplePie_Misc::is_a_class($class, 'SimplePie_Enclosure'))
|
||||
{
|
||||
$this->enclosure_class = $class;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function parse_data_array(&$data, $url)
|
||||
{
|
||||
// Feed Info (Type and Version)
|
||||
if (!empty($data['feedinfo']['type']))
|
||||
{
|
||||
$this->feedinfo = $data['feedinfo'];
|
||||
}
|
||||
|
||||
// Feed level xml:base
|
||||
if (!empty($data['feeddata']['attribs']['XML:BASE']))
|
||||
{
|
||||
$this->feed_xmlbase = $data['feeddata']['attribs']['XML:BASE'];
|
||||
}
|
||||
else if (!empty($data['feeddata']['attribs']['HTTP://WWW.W3.ORG/XML/1998/NAMESPACE:BASE']))
|
||||
{
|
||||
$this->feed_xmlbase = $data['feeddata']['attribs']['HTTP://WWW.W3.ORG/XML/1998/NAMESPACE:BASE'];
|
||||
}
|
||||
// FeedBurner feeds use alternate link
|
||||
else if (strpos($url, 'http://feeds.feedburner.com/') !== 0)
|
||||
{
|
||||
$this->feed_xmlbase = SimplePie_Misc::parse_url($url);
|
||||
if (empty($this->feed_xmlbase['authority']))
|
||||
{
|
||||
$this->feed_xmlbase = preg_replace('/^' . preg_quote(realpath($_SERVER['DOCUMENT_ROOT']), '/') . '/', '', realpath($url));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->feed_xmlbase = $url;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Feed link(s)
|
||||
if (!empty($data['info']['link']))
|
||||
{
|
||||
foreach ($data['info']['link'] as $link)
|
||||
{
|
||||
if (empty($link['attribs']['REL']))
|
||||
{
|
||||
$rel = 'alternate';
|
||||
}
|
||||
else
|
||||
{
|
||||
$rel = strtolower($link['attribs']['REL']);
|
||||
}
|
||||
if ($rel == 'enclosure')
|
||||
{
|
||||
$href = null;
|
||||
$type = null;
|
||||
$length = null;
|
||||
if (!empty($link['data']))
|
||||
{
|
||||
$href = $this->sanitize($link['data'], $link['attribs'], true);
|
||||
}
|
||||
else if (!empty($link['attribs']['HREF']))
|
||||
{
|
||||
$href = $this->sanitize($link['attribs']['HREF'], $link['attribs'], true);
|
||||
}
|
||||
if (!empty($link['attribs']['TYPE'])) {
|
||||
$type = $this->sanitize($link['attribs']['TYPE'], $link['attribs']);
|
||||
}
|
||||
if (!empty($link['attribs']['LENGTH'])) {
|
||||
$length = $this->sanitize($link['attribs']['LENGTH'], $link['attribs']);
|
||||
}
|
||||
$this->info['link']['enclosure'][] = new $this->enclosure_class($href, $type, $length);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!empty($link['data']))
|
||||
{
|
||||
$this->info['link'][$rel][] = $this->sanitize($link['data'], $link['attribs'], true);
|
||||
}
|
||||
else if (!empty($link['attribs']['HREF']))
|
||||
{
|
||||
$this->info['link'][$rel][] = $this->sanitize($link['attribs']['HREF'], $link['attribs'], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use the first alternate link if we don't have any feed xml:base
|
||||
if (empty($this->feed_xmlbase) && !empty($this->info['link']['alternate'][0]))
|
||||
{
|
||||
$this->feed_xmlbase = $this->info['link']['alternate'][0];
|
||||
}
|
||||
|
||||
// Feed Title
|
||||
if (!empty($data['info']['title']['data']))
|
||||
{
|
||||
$this->info['title'] = $this->sanitize($data['info']['title']['data'], $data['info']['title']['attribs']);
|
||||
}
|
||||
|
||||
// Feed Descriptions
|
||||
if (!empty($data['info']['description']['data']))
|
||||
{
|
||||
$this->info['description'] = $this->sanitize($data['info']['description']['data'], $data['info']['description']['attribs'], false, true);
|
||||
}
|
||||
if (!empty($data['info']['dc:description']['data']))
|
||||
{
|
||||
$this->info['dc:description'] = $this->sanitize($data['info']['dc:description']['data'], $data['info']['dc:description']['attribs']);
|
||||
}
|
||||
if (!empty($data['info']['tagline']['data']))
|
||||
{
|
||||
$this->info['tagline'] = $this->sanitize($data['info']['tagline']['data'], $data['info']['tagline']['attribs']);
|
||||
}
|
||||
if (!empty($data['info']['subtitle']['data']))
|
||||
{
|
||||
$this->info['subtitle'] = $this->sanitize($data['info']['subtitle']['data'], $data['info']['subtitle']['attribs']);
|
||||
}
|
||||
|
||||
// Feed Language
|
||||
if (!empty($data['info']['language']['data']))
|
||||
{
|
||||
$this->info['language'] = $this->sanitize($data['info']['language']['data'], $data['info']['language']['attribs']);
|
||||
}
|
||||
if (!empty($data['feeddata']['attribs']['XML:LANG']))
|
||||
{
|
||||
$this->info['xml:lang'] = $this->sanitize($data['feeddata']['attribs']['XML:LANG'], null);
|
||||
}
|
||||
else if (!empty($data['feeddata']['attribs']['HTTP://WWW.W3.ORG/XML/1998/NAMESPACE:LANG']))
|
||||
{
|
||||
$this->info['xml:lang'] = $this->sanitize($data['feeddata']['attribs']['HTTP://WWW.W3.ORG/XML/1998/NAMESPACE:LANG'], null);
|
||||
}
|
||||
|
||||
// Feed Copyright
|
||||
if (!empty($data['info']['copyright']['data']))
|
||||
{
|
||||
$this->info['copyright'] = $this->sanitize($data['info']['copyright']['data'], $data['info']['copyright']['attribs']);
|
||||
}
|
||||
|
||||
// Feed Image
|
||||
if (!empty($data['info']['image']['title']['data']))
|
||||
{
|
||||
$this->info['image']['title'] = $this->sanitize($data['info']['image']['title']['data'], $data['info']['image']['title']['attribs']);
|
||||
}
|
||||
if (!empty($data['info']['image']['url']['data']))
|
||||
{
|
||||
$this->info['image']['url'] = $this->sanitize($data['info']['image']['url']['data'], $data['info']['image']['url']['attribs'], true);
|
||||
}
|
||||
if (!empty($data['info']['logo']['data']))
|
||||
{
|
||||
$this->info['image']['logo'] = $this->sanitize($data['info']['logo']['data'], $data['info']['logo']['attribs'], true);
|
||||
}
|
||||
if (!empty($data['info']['image']['link']['data']))
|
||||
{
|
||||
$this->info['image']['link'] = $this->sanitize($data['info']['image']['link']['data'], $data['info']['image']['link']['attribs'], true);
|
||||
}
|
||||
if (!empty($data['info']['image']['width']['data']))
|
||||
{
|
||||
$this->info['image']['width'] = $this->sanitize($data['info']['image']['width']['data'], $data['info']['image']['width']['attribs']);
|
||||
}
|
||||
if (!empty($data['info']['image']['height']['data']))
|
||||
{
|
||||
$this->info['image']['height'] = $this->sanitize($data['info']['image']['height']['data'], $data['info']['image']['height']['attribs']);
|
||||
}
|
||||
|
||||
// Items
|
||||
if (!empty($data['items']))
|
||||
{
|
||||
foreach ($data['items'] as $key => $item)
|
||||
{
|
||||
$newitem = null;
|
||||
|
||||
// Item level xml:base
|
||||
if (!empty($item['attribs']['XML:BASE']))
|
||||
{
|
||||
$this->item_xmlbase = SimplePie_Misc::absolutize_url($item['attribs']['XML:BASE'], $this->feed_xmlbase);
|
||||
}
|
||||
else if (!empty($item['attribs']['HTTP://WWW.W3.ORG/XML/1998/NAMESPACE:BASE']))
|
||||
{
|
||||
$this->item_xmlbase = SimplePie_Misc::absolutize_url($item['attribs']['HTTP://WWW.W3.ORG/XML/1998/NAMESPACE:BASE'], $this->feed_xmlbase);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->item_xmlbase = null;
|
||||
}
|
||||
|
||||
// Title
|
||||
if (!empty($item['title']['data'])) {
|
||||
$newitem['title'] = $this->sanitize($item['title']['data'], $item['title']['attribs']);
|
||||
}
|
||||
if (!empty($item['dc:title']['data']))
|
||||
{
|
||||
$newitem['dc:title'] = $this->sanitize($item['dc:title']['data'], $item['dc:title']['attribs']);
|
||||
}
|
||||
|
||||
// Description
|
||||
if (!empty($item['content']['data']))
|
||||
{
|
||||
$newitem['content'] = $this->sanitize($item['content']['data'], $item['content']['attribs']);
|
||||
}
|
||||
if (!empty($item['encoded']['data']))
|
||||
{
|
||||
$newitem['encoded'] = $this->sanitize($item['encoded']['data'], $item['encoded']['attribs']);
|
||||
}
|
||||
if (!empty($item['summary']['data']))
|
||||
{
|
||||
$newitem['summary'] = $this->sanitize($item['summary']['data'], $item['summary']['attribs']);
|
||||
}
|
||||
if (!empty($item['description']['data']))
|
||||
{
|
||||
$newitem['description'] = $this->sanitize($item['description']['data'], $item['description']['attribs'], false, true);
|
||||
}
|
||||
if (!empty($item['dc:description']['data']))
|
||||
{
|
||||
$newitem['dc:description'] = $this->sanitize($item['dc:description']['data'], $item['dc:description']['attribs']);
|
||||
}
|
||||
if (!empty($item['longdesc']['data']))
|
||||
{
|
||||
$newitem['longdesc'] = $this->sanitize($item['longdesc']['data'], $item['longdesc']['attribs']);
|
||||
}
|
||||
|
||||
// Link(s)
|
||||
if (!empty($item['link']))
|
||||
{
|
||||
foreach ($item['link'] as $link)
|
||||
{
|
||||
if (empty($link['attribs']['REL']))
|
||||
{
|
||||
$rel = 'alternate';
|
||||
}
|
||||
else
|
||||
{
|
||||
$rel = strtolower($link['attribs']['REL']);
|
||||
}
|
||||
if ($rel == 'enclosure')
|
||||
{
|
||||
$href = null;
|
||||
$type = null;
|
||||
$length = null;
|
||||
if (!empty($link['data']))
|
||||
{
|
||||
$href = $this->sanitize($link['data'], $link['attribs'], true);
|
||||
}
|
||||
else if (!empty($link['attribs']['HREF']))
|
||||
{
|
||||
$href = $this->sanitize($link['attribs']['HREF'], $link['attribs'], true);
|
||||
}
|
||||
if (!empty($link['attribs']['TYPE'])) {
|
||||
$type = $this->sanitize($link['attribs']['TYPE'], $link['attribs']);
|
||||
}
|
||||
if (!empty($link['attribs']['LENGTH'])) {
|
||||
$length = $this->sanitize($link['attribs']['LENGTH'], $link['attribs']);
|
||||
}
|
||||
if (!empty($href))
|
||||
{
|
||||
$newitem['link'][$rel][] = new $this->enclosure_class($href, $type, $length);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!empty($link['data']))
|
||||
{
|
||||
$newitem['link'][$rel][] = $this->sanitize($link['data'], $link['attribs'], true);
|
||||
}
|
||||
else if (!empty($link['attribs']['HREF']))
|
||||
{
|
||||
$newitem['link'][$rel][] = $this->sanitize($link['attribs']['HREF'], $link['attribs'], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enclosure(s)
|
||||
if (!empty($item['enclosure']))
|
||||
{
|
||||
foreach ($item['enclosure'] as $enclosure)
|
||||
{
|
||||
if (!empty($enclosure['attribs']['URL']))
|
||||
{
|
||||
$type = null;
|
||||
$length = null;
|
||||
$href = $this->sanitize($enclosure['attribs']['URL'], $enclosure['attribs'], true);
|
||||
if (!empty($enclosure['attribs']['TYPE']))
|
||||
{
|
||||
$type = $this->sanitize($enclosure['attribs']['TYPE'], $enclosure['attribs']);
|
||||
}
|
||||
if (!empty($enclosure['attribs']['LENGTH']))
|
||||
{
|
||||
$length = $this->sanitize($enclosure['attribs']['LENGTH'], $enclosure['attribs']);
|
||||
}
|
||||
$newitem['enclosures'][] = new $this->enclosure_class($href, $type, $length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ID
|
||||
if (!empty($item['guid']['data']))
|
||||
{
|
||||
if (!empty($item['guid']['attribs']['ISPERMALINK']) && strtolower($item['guid']['attribs']['ISPERMALINK']) == 'false')
|
||||
{
|
||||
$newitem['guid']['permalink'] = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$newitem['guid']['permalink'] = true;
|
||||
}
|
||||
$newitem['guid']['data'] = $this->sanitize($item['guid']['data'], $item['guid']['attribs']);
|
||||
}
|
||||
if (!empty($item['id']['data']))
|
||||
{
|
||||
$newitem['id'] = $this->sanitize($item['id']['data'], $item['id']['attribs']);
|
||||
}
|
||||
|
||||
// Date
|
||||
if (!empty($item['pubdate']['data']))
|
||||
{
|
||||
$newitem['pubdate'] = $this->parse_date($this->sanitize($item['pubdate']['data'], $item['pubdate']['attribs']));
|
||||
}
|
||||
if (!empty($item['dc:date']['data']))
|
||||
{
|
||||
$newitem['dc:date'] = $this->parse_date($this->sanitize($item['dc:date']['data'], $item['dc:date']['attribs']));
|
||||
}
|
||||
if (!empty($item['issued']['data']))
|
||||
{
|
||||
$newitem['issued'] = $this->parse_date($this->sanitize($item['issued']['data'], $item['issued']['attribs']));
|
||||
}
|
||||
if (!empty($item['published']['data']))
|
||||
{
|
||||
$newitem['published'] = $this->parse_date($this->sanitize($item['published']['data'], $item['published']['attribs']));
|
||||
}
|
||||
if (!empty($item['modified']['data']))
|
||||
{
|
||||
$newitem['modified'] = $this->parse_date($this->sanitize($item['modified']['data'], $item['modified']['attribs']));
|
||||
}
|
||||
if (!empty($item['updated']['data']))
|
||||
{
|
||||
$newitem['updated'] = $this->parse_date($this->sanitize($item['updated']['data'], $item['updated']['attribs']));
|
||||
}
|
||||
|
||||
// Categories
|
||||
if (!empty($item['category']))
|
||||
{
|
||||
foreach ($item['category'] as $category)
|
||||
{
|
||||
if (!empty($category['data']))
|
||||
{
|
||||
$newitem['category'][] = $this->sanitize($category['data'], $category['attribs']);
|
||||
}
|
||||
else if (!empty($category['attribs']['TERM']))
|
||||
{
|
||||
$newitem['term'][] = $this->sanitize($category['attribs']['TERM'], $category['attribs']);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($item['subject']))
|
||||
{
|
||||
foreach ($item['subject'] as $category)
|
||||
{
|
||||
if (!empty($category['data']))
|
||||
{
|
||||
$newitem['subject'][] = $this->sanitize($category['data'], $category['attribs']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Author
|
||||
if (!empty($item['creator']))
|
||||
{
|
||||
foreach ($item['creator'] as $creator)
|
||||
{
|
||||
if (!empty($creator['data']))
|
||||
{
|
||||
$newitem['creator'][] = new $this->author_class($this->sanitize($creator['data'], $creator['attribs']), null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($item['author']))
|
||||
{
|
||||
foreach ($item['author'] as $author)
|
||||
{
|
||||
$name = null;
|
||||
$link = null;
|
||||
$email = null;
|
||||
if (!empty($author['rss']))
|
||||
{
|
||||
$sane = $this->sanitize($author['rss']['data'], $author['rss']['attribs']);
|
||||
if (preg_match('/(.*)@(.*) \((.*)\)/msiU', $sane, $matches)) {
|
||||
$name = trim($matches[3]);
|
||||
$email = trim("$matches[1]@$matches[2]");
|
||||
} else {
|
||||
$email = $sane;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!empty($author['name']))
|
||||
{
|
||||
$name = $this->sanitize($author['name']['data'], $author['name']['attribs']);
|
||||
}
|
||||
if (!empty($author['url']))
|
||||
{
|
||||
$link = $this->sanitize($author['url']['data'], $author['url']['attribs'], true);
|
||||
}
|
||||
else if (!empty($author['uri']))
|
||||
{
|
||||
$link = $this->sanitize($author['uri']['data'], $author['uri']['attribs'], true);
|
||||
}
|
||||
else if (!empty($author['homepage']))
|
||||
{
|
||||
$link = $this->sanitize($author['homepage']['data'], $author['homepage']['attribs'], true);
|
||||
}
|
||||
if (!empty($author['email'])) {
|
||||
$email = $this->sanitize($author['email']['data'], $author['email']['attribs']);
|
||||
}
|
||||
}
|
||||
$newitem['author'][] = new $this->author_class($name, $link, $email);
|
||||
}
|
||||
}
|
||||
unset($data['items'][$key]);
|
||||
$this->items[] = new $this->item_class($newitem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sanitize($data, $attribs, $is_url = false, $force_decode = false)
|
||||
{
|
||||
$this->attribs = $attribs;
|
||||
if (isset($this->feedinfo['type']) && $this->feedinfo['type'] == 'Atom')
|
||||
{
|
||||
if ((!empty($attribs['MODE']) && $attribs['MODE'] == 'base64') || (!empty($attribs['TYPE']) && $attribs['TYPE'] == 'application/octet-stream'))
|
||||
{
|
||||
$data = trim($data);
|
||||
$data = base64_decode($data);
|
||||
}
|
||||
else if ((!empty($attribs['MODE']) && $attribs['MODE'] == 'escaped' || !empty($attribs['TYPE']) && ($attribs['TYPE'] == 'html' || $attribs['TYPE'] == 'text/html')))
|
||||
{
|
||||
$data = $this->entities_decode($data);
|
||||
}
|
||||
if (!empty($attribs['TYPE']) && ($attribs['TYPE'] == 'xhtml' || $attribs['TYPE'] == 'application/xhtml+xml'))
|
||||
{
|
||||
if ($this->remove_div)
|
||||
{
|
||||
$data = preg_replace('/<div( .*)?>/msiU', '', strrev(preg_replace('/>vid\/</i', '', strrev($data), 1)), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$data = preg_replace('/<div( .*)?>/msiU', '<div>', $data, 1);
|
||||
}
|
||||
$data = $this->convert_entities($data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$data = $this->convert_entities($data);
|
||||
}
|
||||
if ($force_decode)
|
||||
{
|
||||
$data = $this->entities_decode($data);
|
||||
}
|
||||
$data = trim($data);
|
||||
$data = preg_replace('/<\!--([^-]|-[^-])*-->/msiU', '', $data);
|
||||
|
||||
// If Strip Ads is enabled, strip them.
|
||||
if ($this->strip_ads)
|
||||
{
|
||||
$data = preg_replace('/<a (.*)href=(.*)click\.phdo\?s=(.*)<\/a>/msiU', '', $data); // Pheedo links (tested with Dooce.com)
|
||||
$data = preg_replace('/<p(.*)>(.*)<a href="http:\/\/ad.doubleclick.net\/jump\/(.*)<\/p>/msiU', '', $data); // Doubleclick links (tested with InfoWorld.com)
|
||||
$data = preg_replace('/<p><map (.*)name=(.*)google_ad_map(.*)<\/p>/msiU', '', $data); // Google AdSense for Feeds (tested with tuaw.com).
|
||||
// Feedflare, from Feedburner
|
||||
}
|
||||
|
||||
// Replace H1, H2, and H3 tags with the less important H4 tags.
|
||||
// This is because on a site, the more important headers might make sense,
|
||||
// but it most likely doesn't fit in the context of RSS-in-a-webpage.
|
||||
if ($this->replace_headers)
|
||||
{
|
||||
$data = preg_replace('/<h[1-3]((\s*((\w+:)?\w+)\s*=\s*("([^"]*)"|\'([^\']*)\'|(.*)))*)\s*>/msiU', '<h4\\1>', $data);
|
||||
$data = preg_replace('/<\/h[1-3]>/i', '</h4>', $data);
|
||||
}
|
||||
|
||||
if ($is_url)
|
||||
{
|
||||
$data = $this->replace_urls($data, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$data = preg_replace_callback('/<(\S+)((\s*((\w+:)?\w+)\s*=\s*("([^"]*)"|\'([^\']*)\'|(.*)))*)\s*(\/>|>(.*)<\/\S+>)/msiU', array(&$this, 'replace_urls'), $data);
|
||||
}
|
||||
|
||||
// If Bypass Image Hotlink is enabled, rewrite all the image tags.
|
||||
if ($this->bypass_image_hotlink)
|
||||
{
|
||||
$images = SimplePie_Misc::get_element('img', $data);
|
||||
foreach ($images as $img)
|
||||
{
|
||||
if (!empty($img['attribs']['SRC']['data']))
|
||||
{
|
||||
$pre = '';
|
||||
if ($this->bypass_image_hotlink_page)
|
||||
{
|
||||
$pre = $this->bypass_image_hotlink_page;
|
||||
}
|
||||
$pre .= "?$this->bypass_image_hotlink=";
|
||||
$img['attribs']['SRC']['data'] = $pre . rawurlencode(strtr($img['attribs']['SRC']['data'], array_flip(get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES))));
|
||||
$data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Strip out HTML tags and attributes that might cause various security problems.
|
||||
// Based on recommendations by Mark Pilgrim at:
|
||||
// http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
|
||||
if ($this->strip_htmltags)
|
||||
{
|
||||
foreach ($this->strip_htmltags as $tag)
|
||||
{
|
||||
$data = preg_replace_callback("/<($tag)((\s*((\w+:)?\w+)(\s*=\s*(\"([^\"]*)\"|'([^']*)'|(.*)))?)*)\s*(\/>|>(.*)<\/($tag)((\s*((\w+:)?\w+)(\s*=\s*(\"([^\"]*)\"|'([^']*)'|(.*)))?)*)\s*>)/msiU", array(&$this, 'do_strip_htmltags'), $data);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->strip_attributes)
|
||||
{
|
||||
foreach ($this->strip_attributes as $attrib)
|
||||
{
|
||||
$data = preg_replace('/ '. trim($attrib) .'=("|")(\w|\s|=|-|:|;|\/|\.|\?|&|,|#|!|\(|\)|\'|'|<|>|\+|{|})*("|")/i', '', $data);
|
||||
$data = preg_replace('/ '. trim($attrib) .'=(\'|')(\w|\s|=|-|:|;|\/|\.|\?|&|,|#|!|\(|\)|"|"|<|>|\+|{|})*(\'|')/i', '', $data);
|
||||
$data = preg_replace('/ '. trim($attrib) .'=(\w|\s|=|-|:|;|\/|\.|\?|&|,|#|!|\(|\)|\+|{|})*/i', '', $data);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert encoding
|
||||
$data = SimplePie_Misc::change_encoding($data, $this->input_encoding, $this->output_encoding);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
function do_strip_htmltags($match)
|
||||
{
|
||||
if ($this->encode_instead_of_strip)
|
||||
{
|
||||
if (isset($match[12]) && !in_array(strtolower($match[1]), array('script', 'style')))
|
||||
{
|
||||
return "<$match[1]$match[2]>$match[12]</$match[1]>";
|
||||
}
|
||||
else if (isset($match[12]))
|
||||
{
|
||||
return "<$match[1]$match[2]></$match[1]>";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "<$match[1]$match[2]/>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($match[12]) && !in_array(strtolower($match[1]), array('script', 'style')))
|
||||
{
|
||||
return $match[12];
|
||||
}
|
||||
else
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function replace_urls($data, $raw_url = false)
|
||||
{
|
||||
if (!empty($this->attribs['XML:BASE']))
|
||||
{
|
||||
$xmlbase = $attribs['XML:BASE'];
|
||||
}
|
||||
else if (!empty($this->attribs['HTTP://WWW.W3.ORG/XML/1998/NAMESPACE:BASE']))
|
||||
{
|
||||
$xmlbase = $this->attribs['HTTP://WWW.W3.ORG/XML/1998/NAMESPACE:BASE'];
|
||||
}
|
||||
if (!empty($xmlbase))
|
||||
{
|
||||
if (!empty($this->item_xmlbase))
|
||||
{
|
||||
$xmlbase = SimplePie_Misc::absolutize_url($xmlbase, $this->item_xmlbase);
|
||||
}
|
||||
else
|
||||
{
|
||||
$xmlbase = SimplePie_Misc::absolutize_url($xmlbase, $this->feed_xmlbase);
|
||||
}
|
||||
}
|
||||
else if (!empty($this->item_xmlbase))
|
||||
{
|
||||
$xmlbase = $this->item_xmlbase;
|
||||
}
|
||||
else
|
||||
{
|
||||
$xmlbase = $this->feed_xmlbase;
|
||||
}
|
||||
|
||||
if ($raw_url)
|
||||
{
|
||||
return SimplePie_Misc::absolutize_url($data, $xmlbase);
|
||||
}
|
||||
else
|
||||
{
|
||||
$attributes = array(
|
||||
'background',
|
||||
'href',
|
||||
'src',
|
||||
'longdesc',
|
||||
'usemap',
|
||||
'codebase',
|
||||
'data',
|
||||
'classid',
|
||||
'cite',
|
||||
'action',
|
||||
'profile',
|
||||
'for'
|
||||
);
|
||||
foreach ($attributes as $attribute)
|
||||
{
|
||||
if (preg_match("/$attribute='(.*)'/siU", $data[0], $attrib) || preg_match("/$attribute=\"(.*)\"/siU", $data[0], $attrib) || preg_match("/$attribute=(.*)[ |\/|>]/siU", $data[0], $attrib))
|
||||
{
|
||||
$new_tag = str_replace($attrib[1], SimplePie_Misc::absolutize_url($attrib[1], $xmlbase), $attrib[0]);
|
||||
$data[0] = str_replace($attrib[0], $new_tag, $data[0]);
|
||||
}
|
||||
}
|
||||
return $data[0];
|
||||
}
|
||||
}
|
||||
|
||||
function entities_decode($data)
|
||||
{
|
||||
return preg_replace_callback('/&(#)?(x)?([0-9a-z]+);/mi', array(&$this, 'do_entites_decode'), $data);
|
||||
}
|
||||
|
||||
function do_entites_decode($data)
|
||||
{
|
||||
if (isset($this->cached_entities[$data[0]]))
|
||||
{
|
||||
return $this->cached_entities[$data[0]];
|
||||
}
|
||||
else
|
||||
{
|
||||
$return = SimplePie_Misc::change_encoding(html_entity_decode($data[0], ENT_QUOTES), 'ISO-8859-1', $this->input_encoding);
|
||||
if ($return == $data[0])
|
||||
{
|
||||
$return = SimplePie_Misc::change_encoding(preg_replace_callback('/&#([x]?[0-9a-f]+);/mi', array(&$this, 'replace_num_entity'), $data[0]), 'UTF-8', $this->input_encoding);
|
||||
}
|
||||
$this->cached_entities[$data[0]] = $return;
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
||||
function convert_entities($data)
|
||||
{
|
||||
return preg_replace_callback('/&#(x)?([0-9a-z]+);/mi', array(&$this, 'do_convert_entities'), $data);
|
||||
}
|
||||
|
||||
function do_convert_entities($data)
|
||||
{
|
||||
if (isset($this->cache_convert_entities[$data[0]]))
|
||||
{
|
||||
return $this->cache_convert_entities[$data[0]];
|
||||
}
|
||||
else if (isset($this->cached_entities[$data[0]]))
|
||||
{
|
||||
$return = htmlentities($this->cached_entities[$data[0]], ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
else
|
||||
{
|
||||
$return = htmlentities(preg_replace_callback('/&#([x]?[0-9a-f]+);/mi', array(&$this, 'replace_num_entity'), $data[0]), ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
$this->cache_convert_entities[$data[0]] = $return;
|
||||
return $return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Escape numeric entities
|
||||
* From a PHP Manual note (on html_entity_decode())
|
||||
* Copyright (c) 2005 by "php dot net at c dash ovidiu dot tk",
|
||||
* "emilianomartinezluque at yahoo dot com" and "hurricane at cyberworldz dot org".
|
||||
*
|
||||
* This material may be distributed only subject to the terms and conditions set forth in
|
||||
* the Open Publication License, v1.0 or later (the latest version is presently available at
|
||||
* http://www.opencontent.org/openpub/).
|
||||
*/
|
||||
function replace_num_entity($ord)
|
||||
{
|
||||
$ord = $ord[1];
|
||||
if (preg_match('/^x([0-9a-f]+)$/i', $ord, $match))
|
||||
{
|
||||
$ord = hexdec($match[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$ord = intval($ord);
|
||||
}
|
||||
|
||||
$no_bytes = 0;
|
||||
$byte = array();
|
||||
if ($ord < 128)
|
||||
{
|
||||
return chr($ord);
|
||||
}
|
||||
if ($ord < 2048)
|
||||
{
|
||||
$no_bytes = 2;
|
||||
}
|
||||
else if ($ord < 65536)
|
||||
{
|
||||
$no_bytes = 3;
|
||||
}
|
||||
else if ($ord < 1114112)
|
||||
{
|
||||
$no_bytes = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch ($no_bytes)
|
||||
{
|
||||
case 2:
|
||||
$prefix = array(31, 192);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$prefix = array(15, 224);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
$prefix = array(7, 240);
|
||||
break;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $no_bytes; $i++)
|
||||
{
|
||||
$byte[$no_bytes-$i-1] = (($ord & (63 * pow(2,6*$i))) / pow(2,6*$i)) & 63 | 128;
|
||||
}
|
||||
$byte[0] = ($byte[0] & $prefix[0]) | $prefix[1];
|
||||
|
||||
$ret = '';
|
||||
for ($i = 0; $i < $no_bytes; $i++)
|
||||
{
|
||||
$ret .= chr($byte[$i]);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function parse_date($date)
|
||||
{
|
||||
$military_timezone = array('A' => '-0100', 'B' => '-0200', 'C' => '-0300', 'D' => '-0400', 'E' => '-0500', 'F' => '-0600', 'G' => '-0700', 'H' => '-0800', 'I' => '-0900', 'K' => '-1000', 'L' => '-1100', 'M' => '-1200', 'N' => '+0100', 'O' => '+0200', 'P' => '+0300', 'Q' => '+0400', 'R' => '+0500', 'S' => '+0600', 'T' => '+0700', 'U' => '+0800', 'V' => '+0900', 'W' => '+1000', 'X' => '+1100', 'Y' => '+1200', 'Z' => '-0000');
|
||||
$north_american_timezone = array('GMT' => '-0000', 'EST' => '-0500', 'EDT' => '-0400', 'CST' => '-0600', 'CDT' => '-0500', 'MST' => '-0700', 'MDT' => '-0600', 'PST' => '-0800', 'PDT' => '-0700');
|
||||
if (preg_match('/([0-9]{2,4})-?([0-9]{2})-?([0-9]{2})T([0-9]{2}):?([0-9]{2})(:?([0-9]{2}(\.[0-9]*)?))?(UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[a-z]|(\\+|-)[0-9]{4}|(\\+|-)[0-9]{2}:[0-9]{2})?/i', $date, $matches))
|
||||
{
|
||||
if (!isset($matches[7]))
|
||||
{
|
||||
$matches[7] = '';
|
||||
}
|
||||
if (!isset($matches[9]))
|
||||
{
|
||||
$matches[9] = '';
|
||||
}
|
||||
$matches[7] = str_pad(round($matches[7]), 2, '0', STR_PAD_LEFT);
|
||||
switch (strlen($matches[9]))
|
||||
{
|
||||
case 0:
|
||||
$timezone = '';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
$timezone = $military_timezone[strtoupper($matches[9])];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$timezone = '-0000';
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$timezone = $north_american_timezone[strtoupper($matches[9])];
|
||||
break;
|
||||
|
||||
case 5:
|
||||
$timezone = $matches[9];
|
||||
break;
|
||||
|
||||
case 6:
|
||||
$timezone = substr_replace($matches[9], '', 3, 1);
|
||||
break;
|
||||
}
|
||||
$date = strtotime("$matches[1]-$matches[2]-$matches[3] $matches[4]:$matches[5]:$matches[7] $timezone");
|
||||
}
|
||||
else if (preg_match('/([0-9]{1,2})\s*(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s*([0-9]{2}|[0-9]{4})\s*([0-9]{2}):([0-9]{2})(:([0-9]{2}(\.[0-9]*)?))?\s*(UT|GMT|EST|EDT|CST|CDT|MST|MDT|PST|PDT|[a-z]|(\\+|-)[0-9]{4}|(\\+|-)[0-9]{2}:[0-9]{2})?/i', $date, $matches))
|
||||
{
|
||||
$three_month = array('Jan' => 1, 'Feb' => 2, 'Mar' => 3, 'Apr' => 4, 'May' => 5, 'Jun' => 6, 'Jul' => 7, 'Aug' => 8, 'Sep' => 9, 'Oct' => 10, 'Nov' => 11, 'Dec' => 12);
|
||||
$month = $three_month[$matches[2]];
|
||||
if (strlen($matches[3]) == 2)
|
||||
{
|
||||
$year = ($matches[3] < 70) ? "20$matches[3]" : "19$matches[3]";
|
||||
}
|
||||
else
|
||||
{
|
||||
$year = $matches[3];
|
||||
}
|
||||
if (!isset($matches[7]))
|
||||
{
|
||||
$matches[7] = '';
|
||||
}
|
||||
if (!isset($matches[9]))
|
||||
{
|
||||
$matches[9] = '';
|
||||
}
|
||||
$second = str_pad(round($matches[7]), 2, '0', STR_PAD_LEFT);
|
||||
switch (strlen($matches[9]))
|
||||
{
|
||||
case 0:
|
||||
$timezone = '';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
$timezone = $military_timezone[strtoupper($matches[9])];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$timezone = '-0000';
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$timezone = $north_american_timezone[strtoupper($matches[9])];
|
||||
break;
|
||||
|
||||
case 5:
|
||||
$timezone = $matches[9];
|
||||
break;
|
||||
|
||||
case 6:
|
||||
$timezone = substr_replace($matches[9], '', 3, 1);
|
||||
break;
|
||||
}
|
||||
$date = strtotime("$year-$month-$matches[1] $matches[4]:$matches[5]:$second $timezone");
|
||||
}
|
||||
else
|
||||
{
|
||||
$date = strtotime($date);
|
||||
}
|
||||
if ($date !== false && $date !== -1)
|
||||
{
|
||||
return $date;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
502
thirdparty/simpletest/LICENSE
vendored
Normal file
502
thirdparty/simpletest/LICENSE
vendored
Normal file
@ -0,0 +1,502 @@
|
||||
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!
|
1
thirdparty/simpletest/VERSION
vendored
Normal file
1
thirdparty/simpletest/VERSION
vendored
Normal file
@ -0,0 +1 @@
|
||||
1.0.1
|
0
thirdparty/simpletest/_manifest_exclude
vendored
Normal file
0
thirdparty/simpletest/_manifest_exclude
vendored
Normal file
173
thirdparty/simpletest/compatibility.php
vendored
Normal file
173
thirdparty/simpletest/compatibility.php
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
<?php
|
||||
/**
|
||||
* base include file for SimpleTest
|
||||
* @package SimpleTest
|
||||
* @version $Id: compatibility.php 1723 2008-04-08 00:34:10Z lastcraft $
|
||||
*/
|
||||
|
||||
/**
|
||||
* Static methods for compatibility between different
|
||||
* PHP versions.
|
||||
* @package SimpleTest
|
||||
*/
|
||||
class SimpleTestCompatibility {
|
||||
|
||||
/**
|
||||
* Creates a copy whether in PHP5 or PHP4.
|
||||
* @param object $object Thing to copy.
|
||||
* @return object A copy.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function copy($object) {
|
||||
if (version_compare(phpversion(), '5') >= 0) {
|
||||
eval('$copy = clone $object;');
|
||||
return $copy;
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identity test. Drops back to equality + types for PHP5
|
||||
* objects as the === operator counts as the
|
||||
* stronger reference constraint.
|
||||
* @param mixed $first Test subject.
|
||||
* @param mixed $second Comparison object.
|
||||
* @return boolean True if identical.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function isIdentical($first, $second) {
|
||||
if (version_compare(phpversion(), '5') >= 0) {
|
||||
return SimpleTestCompatibility::_isIdenticalType($first, $second);
|
||||
}
|
||||
if ($first != $second) {
|
||||
return false;
|
||||
}
|
||||
return ($first === $second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive type test.
|
||||
* @param mixed $first Test subject.
|
||||
* @param mixed $second Comparison object.
|
||||
* @return boolean True if same type.
|
||||
* @access private
|
||||
* @static
|
||||
*/
|
||||
function _isIdenticalType($first, $second) {
|
||||
if (gettype($first) != gettype($second)) {
|
||||
return false;
|
||||
}
|
||||
if (is_object($first) && is_object($second)) {
|
||||
if (get_class($first) != get_class($second)) {
|
||||
return false;
|
||||
}
|
||||
return SimpleTestCompatibility::_isArrayOfIdenticalTypes(
|
||||
get_object_vars($first),
|
||||
get_object_vars($second));
|
||||
}
|
||||
if (is_array($first) && is_array($second)) {
|
||||
return SimpleTestCompatibility::_isArrayOfIdenticalTypes($first, $second);
|
||||
}
|
||||
if ($first !== $second) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive type test for each element of an array.
|
||||
* @param mixed $first Test subject.
|
||||
* @param mixed $second Comparison object.
|
||||
* @return boolean True if identical.
|
||||
* @access private
|
||||
* @static
|
||||
*/
|
||||
function _isArrayOfIdenticalTypes($first, $second) {
|
||||
if (array_keys($first) != array_keys($second)) {
|
||||
return false;
|
||||
}
|
||||
foreach (array_keys($first) as $key) {
|
||||
$is_identical = SimpleTestCompatibility::_isIdenticalType(
|
||||
$first[$key],
|
||||
$second[$key]);
|
||||
if (! $is_identical) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for two variables being aliases.
|
||||
* @param mixed $first Test subject.
|
||||
* @param mixed $second Comparison object.
|
||||
* @return boolean True if same.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function isReference(&$first, &$second) {
|
||||
if (version_compare(phpversion(), '5', '>=') && is_object($first)) {
|
||||
return ($first === $second);
|
||||
}
|
||||
if (is_object($first) && is_object($second)) {
|
||||
$id = uniqid("test");
|
||||
$first->$id = true;
|
||||
$is_ref = isset($second->$id);
|
||||
unset($first->$id);
|
||||
return $is_ref;
|
||||
}
|
||||
$temp = $first;
|
||||
$first = uniqid("test");
|
||||
$is_ref = ($first === $second);
|
||||
$first = $temp;
|
||||
return $is_ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if an object is a member of a
|
||||
* class hiearchy.
|
||||
* @param object $object Object to test.
|
||||
* @param string $class Root name of hiearchy.
|
||||
* @return boolean True if class in hiearchy.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function isA($object, $class) {
|
||||
if (version_compare(phpversion(), '5') >= 0) {
|
||||
if (! class_exists($class, false)) {
|
||||
if (function_exists('interface_exists')) {
|
||||
if (! interface_exists($class, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
eval("\$is_a = \$object instanceof $class;");
|
||||
return $is_a;
|
||||
}
|
||||
if (function_exists('is_a')) {
|
||||
return is_a($object, $class);
|
||||
}
|
||||
return ((strtolower($class) == get_class($object))
|
||||
or (is_subclass_of($object, $class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a socket timeout for each chunk.
|
||||
* @param resource $handle Socket handle.
|
||||
* @param integer $timeout Limit in seconds.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function setTimeout($handle, $timeout) {
|
||||
if (function_exists('stream_set_timeout')) {
|
||||
stream_set_timeout($handle, $timeout, 0);
|
||||
} elseif (function_exists('socket_set_timeout')) {
|
||||
socket_set_timeout($handle, $timeout, 0);
|
||||
} elseif (function_exists('set_socket_timeout')) {
|
||||
set_socket_timeout($handle, $timeout, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
380
thirdparty/simpletest/cookies.php
vendored
Normal file
380
thirdparty/simpletest/cookies.php
vendored
Normal file
@ -0,0 +1,380 @@
|
||||
<?php
|
||||
/**
|
||||
* Base include file for SimpleTest
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
* @version $Id: cookies.php 1723 2008-04-08 00:34:10Z lastcraft $
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
* include other SimpleTest class files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/url.php');
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Cookie data holder. Cookie rules are full of pretty
|
||||
* arbitary stuff. I have used...
|
||||
* http://wp.netscape.com/newsref/std/cookie_spec.html
|
||||
* http://www.cookiecentral.com/faq/
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleCookie {
|
||||
var $_host;
|
||||
var $_name;
|
||||
var $_value;
|
||||
var $_path;
|
||||
var $_expiry;
|
||||
var $_is_secure;
|
||||
|
||||
/**
|
||||
* Constructor. Sets the stored values.
|
||||
* @param string $name Cookie key.
|
||||
* @param string $value Value of cookie.
|
||||
* @param string $path Cookie path if not host wide.
|
||||
* @param string $expiry Expiry date as string.
|
||||
* @param boolean $is_secure Currently ignored.
|
||||
*/
|
||||
function SimpleCookie($name, $value = false, $path = false, $expiry = false, $is_secure = false) {
|
||||
$this->_host = false;
|
||||
$this->_name = $name;
|
||||
$this->_value = $value;
|
||||
$this->_path = ($path ? $this->_fixPath($path) : "/");
|
||||
$this->_expiry = false;
|
||||
if (is_string($expiry)) {
|
||||
$this->_expiry = strtotime($expiry);
|
||||
} elseif (is_integer($expiry)) {
|
||||
$this->_expiry = $expiry;
|
||||
}
|
||||
$this->_is_secure = $is_secure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the host. The cookie rules determine
|
||||
* that the first two parts are taken for
|
||||
* certain TLDs and three for others. If the
|
||||
* new host does not match these rules then the
|
||||
* call will fail.
|
||||
* @param string $host New hostname.
|
||||
* @return boolean True if hostname is valid.
|
||||
* @access public
|
||||
*/
|
||||
function setHost($host) {
|
||||
if ($host = $this->_truncateHost($host)) {
|
||||
$this->_host = $host;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the truncated host to which this
|
||||
* cookie applies.
|
||||
* @return string Truncated hostname.
|
||||
* @access public
|
||||
*/
|
||||
function getHost() {
|
||||
return $this->_host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for a cookie being valid for a host name.
|
||||
* @param string $host Host to test against.
|
||||
* @return boolean True if the cookie would be valid
|
||||
* here.
|
||||
*/
|
||||
function isValidHost($host) {
|
||||
return ($this->_truncateHost($host) === $this->getHost());
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts just the domain part that determines a
|
||||
* cookie's host validity.
|
||||
* @param string $host Host name to truncate.
|
||||
* @return string Domain or false on a bad host.
|
||||
* @access private
|
||||
*/
|
||||
function _truncateHost($host) {
|
||||
$tlds = SimpleUrl::getAllTopLevelDomains();
|
||||
if (preg_match('/[a-z\-]+\.(' . $tlds . ')$/i', $host, $matches)) {
|
||||
return $matches[0];
|
||||
} elseif (preg_match('/[a-z\-]+\.[a-z\-]+\.[a-z\-]+$/i', $host, $matches)) {
|
||||
return $matches[0];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for name.
|
||||
* @return string Cookie key.
|
||||
* @access public
|
||||
*/
|
||||
function getName() {
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for value. A deleted cookie will
|
||||
* have an empty string for this.
|
||||
* @return string Cookie value.
|
||||
* @access public
|
||||
*/
|
||||
function getValue() {
|
||||
return $this->_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for path.
|
||||
* @return string Valid cookie path.
|
||||
* @access public
|
||||
*/
|
||||
function getPath() {
|
||||
return $this->_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a path to see if the cookie applies
|
||||
* there. The test path must be longer or
|
||||
* equal to the cookie path.
|
||||
* @param string $path Path to test against.
|
||||
* @return boolean True if cookie valid here.
|
||||
* @access public
|
||||
*/
|
||||
function isValidPath($path) {
|
||||
return (strncmp(
|
||||
$this->_fixPath($path),
|
||||
$this->getPath(),
|
||||
strlen($this->getPath())) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for expiry.
|
||||
* @return string Expiry string.
|
||||
* @access public
|
||||
*/
|
||||
function getExpiry() {
|
||||
if (! $this->_expiry) {
|
||||
return false;
|
||||
}
|
||||
return gmdate("D, d M Y H:i:s", $this->_expiry) . " GMT";
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if cookie is expired against
|
||||
* the cookie format time or timestamp.
|
||||
* Will give true for a session cookie.
|
||||
* @param integer/string $now Time to test against. Result
|
||||
* will be false if this time
|
||||
* is later than the cookie expiry.
|
||||
* Can be either a timestamp integer
|
||||
* or a cookie format date.
|
||||
* @access public
|
||||
*/
|
||||
function isExpired($now) {
|
||||
if (! $this->_expiry) {
|
||||
return true;
|
||||
}
|
||||
if (is_string($now)) {
|
||||
$now = strtotime($now);
|
||||
}
|
||||
return ($this->_expiry < $now);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ages the cookie by the specified number of
|
||||
* seconds.
|
||||
* @param integer $interval In seconds.
|
||||
* @public
|
||||
*/
|
||||
function agePrematurely($interval) {
|
||||
if ($this->_expiry) {
|
||||
$this->_expiry -= $interval;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the secure flag.
|
||||
* @return boolean True if cookie needs SSL.
|
||||
* @access public
|
||||
*/
|
||||
function isSecure() {
|
||||
return $this->_is_secure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a trailing and leading slash to the path
|
||||
* if missing.
|
||||
* @param string $path Path to fix.
|
||||
* @access private
|
||||
*/
|
||||
function _fixPath($path) {
|
||||
if (substr($path, 0, 1) != '/') {
|
||||
$path = '/' . $path;
|
||||
}
|
||||
if (substr($path, -1, 1) != '/') {
|
||||
$path .= '/';
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Repository for cookies. This stuff is a
|
||||
* tiny bit browser dependent.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleCookieJar {
|
||||
var $_cookies;
|
||||
|
||||
/**
|
||||
* Constructor. Jar starts empty.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleCookieJar() {
|
||||
$this->_cookies = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes expired and temporary cookies as if
|
||||
* the browser was closed and re-opened.
|
||||
* @param string/integer $now Time to test expiry against.
|
||||
* @access public
|
||||
*/
|
||||
function restartSession($date = false) {
|
||||
$surviving_cookies = array();
|
||||
for ($i = 0; $i < count($this->_cookies); $i++) {
|
||||
if (! $this->_cookies[$i]->getValue()) {
|
||||
continue;
|
||||
}
|
||||
if (! $this->_cookies[$i]->getExpiry()) {
|
||||
continue;
|
||||
}
|
||||
if ($date && $this->_cookies[$i]->isExpired($date)) {
|
||||
continue;
|
||||
}
|
||||
$surviving_cookies[] = $this->_cookies[$i];
|
||||
}
|
||||
$this->_cookies = $surviving_cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ages all cookies in the cookie jar.
|
||||
* @param integer $interval The old session is moved
|
||||
* into the past by this number
|
||||
* of seconds. Cookies now over
|
||||
* age will be removed.
|
||||
* @access public
|
||||
*/
|
||||
function agePrematurely($interval) {
|
||||
for ($i = 0; $i < count($this->_cookies); $i++) {
|
||||
$this->_cookies[$i]->agePrematurely($interval);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an additional cookie. If a cookie has
|
||||
* the same name and path it is replaced.
|
||||
* @param string $name Cookie key.
|
||||
* @param string $value Value of cookie.
|
||||
* @param string $host Host upon which the cookie is valid.
|
||||
* @param string $path Cookie path if not host wide.
|
||||
* @param string $expiry Expiry date.
|
||||
* @access public
|
||||
*/
|
||||
function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
|
||||
$cookie = new SimpleCookie($name, $value, $path, $expiry);
|
||||
if ($host) {
|
||||
$cookie->setHost($host);
|
||||
}
|
||||
$this->_cookies[$this->_findFirstMatch($cookie)] = $cookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a matching cookie to write over or the
|
||||
* first empty slot if none.
|
||||
* @param SimpleCookie $cookie Cookie to write into jar.
|
||||
* @return integer Available slot.
|
||||
* @access private
|
||||
*/
|
||||
function _findFirstMatch($cookie) {
|
||||
for ($i = 0; $i < count($this->_cookies); $i++) {
|
||||
$is_match = $this->_isMatch(
|
||||
$cookie,
|
||||
$this->_cookies[$i]->getHost(),
|
||||
$this->_cookies[$i]->getPath(),
|
||||
$this->_cookies[$i]->getName());
|
||||
if ($is_match) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
return count($this->_cookies);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the most specific cookie value from the
|
||||
* browser cookies. Looks for the longest path that
|
||||
* matches.
|
||||
* @param string $host Host to search.
|
||||
* @param string $path Applicable path.
|
||||
* @param string $name Name of cookie to read.
|
||||
* @return string False if not present, else the
|
||||
* value as a string.
|
||||
* @access public
|
||||
*/
|
||||
function getCookieValue($host, $path, $name) {
|
||||
$longest_path = '';
|
||||
foreach ($this->_cookies as $cookie) {
|
||||
if ($this->_isMatch($cookie, $host, $path, $name)) {
|
||||
if (strlen($cookie->getPath()) > strlen($longest_path)) {
|
||||
$value = $cookie->getValue();
|
||||
$longest_path = $cookie->getPath();
|
||||
}
|
||||
}
|
||||
}
|
||||
return (isset($value) ? $value : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests cookie for matching against search
|
||||
* criteria.
|
||||
* @param SimpleTest $cookie Cookie to test.
|
||||
* @param string $host Host must match.
|
||||
* @param string $path Cookie path must be shorter than
|
||||
* this path.
|
||||
* @param string $name Name must match.
|
||||
* @return boolean True if matched.
|
||||
* @access private
|
||||
*/
|
||||
function _isMatch($cookie, $host, $path, $name) {
|
||||
if ($cookie->getName() != $name) {
|
||||
return false;
|
||||
}
|
||||
if ($host && $cookie->getHost() && ! $cookie->isValidHost($host)) {
|
||||
return false;
|
||||
}
|
||||
if (! $cookie->isValidPath($path)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a URL to sift relevant cookies by host and
|
||||
* path. Results are list of strings of form "name=value".
|
||||
* @param SimpleUrl $url Url to select by.
|
||||
* @return array Valid name and value pairs.
|
||||
* @access public
|
||||
*/
|
||||
function selectAsPairs($url) {
|
||||
$pairs = array();
|
||||
foreach ($this->_cookies as $cookie) {
|
||||
if ($this->_isMatch($cookie, $url->getHost(), $url->getPath(), $cookie->getName())) {
|
||||
$pairs[] = $cookie->getName() . '=' . $cookie->getValue();
|
||||
}
|
||||
}
|
||||
return $pairs;
|
||||
}
|
||||
}
|
||||
?>
|
552
thirdparty/simpletest/encoding.php
vendored
Normal file
552
thirdparty/simpletest/encoding.php
vendored
Normal file
@ -0,0 +1,552 @@
|
||||
<?php
|
||||
/**
|
||||
* base include file for SimpleTest
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
* @version $Id: encoding.php 1723 2008-04-08 00:34:10Z lastcraft $
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
* include other SimpleTest class files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/socket.php');
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Single post parameter.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleEncodedPair {
|
||||
var $_key;
|
||||
var $_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 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 {
|
||||
var $_key;
|
||||
var $_content;
|
||||
var $_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 {
|
||||
var $_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) {
|
||||
if (is_array($query) and $this->hasMoreThanOneLevel($query)) {
|
||||
$query = $this->rewriteArrayWithMultipleLevels($query);
|
||||
}
|
||||
$this->SimpleEncoding($query);
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
var $_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;
|
||||
}
|
||||
}
|
||||
?>
|
355
thirdparty/simpletest/form.php
vendored
Normal file
355
thirdparty/simpletest/form.php
vendored
Normal file
@ -0,0 +1,355 @@
|
||||
<?php
|
||||
/**
|
||||
* Base include file for SimpleTest.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
* @version $Id: form.php 1672 2008-03-02 04:47:34Z edwardzyang $
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
* include SimpleTest files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/tag.php');
|
||||
require_once(dirname(__FILE__) . '/encoding.php');
|
||||
require_once(dirname(__FILE__) . '/selector.php');
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Form tag class to hold widget values.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleForm {
|
||||
var $_method;
|
||||
var $_action;
|
||||
var $_encoding;
|
||||
var $_default_target;
|
||||
var $_id;
|
||||
var $_buttons;
|
||||
var $_images;
|
||||
var $_widgets;
|
||||
var $_radios;
|
||||
var $_checkboxes;
|
||||
|
||||
/**
|
||||
* Starts with no held controls/widgets.
|
||||
* @param SimpleTag $tag Form tag to read.
|
||||
* @param SimplePage $page Holding page.
|
||||
*/
|
||||
function SimpleForm($tag, &$page) {
|
||||
$this->_method = $tag->getAttribute('method');
|
||||
$this->_action = $this->_createAction($tag->getAttribute('action'), $page);
|
||||
$this->_encoding = $this->_setEncodingClass($tag);
|
||||
$this->_default_target = false;
|
||||
$this->_id = $tag->getAttribute('id');
|
||||
$this->_buttons = array();
|
||||
$this->_images = array();
|
||||
$this->_widgets = array();
|
||||
$this->_radios = array();
|
||||
$this->_checkboxes = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the request packet to be sent by the form.
|
||||
* @param SimpleTag $tag Form tag to read.
|
||||
* @return string Packet class.
|
||||
* @access private
|
||||
*/
|
||||
function _setEncodingClass($tag) {
|
||||
if (strtolower($tag->getAttribute('method')) == 'post') {
|
||||
if (strtolower($tag->getAttribute('enctype')) == 'multipart/form-data') {
|
||||
return 'SimpleMultipartEncoding';
|
||||
}
|
||||
return 'SimplePostEncoding';
|
||||
}
|
||||
return 'SimpleGetEncoding';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frame target within a frameset.
|
||||
* @param string $frame Name of frame.
|
||||
* @access public
|
||||
*/
|
||||
function setDefaultTarget($frame) {
|
||||
$this->_default_target = $frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for method of form submission.
|
||||
* @return string Either get or post.
|
||||
* @access public
|
||||
*/
|
||||
function getMethod() {
|
||||
return ($this->_method ? strtolower($this->_method) : 'get');
|
||||
}
|
||||
|
||||
/**
|
||||
* Combined action attribute with current location
|
||||
* to get an absolute form target.
|
||||
* @param string $action Action attribute from form tag.
|
||||
* @param SimpleUrl $base Page location.
|
||||
* @return SimpleUrl Absolute form target.
|
||||
*/
|
||||
function _createAction($action, &$page) {
|
||||
if (($action === '') || ($action === false)) {
|
||||
return $page->expandUrl($page->getUrl());
|
||||
}
|
||||
return $page->expandUrl(new SimpleUrl($action));;
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute URL of the target.
|
||||
* @return SimpleUrl URL target.
|
||||
* @access public
|
||||
*/
|
||||
function getAction() {
|
||||
$url = $this->_action;
|
||||
if ($this->_default_target && ! $url->getTarget()) {
|
||||
$url->setTarget($this->_default_target);
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the encoding for the current values in the
|
||||
* form.
|
||||
* @return SimpleFormEncoding Request to submit.
|
||||
* @access private
|
||||
*/
|
||||
function _encode() {
|
||||
$class = $this->_encoding;
|
||||
$encoding = new $class();
|
||||
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
|
||||
$this->_widgets[$i]->write($encoding);
|
||||
}
|
||||
return $encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID field of form for unique identification.
|
||||
* @return string Unique tag ID.
|
||||
* @access public
|
||||
*/
|
||||
function getId() {
|
||||
return $this->_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tag contents to the form.
|
||||
* @param SimpleWidget $tag Input tag to add.
|
||||
* @access public
|
||||
*/
|
||||
function addWidget(&$tag) {
|
||||
if (strtolower($tag->getAttribute('type')) == 'submit') {
|
||||
$this->_buttons[] = &$tag;
|
||||
} elseif (strtolower($tag->getAttribute('type')) == 'image') {
|
||||
$this->_images[] = &$tag;
|
||||
} elseif ($tag->getName()) {
|
||||
$this->_setWidget($tag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the widget into the form, grouping radio
|
||||
* buttons if any.
|
||||
* @param SimpleWidget $tag Incoming form control.
|
||||
* @access private
|
||||
*/
|
||||
function _setWidget(&$tag) {
|
||||
if (strtolower($tag->getAttribute('type')) == 'radio') {
|
||||
$this->_addRadioButton($tag);
|
||||
} elseif (strtolower($tag->getAttribute('type')) == 'checkbox') {
|
||||
$this->_addCheckbox($tag);
|
||||
} else {
|
||||
$this->_widgets[] = &$tag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a radio button, building a group if necessary.
|
||||
* @param SimpleRadioButtonTag $tag Incoming form control.
|
||||
* @access private
|
||||
*/
|
||||
function _addRadioButton(&$tag) {
|
||||
if (! isset($this->_radios[$tag->getName()])) {
|
||||
$this->_widgets[] = &new SimpleRadioGroup();
|
||||
$this->_radios[$tag->getName()] = count($this->_widgets) - 1;
|
||||
}
|
||||
$this->_widgets[$this->_radios[$tag->getName()]]->addWidget($tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a checkbox, making it a group on a repeated name.
|
||||
* @param SimpleCheckboxTag $tag Incoming form control.
|
||||
* @access private
|
||||
*/
|
||||
function _addCheckbox(&$tag) {
|
||||
if (! isset($this->_checkboxes[$tag->getName()])) {
|
||||
$this->_widgets[] = &$tag;
|
||||
$this->_checkboxes[$tag->getName()] = count($this->_widgets) - 1;
|
||||
} else {
|
||||
$index = $this->_checkboxes[$tag->getName()];
|
||||
if (! SimpleTestCompatibility::isA($this->_widgets[$index], 'SimpleCheckboxGroup')) {
|
||||
$previous = &$this->_widgets[$index];
|
||||
$this->_widgets[$index] = &new SimpleCheckboxGroup();
|
||||
$this->_widgets[$index]->addWidget($previous);
|
||||
}
|
||||
$this->_widgets[$index]->addWidget($tag);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts current value from form.
|
||||
* @param SimpleSelector $selector Criteria to apply.
|
||||
* @return string/array Value(s) as string or null
|
||||
* if not set.
|
||||
* @access public
|
||||
*/
|
||||
function getValue($selector) {
|
||||
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
|
||||
if ($selector->isMatch($this->_widgets[$i])) {
|
||||
return $this->_widgets[$i]->getValue();
|
||||
}
|
||||
}
|
||||
foreach ($this->_buttons as $button) {
|
||||
if ($selector->isMatch($button)) {
|
||||
return $button->getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a widget value within the form.
|
||||
* @param SimpleSelector $selector Criteria to apply.
|
||||
* @param string $value Value to input into the widget.
|
||||
* @return boolean True if value is legal, false
|
||||
* otherwise. If the field is not
|
||||
* present, nothing will be set.
|
||||
* @access public
|
||||
*/
|
||||
function setField($selector, $value, $position=false) {
|
||||
$success = false;
|
||||
$_position = 0;
|
||||
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
|
||||
if ($selector->isMatch($this->_widgets[$i])) {
|
||||
$_position++;
|
||||
if ($position === false or $_position === (int)$position) {
|
||||
if ($this->_widgets[$i]->setValue($value)) {
|
||||
$success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the page object to set widgets labels to
|
||||
* external label tags.
|
||||
* @param SimpleSelector $selector Criteria to apply.
|
||||
* @access public
|
||||
*/
|
||||
function attachLabelBySelector($selector, $label) {
|
||||
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
|
||||
if ($selector->isMatch($this->_widgets[$i])) {
|
||||
if (method_exists($this->_widgets[$i], 'setLabel')) {
|
||||
$this->_widgets[$i]->setLabel($label);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if a form has a submit button.
|
||||
* @param SimpleSelector $selector Criteria to apply.
|
||||
* @return boolean True if present.
|
||||
* @access public
|
||||
*/
|
||||
function hasSubmit($selector) {
|
||||
foreach ($this->_buttons as $button) {
|
||||
if ($selector->isMatch($button)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if a form has an image control.
|
||||
* @param SimpleSelector $selector Criteria to apply.
|
||||
* @return boolean True if present.
|
||||
* @access public
|
||||
*/
|
||||
function hasImage($selector) {
|
||||
foreach ($this->_images as $image) {
|
||||
if ($selector->isMatch($image)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the submit values for a selected button.
|
||||
* @param SimpleSelector $selector Criteria to apply.
|
||||
* @param hash $additional Additional data for the form.
|
||||
* @return SimpleEncoding Submitted values or false
|
||||
* if there is no such button
|
||||
* in the form.
|
||||
* @access public
|
||||
*/
|
||||
function submitButton($selector, $additional = false) {
|
||||
$additional = $additional ? $additional : array();
|
||||
foreach ($this->_buttons as $button) {
|
||||
if ($selector->isMatch($button)) {
|
||||
$encoding = $this->_encode();
|
||||
$button->write($encoding);
|
||||
if ($additional) {
|
||||
$encoding->merge($additional);
|
||||
}
|
||||
return $encoding;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the submit values for an image.
|
||||
* @param SimpleSelector $selector Criteria to apply.
|
||||
* @param integer $x X-coordinate of click.
|
||||
* @param integer $y Y-coordinate of click.
|
||||
* @param hash $additional Additional data for the form.
|
||||
* @return SimpleEncoding Submitted values or false
|
||||
* if there is no such button in the
|
||||
* form.
|
||||
* @access public
|
||||
*/
|
||||
function submitImage($selector, $x, $y, $additional = false) {
|
||||
$additional = $additional ? $additional : array();
|
||||
foreach ($this->_images as $image) {
|
||||
if ($selector->isMatch($image)) {
|
||||
$encoding = $this->_encode();
|
||||
$image->write($encoding, $x, $y);
|
||||
if ($additional) {
|
||||
$encoding->merge($additional);
|
||||
}
|
||||
return $encoding;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply submits the form without the submit button
|
||||
* value. Used when there is only one button or it
|
||||
* is unimportant.
|
||||
* @return hash Submitted values.
|
||||
* @access public
|
||||
*/
|
||||
function submit() {
|
||||
return $this->_encode();
|
||||
}
|
||||
}
|
||||
?>
|
624
thirdparty/simpletest/http.php
vendored
Normal file
624
thirdparty/simpletest/http.php
vendored
Normal file
@ -0,0 +1,624 @@
|
||||
<?php
|
||||
/**
|
||||
* base include file for SimpleTest
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
* @version $Id: http.php 1722 2008-04-07 19:30:56Z lastcraft $
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
* include other SimpleTest class files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/socket.php');
|
||||
require_once(dirname(__FILE__) . '/cookies.php');
|
||||
require_once(dirname(__FILE__) . '/url.php');
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Creates HTTP headers for the end point of
|
||||
* a HTTP request.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleRoute {
|
||||
var $_url;
|
||||
|
||||
/**
|
||||
* Sets the target URL.
|
||||
* @param SimpleUrl $url URL as object.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleRoute($url) {
|
||||
$this->_url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource name.
|
||||
* @return SimpleUrl Current url.
|
||||
* @access protected
|
||||
*/
|
||||
function getUrl() {
|
||||
return $this->_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the first line which is the actual request.
|
||||
* @param string $method HTTP request method, usually GET.
|
||||
* @return string Request line content.
|
||||
* @access protected
|
||||
*/
|
||||
function _getRequestLine($method) {
|
||||
return $method . ' ' . $this->_url->getPath() .
|
||||
$this->_url->getEncodedRequest() . ' HTTP/1.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the host part of the request.
|
||||
* @return string Host line content.
|
||||
* @access protected
|
||||
*/
|
||||
function _getHostLine() {
|
||||
$line = 'Host: ' . $this->_url->getHost();
|
||||
if ($this->_url->getPort()) {
|
||||
$line .= ':' . $this->_url->getPort();
|
||||
}
|
||||
return $line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a socket to the route.
|
||||
* @param string $method HTTP request method, usually GET.
|
||||
* @param integer $timeout Connection timeout.
|
||||
* @return SimpleSocket New socket.
|
||||
* @access public
|
||||
*/
|
||||
function &createConnection($method, $timeout) {
|
||||
$default_port = ('https' == $this->_url->getScheme()) ? 443 : 80;
|
||||
$socket = &$this->_createSocket(
|
||||
$this->_url->getScheme() ? $this->_url->getScheme() : 'http',
|
||||
$this->_url->getHost(),
|
||||
$this->_url->getPort() ? $this->_url->getPort() : $default_port,
|
||||
$timeout);
|
||||
if (! $socket->isError()) {
|
||||
$socket->write($this->_getRequestLine($method) . "\r\n");
|
||||
$socket->write($this->_getHostLine() . "\r\n");
|
||||
$socket->write("Connection: close\r\n");
|
||||
}
|
||||
return $socket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for socket.
|
||||
* @param string $scheme Protocol to use.
|
||||
* @param string $host Hostname to connect to.
|
||||
* @param integer $port Remote port.
|
||||
* @param integer $timeout Connection timeout.
|
||||
* @return SimpleSocket/SimpleSecureSocket New socket.
|
||||
* @access protected
|
||||
*/
|
||||
function &_createSocket($scheme, $host, $port, $timeout) {
|
||||
if (in_array($scheme, array('https'))) {
|
||||
$socket = &new SimpleSecureSocket($host, $port, $timeout);
|
||||
} else {
|
||||
$socket = &new SimpleSocket($host, $port, $timeout);
|
||||
}
|
||||
return $socket;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates HTTP headers for the end point of
|
||||
* a HTTP request via a proxy server.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleProxyRoute extends SimpleRoute {
|
||||
var $_proxy;
|
||||
var $_username;
|
||||
var $_password;
|
||||
|
||||
/**
|
||||
* Stashes the proxy address.
|
||||
* @param SimpleUrl $url URL as object.
|
||||
* @param string $proxy Proxy URL.
|
||||
* @param string $username Username for autentication.
|
||||
* @param string $password Password for autentication.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleProxyRoute($url, $proxy, $username = false, $password = false) {
|
||||
$this->SimpleRoute($url);
|
||||
$this->_proxy = $proxy;
|
||||
$this->_username = $username;
|
||||
$this->_password = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the first line which is the actual request.
|
||||
* @param string $method HTTP request method, usually GET.
|
||||
* @param SimpleUrl $url URL as object.
|
||||
* @return string Request line content.
|
||||
* @access protected
|
||||
*/
|
||||
function _getRequestLine($method) {
|
||||
$url = $this->getUrl();
|
||||
$scheme = $url->getScheme() ? $url->getScheme() : 'http';
|
||||
$port = $url->getPort() ? ':' . $url->getPort() : '';
|
||||
return $method . ' ' . $scheme . '://' . $url->getHost() . $port .
|
||||
$url->getPath() . $url->getEncodedRequest() . ' HTTP/1.0';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the host part of the request.
|
||||
* @param SimpleUrl $url URL as object.
|
||||
* @return string Host line content.
|
||||
* @access protected
|
||||
*/
|
||||
function _getHostLine() {
|
||||
$host = 'Host: ' . $this->_proxy->getHost();
|
||||
$port = $this->_proxy->getPort() ? $this->_proxy->getPort() : 8080;
|
||||
return "$host:$port";
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a socket to the route.
|
||||
* @param string $method HTTP request method, usually GET.
|
||||
* @param integer $timeout Connection timeout.
|
||||
* @return SimpleSocket New socket.
|
||||
* @access public
|
||||
*/
|
||||
function &createConnection($method, $timeout) {
|
||||
$socket = &$this->_createSocket(
|
||||
$this->_proxy->getScheme() ? $this->_proxy->getScheme() : 'http',
|
||||
$this->_proxy->getHost(),
|
||||
$this->_proxy->getPort() ? $this->_proxy->getPort() : 8080,
|
||||
$timeout);
|
||||
if ($socket->isError()) {
|
||||
return $socket;
|
||||
}
|
||||
$socket->write($this->_getRequestLine($method) . "\r\n");
|
||||
$socket->write($this->_getHostLine() . "\r\n");
|
||||
if ($this->_username && $this->_password) {
|
||||
$socket->write('Proxy-Authorization: Basic ' .
|
||||
base64_encode($this->_username . ':' . $this->_password) .
|
||||
"\r\n");
|
||||
}
|
||||
$socket->write("Connection: close\r\n");
|
||||
return $socket;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request for a web page. Factory for
|
||||
* HttpResponse object.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleHttpRequest {
|
||||
var $_route;
|
||||
var $_encoding;
|
||||
var $_headers;
|
||||
var $_cookies;
|
||||
|
||||
/**
|
||||
* Builds the socket request from the different pieces.
|
||||
* These include proxy information, URL, cookies, headers,
|
||||
* request method and choice of encoding.
|
||||
* @param SimpleRoute $route Request route.
|
||||
* @param SimpleFormEncoding $encoding Content to send with
|
||||
* request.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleHttpRequest(&$route, $encoding) {
|
||||
$this->_route = &$route;
|
||||
$this->_encoding = $encoding;
|
||||
$this->_headers = array();
|
||||
$this->_cookies = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the content to the route's socket.
|
||||
* @param integer $timeout Connection timeout.
|
||||
* @return SimpleHttpResponse A response which may only have
|
||||
* an error, but hopefully has a
|
||||
* complete web page.
|
||||
* @access public
|
||||
*/
|
||||
function &fetch($timeout) {
|
||||
$socket = &$this->_route->createConnection($this->_encoding->getMethod(), $timeout);
|
||||
if (! $socket->isError()) {
|
||||
$this->_dispatchRequest($socket, $this->_encoding);
|
||||
}
|
||||
$response = &$this->_createResponse($socket);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the headers.
|
||||
* @param SimpleSocket $socket Open socket.
|
||||
* @param string $method HTTP request method,
|
||||
* usually GET.
|
||||
* @param SimpleFormEncoding $encoding Content to send with request.
|
||||
* @access private
|
||||
*/
|
||||
function _dispatchRequest(&$socket, $encoding) {
|
||||
foreach ($this->_headers as $header_line) {
|
||||
$socket->write($header_line . "\r\n");
|
||||
}
|
||||
if (count($this->_cookies) > 0) {
|
||||
$socket->write("Cookie: " . implode(";", $this->_cookies) . "\r\n");
|
||||
}
|
||||
$encoding->writeHeadersTo($socket);
|
||||
$socket->write("\r\n");
|
||||
$encoding->writeTo($socket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a header line to the request.
|
||||
* @param string $header_line Text of full header line.
|
||||
* @access public
|
||||
*/
|
||||
function addHeaderLine($header_line) {
|
||||
$this->_headers[] = $header_line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all the relevant cookies from the
|
||||
* cookie jar.
|
||||
* @param SimpleCookieJar $jar Jar to read
|
||||
* @param SimpleUrl $url Url to use for scope.
|
||||
* @access public
|
||||
*/
|
||||
function readCookiesFromJar($jar, $url) {
|
||||
$this->_cookies = $jar->selectAsPairs($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the socket in a response parser.
|
||||
* @param SimpleSocket $socket Responding socket.
|
||||
* @return SimpleHttpResponse Parsed response object.
|
||||
* @access protected
|
||||
*/
|
||||
function &_createResponse(&$socket) {
|
||||
$response = &new SimpleHttpResponse(
|
||||
$socket,
|
||||
$this->_route->getUrl(),
|
||||
$this->_encoding);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collection of header lines in the response.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleHttpHeaders {
|
||||
var $_raw_headers;
|
||||
var $_response_code;
|
||||
var $_http_version;
|
||||
var $_mime_type;
|
||||
var $_location;
|
||||
var $_cookies;
|
||||
var $_authentication;
|
||||
var $_realm;
|
||||
|
||||
/**
|
||||
* Parses the incoming header block.
|
||||
* @param string $headers Header block.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleHttpHeaders($headers) {
|
||||
$this->_raw_headers = $headers;
|
||||
$this->_response_code = false;
|
||||
$this->_http_version = false;
|
||||
$this->_mime_type = '';
|
||||
$this->_location = false;
|
||||
$this->_cookies = array();
|
||||
$this->_authentication = false;
|
||||
$this->_realm = false;
|
||||
foreach (split("\r\n", $headers) as $header_line) {
|
||||
$this->_parseHeaderLine($header_line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for parsed HTTP protocol version.
|
||||
* @return integer HTTP error code.
|
||||
* @access public
|
||||
*/
|
||||
function getHttpVersion() {
|
||||
return $this->_http_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for raw header block.
|
||||
* @return string All headers as raw string.
|
||||
* @access public
|
||||
*/
|
||||
function getRaw() {
|
||||
return $this->_raw_headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for parsed HTTP error code.
|
||||
* @return integer HTTP error code.
|
||||
* @access public
|
||||
*/
|
||||
function getResponseCode() {
|
||||
return (integer)$this->_response_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the redirected URL or false if
|
||||
* no redirection.
|
||||
* @return string URL or false for none.
|
||||
* @access public
|
||||
*/
|
||||
function getLocation() {
|
||||
return $this->_location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the response is a valid redirect.
|
||||
* @return boolean True if valid redirect.
|
||||
* @access public
|
||||
*/
|
||||
function isRedirect() {
|
||||
return in_array($this->_response_code, array(301, 302, 303, 307)) &&
|
||||
(boolean)$this->getLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the response is an authentication
|
||||
* challenge.
|
||||
* @return boolean True if challenge.
|
||||
* @access public
|
||||
*/
|
||||
function isChallenge() {
|
||||
return ($this->_response_code == 401) &&
|
||||
(boolean)$this->_authentication &&
|
||||
(boolean)$this->_realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for MIME type header information.
|
||||
* @return string MIME type.
|
||||
* @access public
|
||||
*/
|
||||
function getMimeType() {
|
||||
return $this->_mime_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for authentication type.
|
||||
* @return string Type.
|
||||
* @access public
|
||||
*/
|
||||
function getAuthentication() {
|
||||
return $this->_authentication;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for security realm.
|
||||
* @return string Realm.
|
||||
* @access public
|
||||
*/
|
||||
function getRealm() {
|
||||
return $this->_realm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes new cookies to the cookie jar.
|
||||
* @param SimpleCookieJar $jar Jar to write to.
|
||||
* @param SimpleUrl $url Host and path to write under.
|
||||
* @access public
|
||||
*/
|
||||
function writeCookiesToJar(&$jar, $url) {
|
||||
foreach ($this->_cookies as $cookie) {
|
||||
$jar->setCookie(
|
||||
$cookie->getName(),
|
||||
$cookie->getValue(),
|
||||
$url->getHost(),
|
||||
$cookie->getPath(),
|
||||
$cookie->getExpiry());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on each header line to accumulate the held
|
||||
* data within the class.
|
||||
* @param string $header_line One line of header.
|
||||
* @access protected
|
||||
*/
|
||||
function _parseHeaderLine($header_line) {
|
||||
if (preg_match('/HTTP\/(\d+\.\d+)\s+(\d+)/i', $header_line, $matches)) {
|
||||
$this->_http_version = $matches[1];
|
||||
$this->_response_code = $matches[2];
|
||||
}
|
||||
if (preg_match('/Content-type:\s*(.*)/i', $header_line, $matches)) {
|
||||
$this->_mime_type = trim($matches[1]);
|
||||
}
|
||||
if (preg_match('/Location:\s*(.*)/i', $header_line, $matches)) {
|
||||
$this->_location = trim($matches[1]);
|
||||
}
|
||||
if (preg_match('/Set-cookie:(.*)/i', $header_line, $matches)) {
|
||||
$this->_cookies[] = $this->_parseCookie($matches[1]);
|
||||
}
|
||||
if (preg_match('/WWW-Authenticate:\s+(\S+)\s+realm=\"(.*?)\"/i', $header_line, $matches)) {
|
||||
$this->_authentication = $matches[1];
|
||||
$this->_realm = trim($matches[2]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the Set-cookie content.
|
||||
* @param string $cookie_line Text after "Set-cookie:"
|
||||
* @return SimpleCookie New cookie object.
|
||||
* @access private
|
||||
*/
|
||||
function _parseCookie($cookie_line) {
|
||||
$parts = split(";", $cookie_line);
|
||||
$cookie = array();
|
||||
preg_match('/\s*(.*?)\s*=(.*)/', array_shift($parts), $cookie);
|
||||
foreach ($parts as $part) {
|
||||
if (preg_match('/\s*(.*?)\s*=(.*)/', $part, $matches)) {
|
||||
$cookie[$matches[1]] = trim($matches[2]);
|
||||
}
|
||||
}
|
||||
return new SimpleCookie(
|
||||
$cookie[1],
|
||||
trim($cookie[2]),
|
||||
isset($cookie["path"]) ? $cookie["path"] : "",
|
||||
isset($cookie["expires"]) ? $cookie["expires"] : false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic HTTP response.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleHttpResponse extends SimpleStickyError {
|
||||
var $_url;
|
||||
var $_encoding;
|
||||
var $_sent;
|
||||
var $_content;
|
||||
var $_headers;
|
||||
|
||||
/**
|
||||
* Constructor. Reads and parses the incoming
|
||||
* content and headers.
|
||||
* @param SimpleSocket $socket Network connection to fetch
|
||||
* response text from.
|
||||
* @param SimpleUrl $url Resource name.
|
||||
* @param mixed $encoding Record of content sent.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleHttpResponse(&$socket, $url, $encoding) {
|
||||
$this->SimpleStickyError();
|
||||
$this->_url = $url;
|
||||
$this->_encoding = $encoding;
|
||||
$this->_sent = $socket->getSent();
|
||||
$this->_content = false;
|
||||
$raw = $this->_readAll($socket);
|
||||
if ($socket->isError()) {
|
||||
$this->_setError('Error reading socket [' . $socket->getError() . ']');
|
||||
return;
|
||||
}
|
||||
$this->_parse($raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits up the headers and the rest of the content.
|
||||
* @param string $raw Content to parse.
|
||||
* @access private
|
||||
*/
|
||||
function _parse($raw) {
|
||||
if (! $raw) {
|
||||
$this->_setError('Nothing fetched');
|
||||
$this->_headers = &new SimpleHttpHeaders('');
|
||||
} elseif (! strstr($raw, "\r\n\r\n")) {
|
||||
$this->_setError('Could not split headers from content');
|
||||
$this->_headers = &new SimpleHttpHeaders($raw);
|
||||
} else {
|
||||
list($headers, $this->_content) = split("\r\n\r\n", $raw, 2);
|
||||
$this->_headers = &new SimpleHttpHeaders($headers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Original request method.
|
||||
* @return string GET, POST or HEAD.
|
||||
* @access public
|
||||
*/
|
||||
function getMethod() {
|
||||
return $this->_encoding->getMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resource name.
|
||||
* @return SimpleUrl Current url.
|
||||
* @access public
|
||||
*/
|
||||
function getUrl() {
|
||||
return $this->_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Original request data.
|
||||
* @return mixed Sent content.
|
||||
* @access public
|
||||
*/
|
||||
function getRequestData() {
|
||||
return $this->_encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw request that was sent down the wire.
|
||||
* @return string Bytes actually sent.
|
||||
* @access public
|
||||
*/
|
||||
function getSent() {
|
||||
return $this->_sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the content after the last
|
||||
* header line.
|
||||
* @return string All content.
|
||||
* @access public
|
||||
*/
|
||||
function getContent() {
|
||||
return $this->_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for header block. The response is the
|
||||
* combination of this and the content.
|
||||
* @return SimpleHeaders Wrapped header block.
|
||||
* @access public
|
||||
*/
|
||||
function getHeaders() {
|
||||
return $this->_headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for any new cookies.
|
||||
* @return array List of new cookies.
|
||||
* @access public
|
||||
*/
|
||||
function getNewCookies() {
|
||||
return $this->_headers->getNewCookies();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the whole of the socket output into a
|
||||
* single string.
|
||||
* @param SimpleSocket $socket Unread socket.
|
||||
* @return string Raw output if successful
|
||||
* else false.
|
||||
* @access private
|
||||
*/
|
||||
function _readAll(&$socket) {
|
||||
$all = '';
|
||||
while (! $this->_isLastPacket($next = $socket->read())) {
|
||||
$all .= $next;
|
||||
}
|
||||
return $all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the packet from the socket is the
|
||||
* last one.
|
||||
* @param string $packet Chunk to interpret.
|
||||
* @return boolean True if empty or EOF.
|
||||
* @access private
|
||||
*/
|
||||
function _isLastPacket($packet) {
|
||||
if (is_string($packet)) {
|
||||
return $packet === '';
|
||||
}
|
||||
return ! $packet;
|
||||
}
|
||||
}
|
||||
?>
|
983
thirdparty/simpletest/page.php
vendored
Normal file
983
thirdparty/simpletest/page.php
vendored
Normal file
@ -0,0 +1,983 @@
|
||||
<?php
|
||||
/**
|
||||
* Base include file for SimpleTest
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
* @version $Id: page.php 1672 2008-03-02 04:47:34Z edwardzyang $
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
* include other SimpleTest class files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/http.php');
|
||||
require_once(dirname(__FILE__) . '/parser.php');
|
||||
require_once(dirname(__FILE__) . '/tag.php');
|
||||
require_once(dirname(__FILE__) . '/form.php');
|
||||
require_once(dirname(__FILE__) . '/selector.php');
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Creates tags and widgets given HTML tag
|
||||
* attributes.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleTagBuilder {
|
||||
|
||||
/**
|
||||
* Factory for the tag objects. Creates the
|
||||
* appropriate tag object for the incoming tag name
|
||||
* and attributes.
|
||||
* @param string $name HTML tag name.
|
||||
* @param hash $attributes Element attributes.
|
||||
* @return SimpleTag Tag object.
|
||||
* @access public
|
||||
*/
|
||||
function createTag($name, $attributes) {
|
||||
static $map = array(
|
||||
'a' => 'SimpleAnchorTag',
|
||||
'title' => 'SimpleTitleTag',
|
||||
'base' => 'SimpleBaseTag',
|
||||
'button' => 'SimpleButtonTag',
|
||||
'textarea' => 'SimpleTextAreaTag',
|
||||
'option' => 'SimpleOptionTag',
|
||||
'label' => 'SimpleLabelTag',
|
||||
'form' => 'SimpleFormTag',
|
||||
'frame' => 'SimpleFrameTag');
|
||||
$attributes = $this->_keysToLowerCase($attributes);
|
||||
if (array_key_exists($name, $map)) {
|
||||
$tag_class = $map[$name];
|
||||
return new $tag_class($attributes);
|
||||
} elseif ($name == 'select') {
|
||||
return $this->_createSelectionTag($attributes);
|
||||
} elseif ($name == 'input') {
|
||||
return $this->_createInputTag($attributes);
|
||||
}
|
||||
return new SimpleTag($name, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for selection fields.
|
||||
* @param hash $attributes Element attributes.
|
||||
* @return SimpleTag Tag object.
|
||||
* @access protected
|
||||
*/
|
||||
function _createSelectionTag($attributes) {
|
||||
if (isset($attributes['multiple'])) {
|
||||
return new MultipleSelectionTag($attributes);
|
||||
}
|
||||
return new SimpleSelectionTag($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory for input tags.
|
||||
* @param hash $attributes Element attributes.
|
||||
* @return SimpleTag Tag object.
|
||||
* @access protected
|
||||
*/
|
||||
function _createInputTag($attributes) {
|
||||
if (! isset($attributes['type'])) {
|
||||
return new SimpleTextTag($attributes);
|
||||
}
|
||||
$type = strtolower(trim($attributes['type']));
|
||||
$map = array(
|
||||
'submit' => 'SimpleSubmitTag',
|
||||
'image' => 'SimpleImageSubmitTag',
|
||||
'checkbox' => 'SimpleCheckboxTag',
|
||||
'radio' => 'SimpleRadioButtonTag',
|
||||
'text' => 'SimpleTextTag',
|
||||
'hidden' => 'SimpleTextTag',
|
||||
'password' => 'SimpleTextTag',
|
||||
'file' => 'SimpleUploadTag');
|
||||
if (array_key_exists($type, $map)) {
|
||||
$tag_class = $map[$type];
|
||||
return new $tag_class($attributes);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the keys lower case for case insensitive look-ups.
|
||||
* @param hash $map Hash to convert.
|
||||
* @return hash Unchanged values, but keys lower case.
|
||||
* @access private
|
||||
*/
|
||||
function _keysToLowerCase($map) {
|
||||
$lower = array();
|
||||
foreach ($map as $key => $value) {
|
||||
$lower[strtolower($key)] = $value;
|
||||
}
|
||||
return $lower;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SAX event handler. Maintains a list of
|
||||
* open tags and dispatches them as they close.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimplePageBuilder extends SimpleSaxListener {
|
||||
var $_tags;
|
||||
var $_page;
|
||||
var $_private_content_tag;
|
||||
|
||||
/**
|
||||
* Sets the builder up empty.
|
||||
* @access public
|
||||
*/
|
||||
function SimplePageBuilder() {
|
||||
$this->SimpleSaxListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees up any references so as to allow the PHP garbage
|
||||
* collection from unset() to work.
|
||||
* @access public
|
||||
*/
|
||||
function free() {
|
||||
unset($this->_tags);
|
||||
unset($this->_page);
|
||||
unset($this->_private_content_tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the raw content and send events
|
||||
* into the page to be built.
|
||||
* @param $response SimpleHttpResponse Fetched response.
|
||||
* @return SimplePage Newly parsed page.
|
||||
* @access public
|
||||
*/
|
||||
function &parse($response) {
|
||||
$this->_tags = array();
|
||||
$this->_page = &$this->_createPage($response);
|
||||
$parser = &$this->_createParser($this);
|
||||
$parser->parse($response->getContent());
|
||||
$this->_page->acceptPageEnd();
|
||||
return $this->_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty page.
|
||||
* @return SimplePage New unparsed page.
|
||||
* @access protected
|
||||
*/
|
||||
function &_createPage($response) {
|
||||
$page = &new SimplePage($response);
|
||||
return $page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the parser used with the builder.
|
||||
* @param $listener SimpleSaxListener Target of parser.
|
||||
* @return SimpleSaxParser Parser to generate
|
||||
* events for the builder.
|
||||
* @access protected
|
||||
*/
|
||||
function &_createParser(&$listener) {
|
||||
$parser = &new SimpleHtmlSaxParser($listener);
|
||||
return $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start of element event. Opens a new tag.
|
||||
* @param string $name Element name.
|
||||
* @param hash $attributes Attributes without content
|
||||
* are marked as true.
|
||||
* @return boolean False on parse error.
|
||||
* @access public
|
||||
*/
|
||||
function startElement($name, $attributes) {
|
||||
$factory = &new SimpleTagBuilder();
|
||||
$tag = $factory->createTag($name, $attributes);
|
||||
if (! $tag) {
|
||||
return true;
|
||||
}
|
||||
if ($tag->getTagName() == 'label') {
|
||||
$this->_page->acceptLabelStart($tag);
|
||||
$this->_openTag($tag);
|
||||
return true;
|
||||
}
|
||||
if ($tag->getTagName() == 'form') {
|
||||
$this->_page->acceptFormStart($tag);
|
||||
return true;
|
||||
}
|
||||
if ($tag->getTagName() == 'frameset') {
|
||||
$this->_page->acceptFramesetStart($tag);
|
||||
return true;
|
||||
}
|
||||
if ($tag->getTagName() == 'frame') {
|
||||
$this->_page->acceptFrame($tag);
|
||||
return true;
|
||||
}
|
||||
if ($tag->isPrivateContent() && ! isset($this->_private_content_tag)) {
|
||||
$this->_private_content_tag = &$tag;
|
||||
}
|
||||
if ($tag->expectEndTag()) {
|
||||
$this->_openTag($tag);
|
||||
return true;
|
||||
}
|
||||
$this->_page->acceptTag($tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of element event.
|
||||
* @param string $name Element name.
|
||||
* @return boolean False on parse error.
|
||||
* @access public
|
||||
*/
|
||||
function endElement($name) {
|
||||
if ($name == 'label') {
|
||||
$this->_page->acceptLabelEnd();
|
||||
return true;
|
||||
}
|
||||
if ($name == 'form') {
|
||||
$this->_page->acceptFormEnd();
|
||||
return true;
|
||||
}
|
||||
if ($name == 'frameset') {
|
||||
$this->_page->acceptFramesetEnd();
|
||||
return true;
|
||||
}
|
||||
if ($this->_hasNamedTagOnOpenTagStack($name)) {
|
||||
$tag = array_pop($this->_tags[$name]);
|
||||
if ($tag->isPrivateContent() && $this->_private_content_tag->getTagName() == $name) {
|
||||
unset($this->_private_content_tag);
|
||||
}
|
||||
$this->_addContentTagToOpenTags($tag);
|
||||
$this->_page->acceptTag($tag);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if there are any open tags awaiting
|
||||
* closure that match the tag name.
|
||||
* @param string $name Element name.
|
||||
* @return boolean True if any are still open.
|
||||
* @access private
|
||||
*/
|
||||
function _hasNamedTagOnOpenTagStack($name) {
|
||||
return isset($this->_tags[$name]) && (count($this->_tags[$name]) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unparsed, but relevant data. The data is added
|
||||
* to every open tag.
|
||||
* @param string $text May include unparsed tags.
|
||||
* @return boolean False on parse error.
|
||||
* @access public
|
||||
*/
|
||||
function addContent($text) {
|
||||
if (isset($this->_private_content_tag)) {
|
||||
$this->_private_content_tag->addContent($text);
|
||||
} else {
|
||||
$this->_addContentToAllOpenTags($text);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Any content fills all currently open tags unless it
|
||||
* is part of an option tag.
|
||||
* @param string $text May include unparsed tags.
|
||||
* @access private
|
||||
*/
|
||||
function _addContentToAllOpenTags($text) {
|
||||
foreach (array_keys($this->_tags) as $name) {
|
||||
for ($i = 0, $count = count($this->_tags[$name]); $i < $count; $i++) {
|
||||
$this->_tags[$name][$i]->addContent($text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsed data in tag form. The parsed tag is added
|
||||
* to every open tag. Used for adding options to select
|
||||
* fields only.
|
||||
* @param SimpleTag $tag Option tags only.
|
||||
* @access private
|
||||
*/
|
||||
function _addContentTagToOpenTags(&$tag) {
|
||||
if ($tag->getTagName() != 'option') {
|
||||
return;
|
||||
}
|
||||
foreach (array_keys($this->_tags) as $name) {
|
||||
for ($i = 0, $count = count($this->_tags[$name]); $i < $count; $i++) {
|
||||
$this->_tags[$name][$i]->addTag($tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a tag for receiving content. Multiple tags
|
||||
* will be receiving input at the same time.
|
||||
* @param SimpleTag $tag New content tag.
|
||||
* @access private
|
||||
*/
|
||||
function _openTag(&$tag) {
|
||||
$name = $tag->getTagName();
|
||||
if (! in_array($name, array_keys($this->_tags))) {
|
||||
$this->_tags[$name] = array();
|
||||
}
|
||||
$this->_tags[$name][] = &$tag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper for a web page.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimplePage {
|
||||
var $_links;
|
||||
var $_title;
|
||||
var $_last_widget;
|
||||
var $_label;
|
||||
var $_left_over_labels;
|
||||
var $_open_forms;
|
||||
var $_complete_forms;
|
||||
var $_frameset;
|
||||
var $_frames;
|
||||
var $_frameset_nesting_level;
|
||||
var $_transport_error;
|
||||
var $_raw;
|
||||
var $_text;
|
||||
var $_sent;
|
||||
var $_headers;
|
||||
var $_method;
|
||||
var $_url;
|
||||
var $_base = false;
|
||||
var $_request_data;
|
||||
|
||||
/**
|
||||
* Parses a page ready to access it's contents.
|
||||
* @param SimpleHttpResponse $response Result of HTTP fetch.
|
||||
* @access public
|
||||
*/
|
||||
function SimplePage($response = false) {
|
||||
$this->_links = array();
|
||||
$this->_title = false;
|
||||
$this->_left_over_labels = array();
|
||||
$this->_open_forms = array();
|
||||
$this->_complete_forms = array();
|
||||
$this->_frameset = false;
|
||||
$this->_frames = array();
|
||||
$this->_frameset_nesting_level = 0;
|
||||
$this->_text = false;
|
||||
if ($response) {
|
||||
$this->_extractResponse($response);
|
||||
} else {
|
||||
$this->_noResponse();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts all of the response information.
|
||||
* @param SimpleHttpResponse $response Response being parsed.
|
||||
* @access private
|
||||
*/
|
||||
function _extractResponse($response) {
|
||||
$this->_transport_error = $response->getError();
|
||||
$this->_raw = $response->getContent();
|
||||
$this->_sent = $response->getSent();
|
||||
$this->_headers = $response->getHeaders();
|
||||
$this->_method = $response->getMethod();
|
||||
$this->_url = $response->getUrl();
|
||||
$this->_request_data = $response->getRequestData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a missing response.
|
||||
* @access private
|
||||
*/
|
||||
function _noResponse() {
|
||||
$this->_transport_error = 'No page fetched yet';
|
||||
$this->_raw = false;
|
||||
$this->_sent = false;
|
||||
$this->_headers = false;
|
||||
$this->_method = 'GET';
|
||||
$this->_url = false;
|
||||
$this->_request_data = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Original request as bytes sent down the wire.
|
||||
* @return mixed Sent content.
|
||||
* @access public
|
||||
*/
|
||||
function getRequest() {
|
||||
return $this->_sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for raw text of page.
|
||||
* @return string Raw unparsed content.
|
||||
* @access public
|
||||
*/
|
||||
function getRaw() {
|
||||
return $this->_raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for plain text of page as a text browser
|
||||
* would see it.
|
||||
* @return string Plain text of page.
|
||||
* @access public
|
||||
*/
|
||||
function getText() {
|
||||
if (! $this->_text) {
|
||||
$this->_text = SimpleHtmlSaxParser::normalise($this->_raw);
|
||||
}
|
||||
return $this->_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for raw headers of page.
|
||||
* @return string Header block as text.
|
||||
* @access public
|
||||
*/
|
||||
function getHeaders() {
|
||||
if ($this->_headers) {
|
||||
return $this->_headers->getRaw();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Original request method.
|
||||
* @return string GET, POST or HEAD.
|
||||
* @access public
|
||||
*/
|
||||
function getMethod() {
|
||||
return $this->_method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Original resource name.
|
||||
* @return SimpleUrl Current url.
|
||||
* @access public
|
||||
*/
|
||||
function getUrl() {
|
||||
return $this->_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base URL if set via BASE tag page url otherwise
|
||||
* @return SimpleUrl Base url.
|
||||
* @access public
|
||||
*/
|
||||
function getBaseUrl() {
|
||||
return $this->_base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Original request data.
|
||||
* @return mixed Sent content.
|
||||
* @access public
|
||||
*/
|
||||
function getRequestData() {
|
||||
return $this->_request_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for last error.
|
||||
* @return string Error from last response.
|
||||
* @access public
|
||||
*/
|
||||
function getTransportError() {
|
||||
return $this->_transport_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for current MIME type.
|
||||
* @return string MIME type as string; e.g. 'text/html'
|
||||
* @access public
|
||||
*/
|
||||
function getMimeType() {
|
||||
if ($this->_headers) {
|
||||
return $this->_headers->getMimeType();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for HTTP response code.
|
||||
* @return integer HTTP response code received.
|
||||
* @access public
|
||||
*/
|
||||
function getResponseCode() {
|
||||
if ($this->_headers) {
|
||||
return $this->_headers->getResponseCode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for last Authentication type. Only valid
|
||||
* straight after a challenge (401).
|
||||
* @return string Description of challenge type.
|
||||
* @access public
|
||||
*/
|
||||
function getAuthentication() {
|
||||
if ($this->_headers) {
|
||||
return $this->_headers->getAuthentication();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for last Authentication realm. Only valid
|
||||
* straight after a challenge (401).
|
||||
* @return string Name of security realm.
|
||||
* @access public
|
||||
*/
|
||||
function getRealm() {
|
||||
if ($this->_headers) {
|
||||
return $this->_headers->getRealm();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for current frame focus. Will be
|
||||
* false as no frames.
|
||||
* @return array Always empty.
|
||||
* @access public
|
||||
*/
|
||||
function getFrameFocus() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the focus by index. The integer index starts from 1.
|
||||
* @param integer $choice Chosen frame.
|
||||
* @return boolean Always false.
|
||||
* @access public
|
||||
*/
|
||||
function setFrameFocusByIndex($choice) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the focus by name. Always fails for a leaf page.
|
||||
* @param string $name Chosen frame.
|
||||
* @return boolean False as no frames.
|
||||
* @access public
|
||||
*/
|
||||
function setFrameFocus($name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the frame focus. Does nothing for a leaf page.
|
||||
* @access public
|
||||
*/
|
||||
function clearFrameFocus() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tag to the page.
|
||||
* @param SimpleTag $tag Tag to accept.
|
||||
* @access public
|
||||
*/
|
||||
function acceptTag(&$tag) {
|
||||
if ($tag->getTagName() == "a") {
|
||||
$this->_addLink($tag);
|
||||
} elseif ($tag->getTagName() == "base") {
|
||||
$this->_setBase($tag);
|
||||
} elseif ($tag->getTagName() == "title") {
|
||||
$this->_setTitle($tag);
|
||||
} elseif ($this->_isFormElement($tag->getTagName())) {
|
||||
for ($i = 0; $i < count($this->_open_forms); $i++) {
|
||||
$this->_open_forms[$i]->addWidget($tag);
|
||||
}
|
||||
$this->_last_widget = &$tag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a label for a described widget.
|
||||
* @param SimpleFormTag $tag Tag to accept.
|
||||
* @access public
|
||||
*/
|
||||
function acceptLabelStart(&$tag) {
|
||||
$this->_label = &$tag;
|
||||
unset($this->_last_widget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the most recently opened label.
|
||||
* @access public
|
||||
*/
|
||||
function acceptLabelEnd() {
|
||||
if (isset($this->_label)) {
|
||||
if (isset($this->_last_widget)) {
|
||||
$this->_last_widget->setLabel($this->_label->getText());
|
||||
unset($this->_last_widget);
|
||||
} else {
|
||||
$this->_left_over_labels[] = SimpleTestCompatibility::copy($this->_label);
|
||||
}
|
||||
unset($this->_label);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if a tag is a possible form
|
||||
* element.
|
||||
* @param string $name HTML element name.
|
||||
* @return boolean True if form element.
|
||||
* @access private
|
||||
*/
|
||||
function _isFormElement($name) {
|
||||
return in_array($name, array('input', 'button', 'textarea', 'select'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a form. New widgets go here.
|
||||
* @param SimpleFormTag $tag Tag to accept.
|
||||
* @access public
|
||||
*/
|
||||
function acceptFormStart(&$tag) {
|
||||
$this->_open_forms[] = &new SimpleForm($tag, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the most recently opened form.
|
||||
* @access public
|
||||
*/
|
||||
function acceptFormEnd() {
|
||||
if (count($this->_open_forms)) {
|
||||
$this->_complete_forms[] = array_pop($this->_open_forms);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a frameset. A frameset may contain nested
|
||||
* frameset tags.
|
||||
* @param SimpleFramesetTag $tag Tag to accept.
|
||||
* @access public
|
||||
*/
|
||||
function acceptFramesetStart(&$tag) {
|
||||
if (! $this->_isLoadingFrames()) {
|
||||
$this->_frameset = &$tag;
|
||||
}
|
||||
$this->_frameset_nesting_level++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the most recently opened frameset.
|
||||
* @access public
|
||||
*/
|
||||
function acceptFramesetEnd() {
|
||||
if ($this->_isLoadingFrames()) {
|
||||
$this->_frameset_nesting_level--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a single frame tag and stashes it in
|
||||
* the current frame set.
|
||||
* @param SimpleFrameTag $tag Tag to accept.
|
||||
* @access public
|
||||
*/
|
||||
function acceptFrame(&$tag) {
|
||||
if ($this->_isLoadingFrames()) {
|
||||
if ($tag->getAttribute('src')) {
|
||||
$this->_frames[] = &$tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if in the middle of reading
|
||||
* a frameset.
|
||||
* @return boolean True if inframeset.
|
||||
* @access private
|
||||
*/
|
||||
function _isLoadingFrames() {
|
||||
if (! $this->_frameset) {
|
||||
return false;
|
||||
}
|
||||
return ($this->_frameset_nesting_level > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if link is an absolute one.
|
||||
* @param string $url Url to test.
|
||||
* @return boolean True if absolute.
|
||||
* @access protected
|
||||
*/
|
||||
function _linkIsAbsolute($url) {
|
||||
$parsed = new SimpleUrl($url);
|
||||
return (boolean)($parsed->getScheme() && $parsed->getHost());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a link to the page.
|
||||
* @param SimpleAnchorTag $tag Link to accept.
|
||||
* @access protected
|
||||
*/
|
||||
function _addLink($tag) {
|
||||
$this->_links[] = $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marker for end of complete page. Any work in
|
||||
* progress can now be closed.
|
||||
* @access public
|
||||
*/
|
||||
function acceptPageEnd() {
|
||||
while (count($this->_open_forms)) {
|
||||
$this->_complete_forms[] = array_pop($this->_open_forms);
|
||||
}
|
||||
foreach ($this->_left_over_labels as $label) {
|
||||
for ($i = 0, $count = count($this->_complete_forms); $i < $count; $i++) {
|
||||
$this->_complete_forms[$i]->attachLabelBySelector(
|
||||
new SimpleById($label->getFor()),
|
||||
$label->getText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for the presence of a frameset.
|
||||
* @return boolean True if frameset.
|
||||
* @access public
|
||||
*/
|
||||
function hasFrames() {
|
||||
return (boolean)$this->_frameset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for frame name and source URL for every frame that
|
||||
* will need to be loaded. Immediate children only.
|
||||
* @return boolean/array False if no frameset or
|
||||
* otherwise a hash of frame URLs.
|
||||
* The key is either a numerical
|
||||
* base one index or the name attribute.
|
||||
* @access public
|
||||
*/
|
||||
function getFrameset() {
|
||||
if (! $this->_frameset) {
|
||||
return false;
|
||||
}
|
||||
$urls = array();
|
||||
for ($i = 0; $i < count($this->_frames); $i++) {
|
||||
$name = $this->_frames[$i]->getAttribute('name');
|
||||
$url = new SimpleUrl($this->_frames[$i]->getAttribute('src'));
|
||||
$urls[$name ? $name : $i + 1] = $this->expandUrl($url);
|
||||
}
|
||||
return $urls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a list of loaded frames.
|
||||
* @return array/string Just the URL for a single page.
|
||||
* @access public
|
||||
*/
|
||||
function getFrames() {
|
||||
$url = $this->expandUrl($this->getUrl());
|
||||
return $url->asString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for a list of all links.
|
||||
* @return array List of urls with scheme of
|
||||
* http or https and hostname.
|
||||
* @access public
|
||||
*/
|
||||
function getUrls() {
|
||||
$all = array();
|
||||
foreach ($this->_links as $link) {
|
||||
$url = $this->_getUrlFromLink($link);
|
||||
$all[] = $url->asString();
|
||||
}
|
||||
return $all;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for URLs by the link label. Label will match
|
||||
* regardess of whitespace issues and case.
|
||||
* @param string $label Text of link.
|
||||
* @return array List of links with that label.
|
||||
* @access public
|
||||
*/
|
||||
function getUrlsByLabel($label) {
|
||||
$matches = array();
|
||||
foreach ($this->_links as $link) {
|
||||
if ($link->getText() == $label) {
|
||||
$matches[] = $this->_getUrlFromLink($link);
|
||||
}
|
||||
}
|
||||
return $matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for a URL by the id attribute.
|
||||
* @param string $id Id attribute of link.
|
||||
* @return SimpleUrl URL with that id of false if none.
|
||||
* @access public
|
||||
*/
|
||||
function getUrlById($id) {
|
||||
foreach ($this->_links as $link) {
|
||||
if ($link->getAttribute('id') === (string)$id) {
|
||||
return $this->_getUrlFromLink($link);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a link tag into a target URL.
|
||||
* @param SimpleAnchor $link Parsed link.
|
||||
* @return SimpleUrl URL with frame target if any.
|
||||
* @access private
|
||||
*/
|
||||
function _getUrlFromLink($link) {
|
||||
$url = $this->expandUrl($link->getHref());
|
||||
if ($link->getAttribute('target')) {
|
||||
$url->setTarget($link->getAttribute('target'));
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands expandomatic URLs into fully qualified
|
||||
* URLs.
|
||||
* @param SimpleUrl $url Relative URL.
|
||||
* @return SimpleUrl Absolute URL.
|
||||
* @access public
|
||||
*/
|
||||
function expandUrl($url) {
|
||||
if (! is_object($url)) {
|
||||
$url = new SimpleUrl($url);
|
||||
}
|
||||
$location = $this->getBaseUrl() ? $this->getBaseUrl() : new SimpleUrl();
|
||||
return $url->makeAbsolute($location->makeAbsolute($this->getUrl()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the base url for the page.
|
||||
* @param SimpleTag $tag Base URL for page.
|
||||
* @access protected
|
||||
*/
|
||||
function _setBase(&$tag) {
|
||||
$url = $tag->getAttribute('href');
|
||||
$this->_base = new SimpleUrl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the title tag contents.
|
||||
* @param SimpleTitleTag $tag Title of page.
|
||||
* @access protected
|
||||
*/
|
||||
function _setTitle(&$tag) {
|
||||
$this->_title = &$tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for parsed title.
|
||||
* @return string Title or false if no title is present.
|
||||
* @access public
|
||||
*/
|
||||
function getTitle() {
|
||||
if ($this->_title) {
|
||||
return $this->_title->getText();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a held form by button label. Will only
|
||||
* search correctly built forms.
|
||||
* @param SimpleSelector $selector Button finder.
|
||||
* @return SimpleForm Form object containing
|
||||
* the button.
|
||||
* @access public
|
||||
*/
|
||||
function &getFormBySubmit($selector) {
|
||||
for ($i = 0; $i < count($this->_complete_forms); $i++) {
|
||||
if ($this->_complete_forms[$i]->hasSubmit($selector)) {
|
||||
return $this->_complete_forms[$i];
|
||||
}
|
||||
}
|
||||
$null = null;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a held form by image using a selector.
|
||||
* Will only search correctly built forms.
|
||||
* @param SimpleSelector $selector Image finder.
|
||||
* @return SimpleForm Form object containing
|
||||
* the image.
|
||||
* @access public
|
||||
*/
|
||||
function &getFormByImage($selector) {
|
||||
for ($i = 0; $i < count($this->_complete_forms); $i++) {
|
||||
if ($this->_complete_forms[$i]->hasImage($selector)) {
|
||||
return $this->_complete_forms[$i];
|
||||
}
|
||||
}
|
||||
$null = null;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a held form by the form ID. A way of
|
||||
* identifying a specific form when we have control
|
||||
* of the HTML code.
|
||||
* @param string $id Form label.
|
||||
* @return SimpleForm Form object containing the matching ID.
|
||||
* @access public
|
||||
*/
|
||||
function &getFormById($id) {
|
||||
for ($i = 0; $i < count($this->_complete_forms); $i++) {
|
||||
if ($this->_complete_forms[$i]->getId() == $id) {
|
||||
return $this->_complete_forms[$i];
|
||||
}
|
||||
}
|
||||
$null = null;
|
||||
return $null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a field on each form in which the field is
|
||||
* available.
|
||||
* @param SimpleSelector $selector Field finder.
|
||||
* @param string $value Value to set field to.
|
||||
* @return boolean True if value is valid.
|
||||
* @access public
|
||||
*/
|
||||
function setField($selector, $value, $position=false) {
|
||||
$is_set = false;
|
||||
for ($i = 0; $i < count($this->_complete_forms); $i++) {
|
||||
if ($this->_complete_forms[$i]->setField($selector, $value, $position)) {
|
||||
$is_set = true;
|
||||
}
|
||||
}
|
||||
return $is_set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for a form element value within a page.
|
||||
* @param SimpleSelector $selector Field finder.
|
||||
* @return string/boolean A string if the field is
|
||||
* present, false if unchecked
|
||||
* and null if missing.
|
||||
* @access public
|
||||
*/
|
||||
function getField($selector) {
|
||||
for ($i = 0; $i < count($this->_complete_forms); $i++) {
|
||||
$value = $this->_complete_forms[$i]->getValue($selector);
|
||||
if (isset($value)) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
?>
|
764
thirdparty/simpletest/parser.php
vendored
Normal file
764
thirdparty/simpletest/parser.php
vendored
Normal file
@ -0,0 +1,764 @@
|
||||
<?php
|
||||
/**
|
||||
* base include file for SimpleTest
|
||||
* @package SimpleTest
|
||||
* @subpackage MockObjects
|
||||
* @version $Id: parser.php 1723 2008-04-08 00:34:10Z lastcraft $
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
* Lexer mode stack constants
|
||||
*/
|
||||
foreach (array('LEXER_ENTER', 'LEXER_MATCHED',
|
||||
'LEXER_UNMATCHED', 'LEXER_EXIT',
|
||||
'LEXER_SPECIAL') as $i => $constant) {
|
||||
if (! defined($constant)) {
|
||||
define($constant, $i + 1);
|
||||
}
|
||||
}
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Compounded regular expression. Any of
|
||||
* the contained patterns could match and
|
||||
* when one does, it's label is returned.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class ParallelRegex {
|
||||
var $_patterns;
|
||||
var $_labels;
|
||||
var $_regex;
|
||||
var $_case;
|
||||
|
||||
/**
|
||||
* Constructor. Starts with no patterns.
|
||||
* @param boolean $case True for case sensitive, false
|
||||
* for insensitive.
|
||||
* @access public
|
||||
*/
|
||||
function ParallelRegex($case) {
|
||||
$this->_case = $case;
|
||||
$this->_patterns = array();
|
||||
$this->_labels = array();
|
||||
$this->_regex = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a pattern with an optional label.
|
||||
* @param string $pattern Perl style regex, but ( and )
|
||||
* lose the usual meaning.
|
||||
* @param string $label Label of regex to be returned
|
||||
* on a match.
|
||||
* @access public
|
||||
*/
|
||||
function addPattern($pattern, $label = true) {
|
||||
$count = count($this->_patterns);
|
||||
$this->_patterns[$count] = $pattern;
|
||||
$this->_labels[$count] = $label;
|
||||
$this->_regex = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to match all patterns at once against
|
||||
* a string.
|
||||
* @param string $subject String to match against.
|
||||
* @param string $match First matched portion of
|
||||
* subject.
|
||||
* @return boolean True on success.
|
||||
* @access public
|
||||
*/
|
||||
function match($subject, &$match) {
|
||||
if (count($this->_patterns) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (! preg_match($this->_getCompoundedRegex(), $subject, $matches)) {
|
||||
$match = '';
|
||||
return false;
|
||||
}
|
||||
$match = $matches[0];
|
||||
for ($i = 1; $i < count($matches); $i++) {
|
||||
if ($matches[$i]) {
|
||||
return $this->_labels[$i - 1];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compounds the patterns into a single
|
||||
* regular expression separated with the
|
||||
* "or" operator. Caches the regex.
|
||||
* Will automatically escape (, ) and / tokens.
|
||||
* @param array $patterns List of patterns in order.
|
||||
* @access private
|
||||
*/
|
||||
function _getCompoundedRegex() {
|
||||
if ($this->_regex == null) {
|
||||
for ($i = 0, $count = count($this->_patterns); $i < $count; $i++) {
|
||||
$this->_patterns[$i] = '(' . str_replace(
|
||||
array('/', '(', ')'),
|
||||
array('\/', '\(', '\)'),
|
||||
$this->_patterns[$i]) . ')';
|
||||
}
|
||||
$this->_regex = "/" . implode("|", $this->_patterns) . "/" . $this->_getPerlMatchingFlags();
|
||||
}
|
||||
return $this->_regex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for perl regex mode flags to use.
|
||||
* @return string Perl regex flags.
|
||||
* @access private
|
||||
*/
|
||||
function _getPerlMatchingFlags() {
|
||||
return ($this->_case ? "msS" : "msSi");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* States for a stack machine.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleStateStack {
|
||||
var $_stack;
|
||||
|
||||
/**
|
||||
* Constructor. Starts in named state.
|
||||
* @param string $start Starting state name.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleStateStack($start) {
|
||||
$this->_stack = array($start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for current state.
|
||||
* @return string State.
|
||||
* @access public
|
||||
*/
|
||||
function getCurrent() {
|
||||
return $this->_stack[count($this->_stack) - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a state to the stack and sets it
|
||||
* to be the current state.
|
||||
* @param string $state New state.
|
||||
* @access public
|
||||
*/
|
||||
function enter($state) {
|
||||
array_push($this->_stack, $state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves the current state and reverts
|
||||
* to the previous one.
|
||||
* @return boolean False if we drop off
|
||||
* the bottom of the list.
|
||||
* @access public
|
||||
*/
|
||||
function leave() {
|
||||
if (count($this->_stack) == 1) {
|
||||
return false;
|
||||
}
|
||||
array_pop($this->_stack);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts text and breaks it into tokens.
|
||||
* Some optimisation to make the sure the
|
||||
* content is only scanned by the PHP regex
|
||||
* parser once. Lexer modes must not start
|
||||
* with leading underscores.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleLexer {
|
||||
var $_regexes;
|
||||
var $_parser;
|
||||
var $_mode;
|
||||
var $_mode_handlers;
|
||||
var $_case;
|
||||
|
||||
/**
|
||||
* Sets up the lexer in case insensitive matching
|
||||
* by default.
|
||||
* @param SimpleSaxParser $parser Handling strategy by
|
||||
* reference.
|
||||
* @param string $start Starting handler.
|
||||
* @param boolean $case True for case sensitive.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleLexer(&$parser, $start = "accept", $case = false) {
|
||||
$this->_case = $case;
|
||||
$this->_regexes = array();
|
||||
$this->_parser = &$parser;
|
||||
$this->_mode = &new SimpleStateStack($start);
|
||||
$this->_mode_handlers = array($start => $start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a token search pattern for a particular
|
||||
* parsing mode. The pattern does not change the
|
||||
* current mode.
|
||||
* @param string $pattern Perl style regex, but ( and )
|
||||
* lose the usual meaning.
|
||||
* @param string $mode Should only apply this
|
||||
* pattern when dealing with
|
||||
* this type of input.
|
||||
* @access public
|
||||
*/
|
||||
function addPattern($pattern, $mode = "accept") {
|
||||
if (! isset($this->_regexes[$mode])) {
|
||||
$this->_regexes[$mode] = new ParallelRegex($this->_case);
|
||||
}
|
||||
$this->_regexes[$mode]->addPattern($pattern);
|
||||
if (! isset($this->_mode_handlers[$mode])) {
|
||||
$this->_mode_handlers[$mode] = $mode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a pattern that will enter a new parsing
|
||||
* mode. Useful for entering parenthesis, strings,
|
||||
* tags, etc.
|
||||
* @param string $pattern Perl style regex, but ( and )
|
||||
* lose the usual meaning.
|
||||
* @param string $mode Should only apply this
|
||||
* pattern when dealing with
|
||||
* this type of input.
|
||||
* @param string $new_mode Change parsing to this new
|
||||
* nested mode.
|
||||
* @access public
|
||||
*/
|
||||
function addEntryPattern($pattern, $mode, $new_mode) {
|
||||
if (! isset($this->_regexes[$mode])) {
|
||||
$this->_regexes[$mode] = new ParallelRegex($this->_case);
|
||||
}
|
||||
$this->_regexes[$mode]->addPattern($pattern, $new_mode);
|
||||
if (! isset($this->_mode_handlers[$new_mode])) {
|
||||
$this->_mode_handlers[$new_mode] = $new_mode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a pattern that will exit the current mode
|
||||
* and re-enter the previous one.
|
||||
* @param string $pattern Perl style regex, but ( and )
|
||||
* lose the usual meaning.
|
||||
* @param string $mode Mode to leave.
|
||||
* @access public
|
||||
*/
|
||||
function addExitPattern($pattern, $mode) {
|
||||
if (! isset($this->_regexes[$mode])) {
|
||||
$this->_regexes[$mode] = new ParallelRegex($this->_case);
|
||||
}
|
||||
$this->_regexes[$mode]->addPattern($pattern, "__exit");
|
||||
if (! isset($this->_mode_handlers[$mode])) {
|
||||
$this->_mode_handlers[$mode] = $mode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a pattern that has a special mode. Acts as an entry
|
||||
* and exit pattern in one go, effectively calling a special
|
||||
* parser handler for this token only.
|
||||
* @param string $pattern Perl style regex, but ( and )
|
||||
* lose the usual meaning.
|
||||
* @param string $mode Should only apply this
|
||||
* pattern when dealing with
|
||||
* this type of input.
|
||||
* @param string $special Use this mode for this one token.
|
||||
* @access public
|
||||
*/
|
||||
function addSpecialPattern($pattern, $mode, $special) {
|
||||
if (! isset($this->_regexes[$mode])) {
|
||||
$this->_regexes[$mode] = new ParallelRegex($this->_case);
|
||||
}
|
||||
$this->_regexes[$mode]->addPattern($pattern, "_$special");
|
||||
if (! isset($this->_mode_handlers[$special])) {
|
||||
$this->_mode_handlers[$special] = $special;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mapping from a mode to another handler.
|
||||
* @param string $mode Mode to be remapped.
|
||||
* @param string $handler New target handler.
|
||||
* @access public
|
||||
*/
|
||||
function mapHandler($mode, $handler) {
|
||||
$this->_mode_handlers[$mode] = $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits the page text into tokens. Will fail
|
||||
* if the handlers report an error or if no
|
||||
* content is consumed. If successful then each
|
||||
* unparsed and parsed token invokes a call to the
|
||||
* held listener.
|
||||
* @param string $raw Raw HTML text.
|
||||
* @return boolean True on success, else false.
|
||||
* @access public
|
||||
*/
|
||||
function parse($raw) {
|
||||
if (! isset($this->_parser)) {
|
||||
return false;
|
||||
}
|
||||
$length = strlen($raw);
|
||||
while (is_array($parsed = $this->_reduce($raw))) {
|
||||
list($raw, $unmatched, $matched, $mode) = $parsed;
|
||||
if (! $this->_dispatchTokens($unmatched, $matched, $mode)) {
|
||||
return false;
|
||||
}
|
||||
if ($raw === '') {
|
||||
return true;
|
||||
}
|
||||
if (strlen($raw) == $length) {
|
||||
return false;
|
||||
}
|
||||
$length = strlen($raw);
|
||||
}
|
||||
if (! $parsed) {
|
||||
return false;
|
||||
}
|
||||
return $this->_invokeParser($raw, LEXER_UNMATCHED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the matched token and any leading unmatched
|
||||
* text to the parser changing the lexer to a new
|
||||
* mode if one is listed.
|
||||
* @param string $unmatched Unmatched leading portion.
|
||||
* @param string $matched Actual token match.
|
||||
* @param string $mode Mode after match. A boolean
|
||||
* false mode causes no change.
|
||||
* @return boolean False if there was any error
|
||||
* from the parser.
|
||||
* @access private
|
||||
*/
|
||||
function _dispatchTokens($unmatched, $matched, $mode = false) {
|
||||
if (! $this->_invokeParser($unmatched, LEXER_UNMATCHED)) {
|
||||
return false;
|
||||
}
|
||||
if (is_bool($mode)) {
|
||||
return $this->_invokeParser($matched, LEXER_MATCHED);
|
||||
}
|
||||
if ($this->_isModeEnd($mode)) {
|
||||
if (! $this->_invokeParser($matched, LEXER_EXIT)) {
|
||||
return false;
|
||||
}
|
||||
return $this->_mode->leave();
|
||||
}
|
||||
if ($this->_isSpecialMode($mode)) {
|
||||
$this->_mode->enter($this->_decodeSpecial($mode));
|
||||
if (! $this->_invokeParser($matched, LEXER_SPECIAL)) {
|
||||
return false;
|
||||
}
|
||||
return $this->_mode->leave();
|
||||
}
|
||||
$this->_mode->enter($mode);
|
||||
return $this->_invokeParser($matched, LEXER_ENTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if the new mode is actually to leave
|
||||
* the current mode and pop an item from the matching
|
||||
* mode stack.
|
||||
* @param string $mode Mode to test.
|
||||
* @return boolean True if this is the exit mode.
|
||||
* @access private
|
||||
*/
|
||||
function _isModeEnd($mode) {
|
||||
return ($mode === "__exit");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the mode is one where this mode
|
||||
* is entered for this token only and automatically
|
||||
* leaves immediately afterwoods.
|
||||
* @param string $mode Mode to test.
|
||||
* @return boolean True if this is the exit mode.
|
||||
* @access private
|
||||
*/
|
||||
function _isSpecialMode($mode) {
|
||||
return (strncmp($mode, "_", 1) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips the magic underscore marking single token
|
||||
* modes.
|
||||
* @param string $mode Mode to decode.
|
||||
* @return string Underlying mode name.
|
||||
* @access private
|
||||
*/
|
||||
function _decodeSpecial($mode) {
|
||||
return substr($mode, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the parser method named after the current
|
||||
* mode. Empty content will be ignored. The lexer
|
||||
* has a parser handler for each mode in the lexer.
|
||||
* @param string $content Text parsed.
|
||||
* @param boolean $is_match Token is recognised rather
|
||||
* than unparsed data.
|
||||
* @access private
|
||||
*/
|
||||
function _invokeParser($content, $is_match) {
|
||||
if (($content === '') || ($content === false)) {
|
||||
return true;
|
||||
}
|
||||
$handler = $this->_mode_handlers[$this->_mode->getCurrent()];
|
||||
return $this->_parser->$handler($content, $is_match);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to match a chunk of text and if successful
|
||||
* removes the recognised chunk and any leading
|
||||
* unparsed data. Empty strings will not be matched.
|
||||
* @param string $raw The subject to parse. This is the
|
||||
* content that will be eaten.
|
||||
* @return array/boolean Three item list of unparsed
|
||||
* content followed by the
|
||||
* recognised token and finally the
|
||||
* action the parser is to take.
|
||||
* True if no match, false if there
|
||||
* is a parsing error.
|
||||
* @access private
|
||||
*/
|
||||
function _reduce($raw) {
|
||||
if ($action = $this->_regexes[$this->_mode->getCurrent()]->match($raw, $match)) {
|
||||
$unparsed_character_count = strpos($raw, $match);
|
||||
$unparsed = substr($raw, 0, $unparsed_character_count);
|
||||
$raw = substr($raw, $unparsed_character_count + strlen($match));
|
||||
return array($raw, $unparsed, $match, $action);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Breaks HTML into SAX events.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleHtmlLexer extends SimpleLexer {
|
||||
|
||||
/**
|
||||
* Sets up the lexer with case insensitive matching
|
||||
* and adds the HTML handlers.
|
||||
* @param SimpleSaxParser $parser Handling strategy by
|
||||
* reference.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleHtmlLexer(&$parser) {
|
||||
$this->SimpleLexer($parser, 'text');
|
||||
$this->mapHandler('text', 'acceptTextToken');
|
||||
$this->_addSkipping();
|
||||
foreach ($this->_getParsedTags() as $tag) {
|
||||
$this->_addTag($tag);
|
||||
}
|
||||
$this->_addInTagTokens();
|
||||
}
|
||||
|
||||
/**
|
||||
* List of parsed tags. Others are ignored.
|
||||
* @return array List of searched for tags.
|
||||
* @access private
|
||||
*/
|
||||
function _getParsedTags() {
|
||||
return array('a', 'base', 'title', 'form', 'input', 'button', 'textarea', 'select',
|
||||
'option', 'frameset', 'frame', 'label');
|
||||
}
|
||||
|
||||
/**
|
||||
* The lexer has to skip certain sections such
|
||||
* as server code, client code and styles.
|
||||
* @access private
|
||||
*/
|
||||
function _addSkipping() {
|
||||
$this->mapHandler('css', 'ignore');
|
||||
$this->addEntryPattern('<style', 'text', 'css');
|
||||
$this->addExitPattern('</style>', 'css');
|
||||
$this->mapHandler('js', 'ignore');
|
||||
$this->addEntryPattern('<script', 'text', 'js');
|
||||
$this->addExitPattern('</script>', 'js');
|
||||
$this->mapHandler('comment', 'ignore');
|
||||
$this->addEntryPattern('<!--', 'text', 'comment');
|
||||
$this->addExitPattern('-->', 'comment');
|
||||
}
|
||||
|
||||
/**
|
||||
* Pattern matches to start and end a tag.
|
||||
* @param string $tag Name of tag to scan for.
|
||||
* @access private
|
||||
*/
|
||||
function _addTag($tag) {
|
||||
$this->addSpecialPattern("</$tag>", 'text', 'acceptEndToken');
|
||||
$this->addEntryPattern("<$tag", 'text', 'tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Pattern matches to parse the inside of a tag
|
||||
* including the attributes and their quoting.
|
||||
* @access private
|
||||
*/
|
||||
function _addInTagTokens() {
|
||||
$this->mapHandler('tag', 'acceptStartToken');
|
||||
$this->addSpecialPattern('\s+', 'tag', 'ignore');
|
||||
$this->_addAttributeTokens();
|
||||
$this->addExitPattern('/>', 'tag');
|
||||
$this->addExitPattern('>', 'tag');
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches attributes that are either single quoted,
|
||||
* double quoted or unquoted.
|
||||
* @access private
|
||||
*/
|
||||
function _addAttributeTokens() {
|
||||
$this->mapHandler('dq_attribute', 'acceptAttributeToken');
|
||||
$this->addEntryPattern('=\s*"', 'tag', 'dq_attribute');
|
||||
$this->addPattern("\\\\\"", 'dq_attribute');
|
||||
$this->addExitPattern('"', 'dq_attribute');
|
||||
$this->mapHandler('sq_attribute', 'acceptAttributeToken');
|
||||
$this->addEntryPattern("=\s*'", 'tag', 'sq_attribute');
|
||||
$this->addPattern("\\\\'", 'sq_attribute');
|
||||
$this->addExitPattern("'", 'sq_attribute');
|
||||
$this->mapHandler('uq_attribute', 'acceptAttributeToken');
|
||||
$this->addSpecialPattern('=\s*[^>\s]*', 'tag', 'uq_attribute');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts HTML tokens into selected SAX events.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleHtmlSaxParser {
|
||||
var $_lexer;
|
||||
var $_listener;
|
||||
var $_tag;
|
||||
var $_attributes;
|
||||
var $_current_attribute;
|
||||
|
||||
/**
|
||||
* Sets the listener.
|
||||
* @param SimpleSaxListener $listener SAX event handler.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleHtmlSaxParser(&$listener) {
|
||||
$this->_listener = &$listener;
|
||||
$this->_lexer = &$this->createLexer($this);
|
||||
$this->_tag = '';
|
||||
$this->_attributes = array();
|
||||
$this->_current_attribute = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the content through the lexer which
|
||||
* should call back to the acceptors.
|
||||
* @param string $raw Page text to parse.
|
||||
* @return boolean False if parse error.
|
||||
* @access public
|
||||
*/
|
||||
function parse($raw) {
|
||||
return $this->_lexer->parse($raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the matching lexer. Starts in 'text' mode.
|
||||
* @param SimpleSaxParser $parser Event generator, usually $self.
|
||||
* @return SimpleLexer Lexer suitable for this parser.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function &createLexer(&$parser) {
|
||||
$lexer = &new SimpleHtmlLexer($parser);
|
||||
return $lexer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a token from the tag mode. If the
|
||||
* starting element completes then the element
|
||||
* is dispatched and the current attributes
|
||||
* set back to empty. The element or attribute
|
||||
* name is converted to lower case.
|
||||
* @param string $token Incoming characters.
|
||||
* @param integer $event Lexer event type.
|
||||
* @return boolean False if parse error.
|
||||
* @access public
|
||||
*/
|
||||
function acceptStartToken($token, $event) {
|
||||
if ($event == LEXER_ENTER) {
|
||||
$this->_tag = strtolower(substr($token, 1));
|
||||
return true;
|
||||
}
|
||||
if ($event == LEXER_EXIT) {
|
||||
$success = $this->_listener->startElement(
|
||||
$this->_tag,
|
||||
$this->_attributes);
|
||||
$this->_tag = '';
|
||||
$this->_attributes = array();
|
||||
return $success;
|
||||
}
|
||||
if ($token != '=') {
|
||||
$this->_current_attribute = strtolower(SimpleHtmlSaxParser::decodeHtml($token));
|
||||
$this->_attributes[$this->_current_attribute] = '';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts a token from the end tag mode.
|
||||
* The element name is converted to lower case.
|
||||
* @param string $token Incoming characters.
|
||||
* @param integer $event Lexer event type.
|
||||
* @return boolean False if parse error.
|
||||
* @access public
|
||||
*/
|
||||
function acceptEndToken($token, $event) {
|
||||
if (! preg_match('/<\/(.*)>/', $token, $matches)) {
|
||||
return false;
|
||||
}
|
||||
return $this->_listener->endElement(strtolower($matches[1]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of the tag data.
|
||||
* @param string $token Incoming characters.
|
||||
* @param integer $event Lexer event type.
|
||||
* @return boolean False if parse error.
|
||||
* @access public
|
||||
*/
|
||||
function acceptAttributeToken($token, $event) {
|
||||
if ($this->_current_attribute) {
|
||||
if ($event == LEXER_UNMATCHED) {
|
||||
$this->_attributes[$this->_current_attribute] .=
|
||||
SimpleHtmlSaxParser::decodeHtml($token);
|
||||
}
|
||||
if ($event == LEXER_SPECIAL) {
|
||||
$this->_attributes[$this->_current_attribute] .=
|
||||
preg_replace('/^=\s*/' , '', SimpleHtmlSaxParser::decodeHtml($token));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A character entity.
|
||||
* @param string $token Incoming characters.
|
||||
* @param integer $event Lexer event type.
|
||||
* @return boolean False if parse error.
|
||||
* @access public
|
||||
*/
|
||||
function acceptEntityToken($token, $event) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Character data between tags regarded as
|
||||
* important.
|
||||
* @param string $token Incoming characters.
|
||||
* @param integer $event Lexer event type.
|
||||
* @return boolean False if parse error.
|
||||
* @access public
|
||||
*/
|
||||
function acceptTextToken($token, $event) {
|
||||
return $this->_listener->addContent($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming data to be ignored.
|
||||
* @param string $token Incoming characters.
|
||||
* @param integer $event Lexer event type.
|
||||
* @return boolean False if parse error.
|
||||
* @access public
|
||||
*/
|
||||
function ignore($token, $event) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes any HTML entities.
|
||||
* @param string $html Incoming HTML.
|
||||
* @return string Outgoing plain text.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function decodeHtml($html) {
|
||||
return html_entity_decode($html, ENT_QUOTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns HTML into text browser visible text. Images
|
||||
* are converted to their alt text and tags are supressed.
|
||||
* Entities are converted to their visible representation.
|
||||
* @param string $html HTML to convert.
|
||||
* @return string Plain text.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function normalise($html) {
|
||||
$text = preg_replace('|<!--.*?-->|', '', $html);
|
||||
$text = preg_replace('|<script[^>]*>.*?</script>|', '', $text);
|
||||
$text = preg_replace('|<img[^>]*alt\s*=\s*"([^"]*)"[^>]*>|', ' \1 ', $text);
|
||||
$text = preg_replace('|<img[^>]*alt\s*=\s*\'([^\']*)\'[^>]*>|', ' \1 ', $text);
|
||||
$text = preg_replace('|<img[^>]*alt\s*=\s*([a-zA-Z_]+)[^>]*>|', ' \1 ', $text);
|
||||
$text = preg_replace('|<[^>]*>|', '', $text);
|
||||
$text = SimpleHtmlSaxParser::decodeHtml($text);
|
||||
$text = preg_replace('|\s+|', ' ', $text);
|
||||
return trim(trim($text), "\xA0"); // TODO: The \xAO is a . Add a test for this.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SAX event handler.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
* @abstract
|
||||
*/
|
||||
class SimpleSaxListener {
|
||||
|
||||
/**
|
||||
* Sets the document to write to.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleSaxListener() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Start of element event.
|
||||
* @param string $name Element name.
|
||||
* @param hash $attributes Name value pairs.
|
||||
* Attributes without content
|
||||
* are marked as true.
|
||||
* @return boolean False on parse error.
|
||||
* @access public
|
||||
*/
|
||||
function startElement($name, $attributes) {
|
||||
}
|
||||
|
||||
/**
|
||||
* End of element event.
|
||||
* @param string $name Element name.
|
||||
* @return boolean False on parse error.
|
||||
* @access public
|
||||
*/
|
||||
function endElement($name) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unparsed, but relevant data.
|
||||
* @param string $text May include unparsed tags.
|
||||
* @return boolean False on parse error.
|
||||
* @access public
|
||||
*/
|
||||
function addContent($text) {
|
||||
}
|
||||
}
|
||||
?>
|
137
thirdparty/simpletest/selector.php
vendored
Normal file
137
thirdparty/simpletest/selector.php
vendored
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
* Base include file for SimpleTest.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
* @version $Id: selector.php 1723 2008-04-08 00:34:10Z lastcraft $
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
* include SimpleTest files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/tag.php');
|
||||
require_once(dirname(__FILE__) . '/encoding.php');
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Used to extract form elements for testing against.
|
||||
* Searches by name attribute.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleByName {
|
||||
var $_name;
|
||||
|
||||
/**
|
||||
* Stashes the name for later comparison.
|
||||
* @param string $name Name attribute to match.
|
||||
*/
|
||||
function SimpleByName($name) {
|
||||
$this->_name = $name;
|
||||
}
|
||||
|
||||
function getName() {
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares with name attribute of widget.
|
||||
* @param SimpleWidget $widget Control to compare.
|
||||
* @access public
|
||||
*/
|
||||
function isMatch($widget) {
|
||||
return ($widget->getName() == $this->_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to extract form elements for testing against.
|
||||
* Searches by visible label or alt text.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleByLabel {
|
||||
var $_label;
|
||||
|
||||
/**
|
||||
* Stashes the name for later comparison.
|
||||
* @param string $label Visible text to match.
|
||||
*/
|
||||
function SimpleByLabel($label) {
|
||||
$this->_label = $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison. Compares visible text of widget or
|
||||
* related label.
|
||||
* @param SimpleWidget $widget Control to compare.
|
||||
* @access public
|
||||
*/
|
||||
function isMatch($widget) {
|
||||
if (! method_exists($widget, 'isLabel')) {
|
||||
return false;
|
||||
}
|
||||
return $widget->isLabel($this->_label);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to extract form elements for testing against.
|
||||
* Searches dy id attribute.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleById {
|
||||
var $_id;
|
||||
|
||||
/**
|
||||
* Stashes the name for later comparison.
|
||||
* @param string $id ID atribute to match.
|
||||
*/
|
||||
function SimpleById($id) {
|
||||
$this->_id = $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison. Compares id attribute of widget.
|
||||
* @param SimpleWidget $widget Control to compare.
|
||||
* @access public
|
||||
*/
|
||||
function isMatch($widget) {
|
||||
return $widget->isId($this->_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to extract form elements for testing against.
|
||||
* Searches by visible label, name or alt text.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleByLabelOrName {
|
||||
var $_label;
|
||||
|
||||
/**
|
||||
* Stashes the name/label for later comparison.
|
||||
* @param string $label Visible text to match.
|
||||
*/
|
||||
function SimpleByLabelOrName($label) {
|
||||
$this->_label = $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison. Compares visible text of widget or
|
||||
* related label or name.
|
||||
* @param SimpleWidget $widget Control to compare.
|
||||
* @access public
|
||||
*/
|
||||
function isMatch($widget) {
|
||||
if (method_exists($widget, 'isLabel')) {
|
||||
if ($widget->isLabel($this->_label)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return ($widget->getName() == $this->_label);
|
||||
}
|
||||
}
|
||||
?>
|
216
thirdparty/simpletest/socket.php
vendored
Normal file
216
thirdparty/simpletest/socket.php
vendored
Normal file
@ -0,0 +1,216 @@
|
||||
<?php
|
||||
/**
|
||||
* base include file for SimpleTest
|
||||
* @package SimpleTest
|
||||
* @subpackage MockObjects
|
||||
* @version $Id: socket.php 1723 2008-04-08 00:34:10Z lastcraft $
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
* include SimpleTest files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/compatibility.php');
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Stashes an error for later. Useful for constructors
|
||||
* until PHP gets exceptions.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleStickyError {
|
||||
var $_error = 'Constructor not chained';
|
||||
|
||||
/**
|
||||
* Sets the error to empty.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleStickyError() {
|
||||
$this->_clearError();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for an outstanding error.
|
||||
* @return boolean True if there is an error.
|
||||
* @access public
|
||||
*/
|
||||
function isError() {
|
||||
return ($this->_error != '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for an outstanding error.
|
||||
* @return string Empty string if no error otherwise
|
||||
* the error message.
|
||||
* @access public
|
||||
*/
|
||||
function getError() {
|
||||
return $this->_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the internal error.
|
||||
* @param string Error message to stash.
|
||||
* @access protected
|
||||
*/
|
||||
function _setError($error) {
|
||||
$this->_error = $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the error state to no error.
|
||||
* @access protected
|
||||
*/
|
||||
function _clearError() {
|
||||
$this->_setError('');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for TCP/IP socket.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleSocket extends SimpleStickyError {
|
||||
var $_handle;
|
||||
var $_is_open = false;
|
||||
var $_sent = '';
|
||||
var $lock_size;
|
||||
|
||||
/**
|
||||
* Opens a socket for reading and writing.
|
||||
* @param string $host Hostname to send request to.
|
||||
* @param integer $port Port on remote machine to open.
|
||||
* @param integer $timeout Connection timeout in seconds.
|
||||
* @param integer $block_size Size of chunk to read.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleSocket($host, $port, $timeout, $block_size = 255) {
|
||||
$this->SimpleStickyError();
|
||||
if (! ($this->_handle = $this->_openSocket($host, $port, $error_number, $error, $timeout))) {
|
||||
$this->_setError("Cannot open [$host:$port] with [$error] within [$timeout] seconds");
|
||||
return;
|
||||
}
|
||||
$this->_is_open = true;
|
||||
$this->_block_size = $block_size;
|
||||
SimpleTestCompatibility::setTimeout($this->_handle, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes some data to the socket and saves alocal copy.
|
||||
* @param string $message String to send to socket.
|
||||
* @return boolean True if successful.
|
||||
* @access public
|
||||
*/
|
||||
function write($message) {
|
||||
if ($this->isError() || ! $this->isOpen()) {
|
||||
return false;
|
||||
}
|
||||
$count = fwrite($this->_handle, $message);
|
||||
if (! $count) {
|
||||
if ($count === false) {
|
||||
$this->_setError('Cannot write to socket');
|
||||
$this->close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
fflush($this->_handle);
|
||||
$this->_sent .= $message;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from the socket. The error suppresion
|
||||
* is a workaround for PHP4 always throwing a warning
|
||||
* with a secure socket.
|
||||
* @return integer/boolean Incoming bytes. False
|
||||
* on error.
|
||||
* @access public
|
||||
*/
|
||||
function read() {
|
||||
if ($this->isError() || ! $this->isOpen()) {
|
||||
return false;
|
||||
}
|
||||
$raw = @fread($this->_handle, $this->_block_size);
|
||||
if ($raw === false) {
|
||||
$this->_setError('Cannot read from socket');
|
||||
$this->close();
|
||||
}
|
||||
return $raw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for socket open state.
|
||||
* @return boolean True if open.
|
||||
* @access public
|
||||
*/
|
||||
function isOpen() {
|
||||
return $this->_is_open;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the socket preventing further reads.
|
||||
* Cannot be reopened once closed.
|
||||
* @return boolean True if successful.
|
||||
* @access public
|
||||
*/
|
||||
function close() {
|
||||
$this->_is_open = false;
|
||||
return fclose($this->_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for content so far.
|
||||
* @return string Bytes sent only.
|
||||
* @access public
|
||||
*/
|
||||
function getSent() {
|
||||
return $this->_sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually opens the low level socket.
|
||||
* @param string $host Host to connect to.
|
||||
* @param integer $port Port on host.
|
||||
* @param integer $error_number Recipient of error code.
|
||||
* @param string $error Recipoent of error message.
|
||||
* @param integer $timeout Maximum time to wait for connection.
|
||||
* @access protected
|
||||
*/
|
||||
function _openSocket($host, $port, &$error_number, &$error, $timeout) {
|
||||
return @fsockopen($host, $port, $error_number, $error, $timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for TCP/IP socket over TLS.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleSecureSocket extends SimpleSocket {
|
||||
|
||||
/**
|
||||
* Opens a secure socket for reading and writing.
|
||||
* @param string $host Hostname to send request to.
|
||||
* @param integer $port Port on remote machine to open.
|
||||
* @param integer $timeout Connection timeout in seconds.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleSecureSocket($host, $port, $timeout) {
|
||||
$this->SimpleSocket($host, $port, $timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually opens the low level socket.
|
||||
* @param string $host Host to connect to.
|
||||
* @param integer $port Port on host.
|
||||
* @param integer $error_number Recipient of error code.
|
||||
* @param string $error Recipient of error message.
|
||||
* @param integer $timeout Maximum time to wait for connection.
|
||||
* @access protected
|
||||
*/
|
||||
function _openSocket($host, $port, &$error_number, &$error, $timeout) {
|
||||
return parent::_openSocket("tls://$host", $port, $error_number, $error, $timeout);
|
||||
}
|
||||
}
|
||||
?>
|
1418
thirdparty/simpletest/tag.php
vendored
Normal file
1418
thirdparty/simpletest/tag.php
vendored
Normal file
@ -0,0 +1,1418 @@
|
||||
<?php
|
||||
/**
|
||||
* Base include file for SimpleTest.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
* @version $Id: tag.php 1723 2008-04-08 00:34:10Z lastcraft $
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
* include SimpleTest files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/parser.php');
|
||||
require_once(dirname(__FILE__) . '/encoding.php');
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* HTML or XML tag.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleTag {
|
||||
var $_name;
|
||||
var $_attributes;
|
||||
var $_content;
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* @param string $name Tag name.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values. Note that
|
||||
* the keys must have been
|
||||
* converted to lower case.
|
||||
*/
|
||||
function SimpleTag($name, $attributes) {
|
||||
$this->_name = strtolower(trim($name));
|
||||
$this->_attributes = $attributes;
|
||||
$this->_content = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the tag can have both start and
|
||||
* end tags with content in between.
|
||||
* @return boolean True if content allowed.
|
||||
* @access public
|
||||
*/
|
||||
function expectEndTag() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current tag should not swallow all content for
|
||||
* itself as it's searchable page content. Private
|
||||
* content tags are usually widgets that contain default
|
||||
* values.
|
||||
* @return boolean False as content is available
|
||||
* to other tags by default.
|
||||
* @access public
|
||||
*/
|
||||
function isPrivateContent() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends string content to the current content.
|
||||
* @param string $content Additional text.
|
||||
* @access public
|
||||
*/
|
||||
function addContent($content) {
|
||||
$this->_content .= (string)$content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an enclosed tag to the content.
|
||||
* @param SimpleTag $tag New tag.
|
||||
* @access public
|
||||
*/
|
||||
function addTag(&$tag) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for tag name.
|
||||
* @return string Name of tag.
|
||||
* @access public
|
||||
*/
|
||||
function getTagName() {
|
||||
return $this->_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of legal child elements.
|
||||
* @return array List of element names.
|
||||
* @access public
|
||||
*/
|
||||
function getChildElements() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for an attribute.
|
||||
* @param string $label Attribute name.
|
||||
* @return string Attribute value.
|
||||
* @access public
|
||||
*/
|
||||
function getAttribute($label) {
|
||||
$label = strtolower($label);
|
||||
if (! isset($this->_attributes[$label])) {
|
||||
return false;
|
||||
}
|
||||
return (string)$this->_attributes[$label];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an attribute.
|
||||
* @param string $label Attribute name.
|
||||
* @return string $value New attribute value.
|
||||
* @access protected
|
||||
*/
|
||||
function _setAttribute($label, $value) {
|
||||
$this->_attributes[strtolower($label)] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the whole content so far.
|
||||
* @return string Content as big raw string.
|
||||
* @access public
|
||||
*/
|
||||
function getContent() {
|
||||
return $this->_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for content reduced to visible text. Acts
|
||||
* like a text mode browser, normalising space and
|
||||
* reducing images to their alt text.
|
||||
* @return string Content as plain text.
|
||||
* @access public
|
||||
*/
|
||||
function getText() {
|
||||
return SimpleHtmlSaxParser::normalise($this->_content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if id attribute matches.
|
||||
* @param string $id ID to test against.
|
||||
* @return boolean True on match.
|
||||
* @access public
|
||||
*/
|
||||
function isId($id) {
|
||||
return ($this->getAttribute('id') == $id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base url.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleBaseTag extends SimpleTag {
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleBaseTag($attributes) {
|
||||
$this->SimpleTag('base', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base tag is not a block tag.
|
||||
* @return boolean false
|
||||
* @access public
|
||||
*/
|
||||
function expectEndTag() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Page title.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleTitleTag extends SimpleTag {
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleTitleTag($attributes) {
|
||||
$this->SimpleTag('title', $attributes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Link.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleAnchorTag extends SimpleTag {
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleAnchorTag($attributes) {
|
||||
$this->SimpleTag('a', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for URL as string.
|
||||
* @return string Coerced as string.
|
||||
* @access public
|
||||
*/
|
||||
function getHref() {
|
||||
$url = $this->getAttribute('href');
|
||||
if (is_bool($url)) {
|
||||
$url = '';
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form element.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleWidget extends SimpleTag {
|
||||
var $_value;
|
||||
var $_label;
|
||||
var $_is_set;
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* @param string $name Tag name.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleWidget($name, $attributes) {
|
||||
$this->SimpleTag($name, $attributes);
|
||||
$this->_value = false;
|
||||
$this->_label = false;
|
||||
$this->_is_set = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for name submitted as the key in
|
||||
* GET/POST variables hash.
|
||||
* @return string Parsed value.
|
||||
* @access public
|
||||
*/
|
||||
function getName() {
|
||||
return $this->getAttribute('name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for default value parsed with the tag.
|
||||
* @return string Parsed value.
|
||||
* @access public
|
||||
*/
|
||||
function getDefault() {
|
||||
return $this->getAttribute('value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for currently set value or default if
|
||||
* none.
|
||||
* @return string Value set by form or default
|
||||
* if none.
|
||||
* @access public
|
||||
*/
|
||||
function getValue() {
|
||||
if (! $this->_is_set) {
|
||||
return $this->getDefault();
|
||||
}
|
||||
return $this->_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current form element value.
|
||||
* @param string $value New value.
|
||||
* @return boolean True if allowed.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($value) {
|
||||
$this->_value = $value;
|
||||
$this->_is_set = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the form element value back to the
|
||||
* default.
|
||||
* @access public
|
||||
*/
|
||||
function resetValue() {
|
||||
$this->_is_set = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows setting of a label externally, say by a
|
||||
* label tag.
|
||||
* @param string $label Label to attach.
|
||||
* @access public
|
||||
*/
|
||||
function setLabel($label) {
|
||||
$this->_label = trim($label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads external or internal label.
|
||||
* @param string $label Label to test.
|
||||
* @return boolean True is match.
|
||||
* @access public
|
||||
*/
|
||||
function isLabel($label) {
|
||||
return $this->_label == trim($label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the value into the form encoded packet.
|
||||
* @param SimpleEncoding $encoding Form packet.
|
||||
* @access public
|
||||
*/
|
||||
function write(&$encoding) {
|
||||
if ($this->getName()) {
|
||||
$encoding->add($this->getName(), $this->getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Text, password and hidden field.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleTextTag extends SimpleWidget {
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleTextTag($attributes) {
|
||||
$this->SimpleWidget('input', $attributes);
|
||||
if ($this->getAttribute('value') === false) {
|
||||
$this->_setAttribute('value', '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag contains no content.
|
||||
* @return boolean False.
|
||||
* @access public
|
||||
*/
|
||||
function expectEndTag() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current form element value. Cannot
|
||||
* change the value of a hidden field.
|
||||
* @param string $value New value.
|
||||
* @return boolean True if allowed.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($value) {
|
||||
if ($this->getAttribute('type') == 'hidden') {
|
||||
return false;
|
||||
}
|
||||
return parent::setValue($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit button as input tag.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleSubmitTag extends SimpleWidget {
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleSubmitTag($attributes) {
|
||||
$this->SimpleWidget('input', $attributes);
|
||||
if ($this->getAttribute('value') === false) {
|
||||
$this->_setAttribute('value', 'Submit');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag contains no end element.
|
||||
* @return boolean False.
|
||||
* @access public
|
||||
*/
|
||||
function expectEndTag() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the setting of the button value.
|
||||
* @param string $value Ignored.
|
||||
* @return boolean True if allowed.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value of browser visible text.
|
||||
* @return string Visible label.
|
||||
* @access public
|
||||
*/
|
||||
function getLabel() {
|
||||
return $this->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for a label match when searching.
|
||||
* @param string $label Label to test.
|
||||
* @return boolean True on match.
|
||||
* @access public
|
||||
*/
|
||||
function isLabel($label) {
|
||||
return trim($label) == trim($this->getLabel());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Image button as input tag.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleImageSubmitTag extends SimpleWidget {
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleImageSubmitTag($attributes) {
|
||||
$this->SimpleWidget('input', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag contains no end element.
|
||||
* @return boolean False.
|
||||
* @access public
|
||||
*/
|
||||
function expectEndTag() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the setting of the button value.
|
||||
* @param string $value Ignored.
|
||||
* @return boolean True if allowed.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value of browser visible text.
|
||||
* @return string Visible label.
|
||||
* @access public
|
||||
*/
|
||||
function getLabel() {
|
||||
if ($this->getAttribute('title')) {
|
||||
return $this->getAttribute('title');
|
||||
}
|
||||
return $this->getAttribute('alt');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for a label match when searching.
|
||||
* @param string $label Label to test.
|
||||
* @return boolean True on match.
|
||||
* @access public
|
||||
*/
|
||||
function isLabel($label) {
|
||||
return trim($label) == trim($this->getLabel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the value into the form encoded packet.
|
||||
* @param SimpleEncoding $encoding Form packet.
|
||||
* @param integer $x X coordinate of click.
|
||||
* @param integer $y Y coordinate of click.
|
||||
* @access public
|
||||
*/
|
||||
function write(&$encoding, $x, $y) {
|
||||
if ($this->getName()) {
|
||||
$encoding->add($this->getName() . '.x', $x);
|
||||
$encoding->add($this->getName() . '.y', $y);
|
||||
} else {
|
||||
$encoding->add('x', $x);
|
||||
$encoding->add('y', $y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit button as button tag.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleButtonTag extends SimpleWidget {
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* Defaults are very browser dependent.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleButtonTag($attributes) {
|
||||
$this->SimpleWidget('button', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the tag can have both start and
|
||||
* end tags with content in between.
|
||||
* @return boolean True if content allowed.
|
||||
* @access public
|
||||
*/
|
||||
function expectEndTag() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the setting of the button value.
|
||||
* @param string $value Ignored.
|
||||
* @return boolean True if allowed.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value of browser visible text.
|
||||
* @return string Visible label.
|
||||
* @access public
|
||||
*/
|
||||
function getLabel() {
|
||||
return $this->getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for a label match when searching.
|
||||
* @param string $label Label to test.
|
||||
* @return boolean True on match.
|
||||
* @access public
|
||||
*/
|
||||
function isLabel($label) {
|
||||
return trim($label) == trim($this->getLabel());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Content tag for text area.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleTextAreaTag extends SimpleWidget {
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleTextAreaTag($attributes) {
|
||||
$this->SimpleWidget('textarea', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for starting value.
|
||||
* @return string Parsed value.
|
||||
* @access public
|
||||
*/
|
||||
function getDefault() {
|
||||
return $this->_wrap(SimpleHtmlSaxParser::decodeHtml($this->getContent()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies word wrapping if needed.
|
||||
* @param string $value New value.
|
||||
* @return boolean True if allowed.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($value) {
|
||||
return parent::setValue($this->_wrap($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if text should be wrapped.
|
||||
* @return boolean True if wrapping on.
|
||||
* @access private
|
||||
*/
|
||||
function _wrapIsEnabled() {
|
||||
if ($this->getAttribute('cols')) {
|
||||
$wrap = $this->getAttribute('wrap');
|
||||
if (($wrap == 'physical') || ($wrap == 'hard')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the formatting that is peculiar to
|
||||
* this tag. There is strange behaviour in this
|
||||
* one, including stripping a leading new line.
|
||||
* Go figure. I am using Firefox as a guide.
|
||||
* @param string $text Text to wrap.
|
||||
* @return string Text wrapped with carriage
|
||||
* returns and line feeds
|
||||
* @access private
|
||||
*/
|
||||
function _wrap($text) {
|
||||
$text = str_replace("\r\r\n", "\r\n", str_replace("\n", "\r\n", $text));
|
||||
$text = str_replace("\r\n\n", "\r\n", str_replace("\r", "\r\n", $text));
|
||||
if (strncmp($text, "\r\n", strlen("\r\n")) == 0) {
|
||||
$text = substr($text, strlen("\r\n"));
|
||||
}
|
||||
if ($this->_wrapIsEnabled()) {
|
||||
return wordwrap(
|
||||
$text,
|
||||
(integer)$this->getAttribute('cols'),
|
||||
"\r\n");
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* The content of textarea is not part of the page.
|
||||
* @return boolean True.
|
||||
* @access public
|
||||
*/
|
||||
function isPrivateContent() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* File upload widget.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleUploadTag extends SimpleWidget {
|
||||
|
||||
/**
|
||||
* Starts with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleUploadTag($attributes) {
|
||||
$this->SimpleWidget('input', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag contains no content.
|
||||
* @return boolean False.
|
||||
* @access public
|
||||
*/
|
||||
function expectEndTag() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the value into the form encoded packet.
|
||||
* @param SimpleEncoding $encoding Form packet.
|
||||
* @access public
|
||||
*/
|
||||
function write(&$encoding) {
|
||||
if (! file_exists($this->getValue())) {
|
||||
return;
|
||||
}
|
||||
$encoding->attach(
|
||||
$this->getName(),
|
||||
implode('', file($this->getValue())),
|
||||
basename($this->getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop down widget.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleSelectionTag extends SimpleWidget {
|
||||
var $_options;
|
||||
var $_choice;
|
||||
|
||||
/**
|
||||
* Starts with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleSelectionTag($attributes) {
|
||||
$this->SimpleWidget('select', $attributes);
|
||||
$this->_options = array();
|
||||
$this->_choice = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an option tag to a selection field.
|
||||
* @param SimpleOptionTag $tag New option.
|
||||
* @access public
|
||||
*/
|
||||
function addTag(&$tag) {
|
||||
if ($tag->getTagName() == 'option') {
|
||||
$this->_options[] = &$tag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Text within the selection element is ignored.
|
||||
* @param string $content Ignored.
|
||||
* @access public
|
||||
*/
|
||||
function addContent($content) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans options for defaults. If none, then
|
||||
* the first option is selected.
|
||||
* @return string Selected field.
|
||||
* @access public
|
||||
*/
|
||||
function getDefault() {
|
||||
for ($i = 0, $count = count($this->_options); $i < $count; $i++) {
|
||||
if ($this->_options[$i]->getAttribute('selected') !== false) {
|
||||
return $this->_options[$i]->getDefault();
|
||||
}
|
||||
}
|
||||
if ($count > 0) {
|
||||
return $this->_options[0]->getDefault();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Can only set allowed values.
|
||||
* @param string $value New choice.
|
||||
* @return boolean True if allowed.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($value) {
|
||||
for ($i = 0, $count = count($this->_options); $i < $count; $i++) {
|
||||
if ($this->_options[$i]->isValue($value)) {
|
||||
$this->_choice = $i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for current selection value.
|
||||
* @return string Value attribute or
|
||||
* content of opton.
|
||||
* @access public
|
||||
*/
|
||||
function getValue() {
|
||||
if ($this->_choice === false) {
|
||||
return $this->getDefault();
|
||||
}
|
||||
return $this->_options[$this->_choice]->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop down widget.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class MultipleSelectionTag extends SimpleWidget {
|
||||
var $_options;
|
||||
var $_values;
|
||||
|
||||
/**
|
||||
* Starts with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function MultipleSelectionTag($attributes) {
|
||||
$this->SimpleWidget('select', $attributes);
|
||||
$this->_options = array();
|
||||
$this->_values = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an option tag to a selection field.
|
||||
* @param SimpleOptionTag $tag New option.
|
||||
* @access public
|
||||
*/
|
||||
function addTag(&$tag) {
|
||||
if ($tag->getTagName() == 'option') {
|
||||
$this->_options[] = &$tag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Text within the selection element is ignored.
|
||||
* @param string $content Ignored.
|
||||
* @access public
|
||||
*/
|
||||
function addContent($content) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans options for defaults to populate the
|
||||
* value array().
|
||||
* @return array Selected fields.
|
||||
* @access public
|
||||
*/
|
||||
function getDefault() {
|
||||
$default = array();
|
||||
for ($i = 0, $count = count($this->_options); $i < $count; $i++) {
|
||||
if ($this->_options[$i]->getAttribute('selected') !== false) {
|
||||
$default[] = $this->_options[$i]->getDefault();
|
||||
}
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can only set allowed values. Any illegal value
|
||||
* will result in a failure, but all correct values
|
||||
* will be set.
|
||||
* @param array $desired New choices.
|
||||
* @return boolean True if all allowed.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($desired) {
|
||||
$achieved = array();
|
||||
foreach ($desired as $value) {
|
||||
$success = false;
|
||||
for ($i = 0, $count = count($this->_options); $i < $count; $i++) {
|
||||
if ($this->_options[$i]->isValue($value)) {
|
||||
$achieved[] = $this->_options[$i]->getValue();
|
||||
$success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! $success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$this->_values = $achieved;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for current selection value.
|
||||
* @return array List of currently set options.
|
||||
* @access public
|
||||
*/
|
||||
function getValue() {
|
||||
if ($this->_values === false) {
|
||||
return $this->getDefault();
|
||||
}
|
||||
return $this->_values;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Option for selection field.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleOptionTag extends SimpleWidget {
|
||||
|
||||
/**
|
||||
* Stashes the attributes.
|
||||
*/
|
||||
function SimpleOptionTag($attributes) {
|
||||
$this->SimpleWidget('option', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
* @param string $value Ignored.
|
||||
* @return boolean Not allowed.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if a value matches the option.
|
||||
* @param string $compare Value to compare with.
|
||||
* @return boolean True if possible match.
|
||||
* @access public
|
||||
*/
|
||||
function isValue($compare) {
|
||||
$compare = trim($compare);
|
||||
if (trim($this->getValue()) == $compare) {
|
||||
return true;
|
||||
}
|
||||
return trim($this->getContent()) == $compare;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for starting value. Will be set to
|
||||
* the option label if no value exists.
|
||||
* @return string Parsed value.
|
||||
* @access public
|
||||
*/
|
||||
function getDefault() {
|
||||
if ($this->getAttribute('value') === false) {
|
||||
return $this->getContent();
|
||||
}
|
||||
return $this->getAttribute('value');
|
||||
}
|
||||
|
||||
/**
|
||||
* The content of options is not part of the page.
|
||||
* @return boolean True.
|
||||
* @access public
|
||||
*/
|
||||
function isPrivateContent() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Radio button.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleRadioButtonTag extends SimpleWidget {
|
||||
|
||||
/**
|
||||
* Stashes the attributes.
|
||||
* @param array $attributes Hash of attributes.
|
||||
*/
|
||||
function SimpleRadioButtonTag($attributes) {
|
||||
$this->SimpleWidget('input', $attributes);
|
||||
if ($this->getAttribute('value') === false) {
|
||||
$this->_setAttribute('value', 'on');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag contains no content.
|
||||
* @return boolean False.
|
||||
* @access public
|
||||
*/
|
||||
function expectEndTag() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The only allowed value sn the one in the
|
||||
* "value" attribute.
|
||||
* @param string $value New value.
|
||||
* @return boolean True if allowed.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($value) {
|
||||
if ($value === false) {
|
||||
return parent::setValue($value);
|
||||
}
|
||||
if ($value != $this->getAttribute('value')) {
|
||||
return false;
|
||||
}
|
||||
return parent::setValue($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for starting value.
|
||||
* @return string Parsed value.
|
||||
* @access public
|
||||
*/
|
||||
function getDefault() {
|
||||
if ($this->getAttribute('checked') !== false) {
|
||||
return $this->getAttribute('value');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checkbox widget.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleCheckboxTag extends SimpleWidget {
|
||||
|
||||
/**
|
||||
* Starts with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleCheckboxTag($attributes) {
|
||||
$this->SimpleWidget('input', $attributes);
|
||||
if ($this->getAttribute('value') === false) {
|
||||
$this->_setAttribute('value', 'on');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag contains no content.
|
||||
* @return boolean False.
|
||||
* @access public
|
||||
*/
|
||||
function expectEndTag() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The only allowed value in the one in the
|
||||
* "value" attribute. The default for this
|
||||
* attribute is "on". If this widget is set to
|
||||
* true, then the usual value will be taken.
|
||||
* @param string $value New value.
|
||||
* @return boolean True if allowed.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($value) {
|
||||
if ($value === false) {
|
||||
return parent::setValue($value);
|
||||
}
|
||||
if ($value === true) {
|
||||
return parent::setValue($this->getAttribute('value'));
|
||||
}
|
||||
if ($value != $this->getAttribute('value')) {
|
||||
return false;
|
||||
}
|
||||
return parent::setValue($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for starting value. The default
|
||||
* value is "on".
|
||||
* @return string Parsed value.
|
||||
* @access public
|
||||
*/
|
||||
function getDefault() {
|
||||
if ($this->getAttribute('checked') !== false) {
|
||||
return $this->getAttribute('value');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A group of multiple widgets with some shared behaviour.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleTagGroup {
|
||||
var $_widgets = array();
|
||||
|
||||
/**
|
||||
* Adds a tag to the group.
|
||||
* @param SimpleWidget $widget
|
||||
* @access public
|
||||
*/
|
||||
function addWidget(&$widget) {
|
||||
$this->_widgets[] = &$widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor to widget set.
|
||||
* @return array All widgets.
|
||||
* @access protected
|
||||
*/
|
||||
function &_getWidgets() {
|
||||
return $this->_widgets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for an attribute.
|
||||
* @param string $label Attribute name.
|
||||
* @return boolean Always false.
|
||||
* @access public
|
||||
*/
|
||||
function getAttribute($label) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the name for the widget from the first
|
||||
* member.
|
||||
* @return string Name of widget.
|
||||
* @access public
|
||||
*/
|
||||
function getName() {
|
||||
if (count($this->_widgets) > 0) {
|
||||
return $this->_widgets[0]->getName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the widgets for one with the appropriate
|
||||
* ID field.
|
||||
* @param string $id ID value to try.
|
||||
* @return boolean True if matched.
|
||||
* @access public
|
||||
*/
|
||||
function isId($id) {
|
||||
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
|
||||
if ($this->_widgets[$i]->isId($id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the widgets for one with the appropriate
|
||||
* attached label.
|
||||
* @param string $label Attached label to try.
|
||||
* @return boolean True if matched.
|
||||
* @access public
|
||||
*/
|
||||
function isLabel($label) {
|
||||
for ($i = 0, $count = count($this->_widgets); $i < $count; $i++) {
|
||||
if ($this->_widgets[$i]->isLabel($label)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the value into the form encoded packet.
|
||||
* @param SimpleEncoding $encoding Form packet.
|
||||
* @access public
|
||||
*/
|
||||
function write(&$encoding) {
|
||||
$encoding->add($this->getName(), $this->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A group of tags with the same name within a form.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleCheckboxGroup extends SimpleTagGroup {
|
||||
|
||||
/**
|
||||
* Accessor for current selected widget or false
|
||||
* if none.
|
||||
* @return string/array Widget values or false if none.
|
||||
* @access public
|
||||
*/
|
||||
function getValue() {
|
||||
$values = array();
|
||||
$widgets = &$this->_getWidgets();
|
||||
for ($i = 0, $count = count($widgets); $i < $count; $i++) {
|
||||
if ($widgets[$i]->getValue() !== false) {
|
||||
$values[] = $widgets[$i]->getValue();
|
||||
}
|
||||
}
|
||||
return $this->_coerceValues($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for starting value that is active.
|
||||
* @return string/array Widget values or false if none.
|
||||
* @access public
|
||||
*/
|
||||
function getDefault() {
|
||||
$values = array();
|
||||
$widgets = &$this->_getWidgets();
|
||||
for ($i = 0, $count = count($widgets); $i < $count; $i++) {
|
||||
if ($widgets[$i]->getDefault() !== false) {
|
||||
$values[] = $widgets[$i]->getDefault();
|
||||
}
|
||||
}
|
||||
return $this->_coerceValues($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for current set values.
|
||||
* @param string/array/boolean $values Either a single string, a
|
||||
* hash or false for nothing set.
|
||||
* @return boolean True if all values can be set.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($values) {
|
||||
$values = $this->_makeArray($values);
|
||||
if (! $this->_valuesArePossible($values)) {
|
||||
return false;
|
||||
}
|
||||
$widgets = &$this->_getWidgets();
|
||||
for ($i = 0, $count = count($widgets); $i < $count; $i++) {
|
||||
$possible = $widgets[$i]->getAttribute('value');
|
||||
if (in_array($widgets[$i]->getAttribute('value'), $values)) {
|
||||
$widgets[$i]->setValue($possible);
|
||||
} else {
|
||||
$widgets[$i]->setValue(false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if a possible value set is legal.
|
||||
* @param string/array/boolean $values Either a single string, a
|
||||
* hash or false for nothing set.
|
||||
* @return boolean False if trying to set a
|
||||
* missing value.
|
||||
* @access private
|
||||
*/
|
||||
function _valuesArePossible($values) {
|
||||
$matches = array();
|
||||
$widgets = &$this->_getWidgets();
|
||||
for ($i = 0, $count = count($widgets); $i < $count; $i++) {
|
||||
$possible = $widgets[$i]->getAttribute('value');
|
||||
if (in_array($possible, $values)) {
|
||||
$matches[] = $possible;
|
||||
}
|
||||
}
|
||||
return ($values == $matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the output to an appropriate format. This means
|
||||
* that no values is false, a single value is just that
|
||||
* value and only two or more are contained in an array.
|
||||
* @param array $values List of values of widgets.
|
||||
* @return string/array/boolean Expected format for a tag.
|
||||
* @access private
|
||||
*/
|
||||
function _coerceValues($values) {
|
||||
if (count($values) == 0) {
|
||||
return false;
|
||||
} elseif (count($values) == 1) {
|
||||
return $values[0];
|
||||
} else {
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts false or string into array. The opposite of
|
||||
* the coercian method.
|
||||
* @param string/array/boolean $value A single item is converted
|
||||
* to a one item list. False
|
||||
* gives an empty list.
|
||||
* @return array List of values, possibly empty.
|
||||
* @access private
|
||||
*/
|
||||
function _makeArray($value) {
|
||||
if ($value === false) {
|
||||
return array();
|
||||
}
|
||||
if (is_string($value)) {
|
||||
return array($value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A group of tags with the same name within a form.
|
||||
* Used for radio buttons.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleRadioGroup extends SimpleTagGroup {
|
||||
|
||||
/**
|
||||
* Each tag is tried in turn until one is
|
||||
* successfully set. The others will be
|
||||
* unchecked if successful.
|
||||
* @param string $value New value.
|
||||
* @return boolean True if any allowed.
|
||||
* @access public
|
||||
*/
|
||||
function setValue($value) {
|
||||
if (! $this->_valueIsPossible($value)) {
|
||||
return false;
|
||||
}
|
||||
$index = false;
|
||||
$widgets = &$this->_getWidgets();
|
||||
for ($i = 0, $count = count($widgets); $i < $count; $i++) {
|
||||
if (! $widgets[$i]->setValue($value)) {
|
||||
$widgets[$i]->setValue(false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if a value is allowed.
|
||||
* @param string Attempted value.
|
||||
* @return boolean True if a valid value.
|
||||
* @access private
|
||||
*/
|
||||
function _valueIsPossible($value) {
|
||||
$widgets = &$this->_getWidgets();
|
||||
for ($i = 0, $count = count($widgets); $i < $count; $i++) {
|
||||
if ($widgets[$i]->getAttribute('value') == $value) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for current selected widget or false
|
||||
* if none.
|
||||
* @return string/boolean Value attribute or
|
||||
* content of opton.
|
||||
* @access public
|
||||
*/
|
||||
function getValue() {
|
||||
$widgets = &$this->_getWidgets();
|
||||
for ($i = 0, $count = count($widgets); $i < $count; $i++) {
|
||||
if ($widgets[$i]->getValue() !== false) {
|
||||
return $widgets[$i]->getValue();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for starting value that is active.
|
||||
* @return string/boolean Value of first checked
|
||||
* widget or false if none.
|
||||
* @access public
|
||||
*/
|
||||
function getDefault() {
|
||||
$widgets = &$this->_getWidgets();
|
||||
for ($i = 0, $count = count($widgets); $i < $count; $i++) {
|
||||
if ($widgets[$i]->getDefault() !== false) {
|
||||
return $widgets[$i]->getDefault();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag to keep track of labels.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleLabelTag extends SimpleTag {
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleLabelTag($attributes) {
|
||||
$this->SimpleTag('label', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Access for the ID to attach the label to.
|
||||
* @return string For attribute.
|
||||
* @access public
|
||||
*/
|
||||
function getFor() {
|
||||
return $this->getAttribute('for');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag to aid parsing the form.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleFormTag extends SimpleTag {
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleFormTag($attributes) {
|
||||
$this->SimpleTag('form', $attributes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag to aid parsing the frames in a page.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleFrameTag extends SimpleTag {
|
||||
|
||||
/**
|
||||
* Starts with a named tag with attributes only.
|
||||
* @param hash $attributes Attribute names and
|
||||
* string values.
|
||||
*/
|
||||
function SimpleFrameTag($attributes) {
|
||||
$this->SimpleTag('frame', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag contains no content.
|
||||
* @return boolean False.
|
||||
* @access public
|
||||
*/
|
||||
function expectEndTag() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
?>
|
528
thirdparty/simpletest/url.php
vendored
Normal file
528
thirdparty/simpletest/url.php
vendored
Normal file
@ -0,0 +1,528 @@
|
||||
<?php
|
||||
/**
|
||||
* base include file for SimpleTest
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
* @version $Id: url.php 1723 2008-04-08 00:34:10Z lastcraft $
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
* include other SimpleTest class files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/encoding.php');
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* URL parser to replace parse_url() PHP function which
|
||||
* got broken in PHP 4.3.0. Adds some browser specific
|
||||
* functionality such as expandomatics.
|
||||
* Guesses a bit trying to separate the host from
|
||||
* the path and tries to keep a raw, possibly unparsable,
|
||||
* request string as long as possible.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleUrl {
|
||||
var $_scheme;
|
||||
var $_username;
|
||||
var $_password;
|
||||
var $_host;
|
||||
var $_port;
|
||||
var $_path;
|
||||
var $_request;
|
||||
var $_fragment;
|
||||
var $_x;
|
||||
var $_y;
|
||||
var $_target;
|
||||
var $_raw = false;
|
||||
|
||||
/**
|
||||
* Constructor. Parses URL into sections.
|
||||
* @param string $url Incoming URL.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleUrl($url = '') {
|
||||
list($x, $y) = $this->_chompCoordinates($url);
|
||||
$this->setCoordinates($x, $y);
|
||||
$this->_scheme = $this->_chompScheme($url);
|
||||
list($this->_username, $this->_password) = $this->_chompLogin($url);
|
||||
$this->_host = $this->_chompHost($url);
|
||||
$this->_port = false;
|
||||
if (preg_match('/(.*?):(.*)/', $this->_host, $host_parts)) {
|
||||
$this->_host = $host_parts[1];
|
||||
$this->_port = (integer)$host_parts[2];
|
||||
}
|
||||
$this->_path = $this->_chompPath($url);
|
||||
$this->_request = $this->_parseRequest($this->_chompRequest($url));
|
||||
$this->_fragment = (strncmp($url, "#", 1) == 0 ? substr($url, 1) : false);
|
||||
$this->_target = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the X, Y coordinate pair from an image map.
|
||||
* @param string $url URL so far. The coordinates will be
|
||||
* removed.
|
||||
* @return array X, Y as a pair of integers.
|
||||
* @access private
|
||||
*/
|
||||
function _chompCoordinates(&$url) {
|
||||
if (preg_match('/(.*)\?(\d+),(\d+)$/', $url, $matches)) {
|
||||
$url = $matches[1];
|
||||
return array((integer)$matches[2], (integer)$matches[3]);
|
||||
}
|
||||
return array(false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the scheme part of an incoming URL.
|
||||
* @param string $url URL so far. The scheme will be
|
||||
* removed.
|
||||
* @return string Scheme part or false.
|
||||
* @access private
|
||||
*/
|
||||
function _chompScheme(&$url) {
|
||||
if (preg_match('/^([^\/:]*):(\/\/)(.*)/', $url, $matches)) {
|
||||
$url = $matches[2] . $matches[3];
|
||||
return $matches[1];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the username and password from the
|
||||
* incoming URL. The // prefix will be reattached
|
||||
* to the URL after the doublet is extracted.
|
||||
* @param string $url URL so far. The username and
|
||||
* password are removed.
|
||||
* @return array Two item list of username and
|
||||
* password. Will urldecode() them.
|
||||
* @access private
|
||||
*/
|
||||
function _chompLogin(&$url) {
|
||||
$prefix = '';
|
||||
if (preg_match('/^(\/\/)(.*)/', $url, $matches)) {
|
||||
$prefix = $matches[1];
|
||||
$url = $matches[2];
|
||||
}
|
||||
if (preg_match('/^([^\/]*)@(.*)/', $url, $matches)) {
|
||||
$url = $prefix . $matches[2];
|
||||
$parts = split(":", $matches[1]);
|
||||
return array(
|
||||
urldecode($parts[0]),
|
||||
isset($parts[1]) ? urldecode($parts[1]) : false);
|
||||
}
|
||||
$url = $prefix . $url;
|
||||
return array(false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the host part of an incoming URL.
|
||||
* Includes the port number part. Will extract
|
||||
* the host if it starts with // or it has
|
||||
* a top level domain or it has at least two
|
||||
* dots.
|
||||
* @param string $url URL so far. The host will be
|
||||
* removed.
|
||||
* @return string Host part guess or false.
|
||||
* @access private
|
||||
*/
|
||||
function _chompHost(&$url) {
|
||||
if (preg_match('/^(\/\/)(.*?)(\/.*|\?.*|#.*|$)/', $url, $matches)) {
|
||||
$url = $matches[3];
|
||||
return $matches[2];
|
||||
}
|
||||
if (preg_match('/(.*?)(\.\.\/|\.\/|\/|\?|#|$)(.*)/', $url, $matches)) {
|
||||
$tlds = SimpleUrl::getAllTopLevelDomains();
|
||||
if (preg_match('/[a-z0-9\-]+\.(' . $tlds . ')/i', $matches[1])) {
|
||||
$url = $matches[2] . $matches[3];
|
||||
return $matches[1];
|
||||
} elseif (preg_match('/[a-z0-9\-]+\.[a-z0-9\-]+\.[a-z0-9\-]+/i', $matches[1])) {
|
||||
$url = $matches[2] . $matches[3];
|
||||
return $matches[1];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the path information from the incoming
|
||||
* URL. Strips this path from the URL.
|
||||
* @param string $url URL so far. The host will be
|
||||
* removed.
|
||||
* @return string Path part or '/'.
|
||||
* @access private
|
||||
*/
|
||||
function _chompPath(&$url) {
|
||||
if (preg_match('/(.*?)(\?|#|$)(.*)/', $url, $matches)) {
|
||||
$url = $matches[2] . $matches[3];
|
||||
return ($matches[1] ? $matches[1] : '');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips off the request data.
|
||||
* @param string $url URL so far. The request will be
|
||||
* removed.
|
||||
* @return string Raw request part.
|
||||
* @access private
|
||||
*/
|
||||
function _chompRequest(&$url) {
|
||||
if (preg_match('/\?(.*?)(#|$)(.*)/', $url, $matches)) {
|
||||
$url = $matches[2] . $matches[3];
|
||||
return $matches[1];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Breaks the request down into an object.
|
||||
* @param string $raw Raw request.
|
||||
* @return SimpleFormEncoding Parsed data.
|
||||
* @access private
|
||||
*/
|
||||
function _parseRequest($raw) {
|
||||
$this->_raw = $raw;
|
||||
$request = new SimpleGetEncoding();
|
||||
foreach (split("&", $raw) as $pair) {
|
||||
if (preg_match('/(.*?)=(.*)/', $pair, $matches)) {
|
||||
$request->add($matches[1], urldecode($matches[2]));
|
||||
} elseif ($pair) {
|
||||
$request->add($pair, '');
|
||||
}
|
||||
}
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for protocol part.
|
||||
* @param string $default Value to use if not present.
|
||||
* @return string Scheme name, e.g "http".
|
||||
* @access public
|
||||
*/
|
||||
function getScheme($default = false) {
|
||||
return $this->_scheme ? $this->_scheme : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for user name.
|
||||
* @return string Username preceding host.
|
||||
* @access public
|
||||
*/
|
||||
function getUsername() {
|
||||
return $this->_username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for password.
|
||||
* @return string Password preceding host.
|
||||
* @access public
|
||||
*/
|
||||
function getPassword() {
|
||||
return $this->_password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for hostname and port.
|
||||
* @param string $default Value to use if not present.
|
||||
* @return string Hostname only.
|
||||
* @access public
|
||||
*/
|
||||
function getHost($default = false) {
|
||||
return $this->_host ? $this->_host : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for top level domain.
|
||||
* @return string Last part of host.
|
||||
* @access public
|
||||
*/
|
||||
function getTld() {
|
||||
$path_parts = pathinfo($this->getHost());
|
||||
return (isset($path_parts['extension']) ? $path_parts['extension'] : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for port number.
|
||||
* @return integer TCP/IP port number.
|
||||
* @access public
|
||||
*/
|
||||
function getPort() {
|
||||
return $this->_port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for path.
|
||||
* @return string Full path including leading slash if implied.
|
||||
* @access public
|
||||
*/
|
||||
function getPath() {
|
||||
if (! $this->_path && $this->_host) {
|
||||
return '/';
|
||||
}
|
||||
return $this->_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for page if any. This may be a
|
||||
* directory name if ambiguious.
|
||||
* @return Page name.
|
||||
* @access public
|
||||
*/
|
||||
function getPage() {
|
||||
if (! preg_match('/([^\/]*?)$/', $this->getPath(), $matches)) {
|
||||
return false;
|
||||
}
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path to the page.
|
||||
* @return string Path less the page.
|
||||
* @access public
|
||||
*/
|
||||
function getBasePath() {
|
||||
if (! preg_match('/(.*\/)[^\/]*?$/', $this->getPath(), $matches)) {
|
||||
return false;
|
||||
}
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for fragment at end of URL after the "#".
|
||||
* @return string Part after "#".
|
||||
* @access public
|
||||
*/
|
||||
function getFragment() {
|
||||
return $this->_fragment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets image coordinates. Set to false to clear
|
||||
* them.
|
||||
* @param integer $x Horizontal position.
|
||||
* @param integer $y Vertical position.
|
||||
* @access public
|
||||
*/
|
||||
function setCoordinates($x = false, $y = false) {
|
||||
if (($x === false) || ($y === false)) {
|
||||
$this->_x = $this->_y = false;
|
||||
return;
|
||||
}
|
||||
$this->_x = (integer)$x;
|
||||
$this->_y = (integer)$y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for horizontal image coordinate.
|
||||
* @return integer X value.
|
||||
* @access public
|
||||
*/
|
||||
function getX() {
|
||||
return $this->_x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for vertical image coordinate.
|
||||
* @return integer Y value.
|
||||
* @access public
|
||||
*/
|
||||
function getY() {
|
||||
return $this->_y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for current request parameters
|
||||
* in URL string form. Will return teh original request
|
||||
* if at all possible even if it doesn't make much
|
||||
* sense.
|
||||
* @return string Form is string "?a=1&b=2", etc.
|
||||
* @access public
|
||||
*/
|
||||
function getEncodedRequest() {
|
||||
if ($this->_raw) {
|
||||
$encoded = $this->_raw;
|
||||
} else {
|
||||
$encoded = $this->_request->asUrlRequest();
|
||||
}
|
||||
if ($encoded) {
|
||||
return '?' . preg_replace('/^\?/', '', $encoded);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an additional parameter to the request.
|
||||
* @param string $key Name of parameter.
|
||||
* @param string $value Value as string.
|
||||
* @access public
|
||||
*/
|
||||
function addRequestParameter($key, $value) {
|
||||
$this->_raw = false;
|
||||
$this->_request->add($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds additional parameters to the request.
|
||||
* @param hash/SimpleFormEncoding $parameters Additional
|
||||
* parameters.
|
||||
* @access public
|
||||
*/
|
||||
function addRequestParameters($parameters) {
|
||||
$this->_raw = false;
|
||||
$this->_request->merge($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears down all parameters.
|
||||
* @access public
|
||||
*/
|
||||
function clearRequest() {
|
||||
$this->_raw = false;
|
||||
$this->_request = &new SimpleGetEncoding();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the frame target if present. Although
|
||||
* not strictly part of the URL specification it
|
||||
* acts as similarily to the browser.
|
||||
* @return boolean/string Frame name or false if none.
|
||||
* @access public
|
||||
*/
|
||||
function getTarget() {
|
||||
return $this->_target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches a frame target.
|
||||
* @param string $frame Name of frame.
|
||||
* @access public
|
||||
*/
|
||||
function setTarget($frame) {
|
||||
$this->_raw = false;
|
||||
$this->_target = $frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the URL back into a string.
|
||||
* @return string URL in canonical form.
|
||||
* @access public
|
||||
*/
|
||||
function asString() {
|
||||
$path = $this->_path;
|
||||
$scheme = $identity = $host = $encoded = $fragment = '';
|
||||
if ($this->_username && $this->_password) {
|
||||
$identity = $this->_username . ':' . $this->_password . '@';
|
||||
}
|
||||
if ($this->getHost()) {
|
||||
$scheme = $this->getScheme() ? $this->getScheme() : 'http';
|
||||
$scheme .= "://";
|
||||
$host = $this->getHost();
|
||||
}
|
||||
if (substr($this->_path, 0, 1) == '/') {
|
||||
$path = $this->normalisePath($this->_path);
|
||||
}
|
||||
$encoded = $this->getEncodedRequest();
|
||||
$fragment = $this->getFragment() ? '#'. $this->getFragment() : '';
|
||||
$coords = $this->getX() === false ? '' : '?' . $this->getX() . ',' . $this->getY();
|
||||
return "$scheme$identity$host$path$encoded$fragment$coords";
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces unknown sections to turn a relative
|
||||
* URL into an absolute one. The base URL can
|
||||
* be either a string or a SimpleUrl object.
|
||||
* @param string/SimpleUrl $base Base URL.
|
||||
* @access public
|
||||
*/
|
||||
function makeAbsolute($base) {
|
||||
if (! is_object($base)) {
|
||||
$base = new SimpleUrl($base);
|
||||
}
|
||||
if ($this->getHost()) {
|
||||
$scheme = $this->getScheme();
|
||||
$host = $this->getHost();
|
||||
$port = $this->getPort() ? ':' . $this->getPort() : '';
|
||||
$identity = $this->getIdentity() ? $this->getIdentity() . '@' : '';
|
||||
if (! $identity) {
|
||||
$identity = $base->getIdentity() ? $base->getIdentity() . '@' : '';
|
||||
}
|
||||
} else {
|
||||
$scheme = $base->getScheme();
|
||||
$host = $base->getHost();
|
||||
$port = $base->getPort() ? ':' . $base->getPort() : '';
|
||||
$identity = $base->getIdentity() ? $base->getIdentity() . '@' : '';
|
||||
}
|
||||
$path = $this->normalisePath($this->_extractAbsolutePath($base));
|
||||
$encoded = $this->getEncodedRequest();
|
||||
$fragment = $this->getFragment() ? '#'. $this->getFragment() : '';
|
||||
$coords = $this->getX() === false ? '' : '?' . $this->getX() . ',' . $this->getY();
|
||||
return new SimpleUrl("$scheme://$identity$host$port$path$encoded$fragment$coords");
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces unknown sections of the path with base parts
|
||||
* to return a complete absolute one.
|
||||
* @param string/SimpleUrl $base Base URL.
|
||||
* @param string Absolute path.
|
||||
* @access private
|
||||
*/
|
||||
function _extractAbsolutePath($base) {
|
||||
if ($this->getHost()) {
|
||||
return $this->_path;
|
||||
}
|
||||
if (! $this->_isRelativePath($this->_path)) {
|
||||
return $this->_path;
|
||||
}
|
||||
if ($this->_path) {
|
||||
return $base->getBasePath() . $this->_path;
|
||||
}
|
||||
return $base->getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple test to see if a path part is relative.
|
||||
* @param string $path Path to test.
|
||||
* @return boolean True if starts with a "/".
|
||||
* @access private
|
||||
*/
|
||||
function _isRelativePath($path) {
|
||||
return (substr($path, 0, 1) != '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the username and password for use in rendering
|
||||
* a URL.
|
||||
* @return string/boolean Form of username:password or false.
|
||||
* @access public
|
||||
*/
|
||||
function getIdentity() {
|
||||
if ($this->_username && $this->_password) {
|
||||
return $this->_username . ':' . $this->_password;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces . and .. sections of the path.
|
||||
* @param string $path Unoptimised path.
|
||||
* @return string Path with dots removed if possible.
|
||||
* @access public
|
||||
*/
|
||||
function normalisePath($path) {
|
||||
$path = preg_replace('|/\./|', '/', $path);
|
||||
return preg_replace('|/[^/]+/\.\./|', '/', $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* A pipe seperated list of all TLDs that result in two part
|
||||
* domain names.
|
||||
* @return string Pipe separated list.
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
function getAllTopLevelDomains() {
|
||||
return 'com|edu|net|org|gov|mil|int|biz|info|name|pro|aero|coop|museum';
|
||||
}
|
||||
}
|
||||
?>
|
162
thirdparty/spyc/README
vendored
Normal file
162
thirdparty/spyc/README
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
#
|
||||
# S P Y C
|
||||
# a simple php yaml class
|
||||
# v0.2(.5)
|
||||
#
|
||||
# Load this README!
|
||||
# >> $readme = Spyc::YAMLLoad('README');
|
||||
#
|
||||
--- %YAML:1.1
|
||||
title: Spyc -- a Simple PHP YAML Class
|
||||
version: 0.2.5
|
||||
author: [chris wanstrath, chris@ozmm.org]
|
||||
websites: [http://www.yaml.org, http://spyc.sourceforge.net]
|
||||
license: [MIT License, http://www.opensource.org/licenses/mit-license.php]
|
||||
copyright: (c) 2005-2006 Chris Wanstrath
|
||||
tested on: [php 4.3.11, php 5.0.4]
|
||||
|
||||
installation: >
|
||||
Copy spyc.php to a directory you can
|
||||
access with your YAML-ready PHP script.
|
||||
|
||||
That's it!
|
||||
|
||||
about: >
|
||||
From www.yaml.org:
|
||||
|
||||
"YAML(tm) (rhymes with 'camel') is a human-friendly, cross language,
|
||||
Unicode based data serialization language designed around the common
|
||||
native data structures of agile programming languages. It is broadly
|
||||
useful for programming needs ranging from configuration files to
|
||||
Internet messaging to object persistence to data auditing. Together
|
||||
with the Unicode standard for characters, the YAML specification provides
|
||||
all the information necessary to understand YAML Version 1.1 and to
|
||||
creating programs that process YAML information.
|
||||
|
||||
YAML(tm) is a balance of the following design goals:
|
||||
- YAML documents are very readable by humans.
|
||||
- YAML interacts well with scripting languages.
|
||||
- YAML uses host languages' native data structures.
|
||||
- YAML has a consistent information model.
|
||||
- YAML enables stream-based processing.
|
||||
- YAML is expressive and extensible.
|
||||
- YAML is easy to implement."
|
||||
|
||||
YAML makes a lot of sense. It's easy to use, easy to learn, and cool.
|
||||
As the lucky stiff named why once said, "YAML is a beacon of light."
|
||||
|
||||
If you're new to YAML, may we suggest YAML In Five Minutes:
|
||||
- http://yaml.kwiki.org/?YamlInFiveMinutes
|
||||
|
||||
If you don't have five minutes, realize that this README is a completely
|
||||
valid YAML document. Dig in, load this or any YAML file into an array
|
||||
with Spyc and see how easy it is to translate friendly text into usable
|
||||
data.
|
||||
|
||||
The purpose of Spyc is to provide a pure PHP alternative to Syck, a
|
||||
simple API for loading and dumping YAML documents, a YAML loader which
|
||||
understands a usable subset of the YAML spec, and to further spread
|
||||
the glory of YAML to the PHP masses.
|
||||
|
||||
If you're at all hesitant ("usable subset of YAML?!"), navigate
|
||||
http://yaml.org/start.html. Spyc completely understands the YAML
|
||||
document shown there, a document which has features way beyond the
|
||||
scope of what normal config files might require. Try it for yourself,
|
||||
and then start enjoying the peace of mind YAML brings to your life.
|
||||
|
||||
meat and a few potatoes:
|
||||
- concept: Loading a YAML document into PHP
|
||||
brief: >
|
||||
$yaml will become an array of all the data in wicked.yaml
|
||||
code: |
|
||||
|
||||
include('spyc.php');
|
||||
|
||||
$yaml = Spyc::YAMLLoad('wicked.yaml');
|
||||
|
||||
- concept: Loading a YAML string into PHP
|
||||
brief: >
|
||||
$array will look like this:
|
||||
array('A YAML','document in a','string')
|
||||
code: |
|
||||
|
||||
include('spyc.php');
|
||||
|
||||
$yaml = '- A YAML\n- document in a\n- string.';
|
||||
$array = Spyc::YAMLLoad($yaml);
|
||||
|
||||
- concept: Dumping a PHP array to YAML
|
||||
brief: >
|
||||
$yaml will become a string of a YAML document created from
|
||||
$array.
|
||||
code: |
|
||||
|
||||
include('spyc.php');
|
||||
|
||||
$array['name'] = 'chris';
|
||||
$array['sport'] = 'curbing';
|
||||
|
||||
$yaml = Spyc::YAMLDump($array);
|
||||
|
||||
prior art:
|
||||
- who: [Brian Ingerson, Clark Evans, Oren Ben-Kiki]
|
||||
why?: >
|
||||
The YAML spec is really a piece of work, and these guys
|
||||
did a great job on it. A simple and elegant language like
|
||||
YAML was a long time coming and it's refreshing to know
|
||||
such able minded individuals took the task to heart and
|
||||
executed it with cunning and strength. In addition to
|
||||
their various noteworthy contributions to YAML parsers
|
||||
and related projects, YAML.pm's README is a treasure trove
|
||||
of information for knowledge seekers. Thanks, guys.
|
||||
|
||||
- who: why the lucky stiff
|
||||
why?: >
|
||||
As the author of Syck, the code used in Ruby for the language's
|
||||
YAML class and methods, why is indirectly (directly?) responsible
|
||||
for my first exposure to YAML (as a config file in a Ruby web-app)
|
||||
and the countless hours I spent playing with this sheik new data
|
||||
format afterwards. Syck's README is a YAML file and thus the
|
||||
inspiration for this file and, even, this very piece of software.
|
||||
|
||||
- who: Steve Howell
|
||||
why?: >
|
||||
Python's YAML implementation. PyYAML's README file is also YAML,
|
||||
so it too inspired the YAML format of this README file.
|
||||
|
||||
- who: [Rasmus Lerdorf, Zeev Suraski, Andi Gutmans, et al]
|
||||
why?: >
|
||||
PHP is great at what it does best. It's also paid a lot of my bills.
|
||||
Thanks.
|
||||
|
||||
bugs:
|
||||
report: >
|
||||
Please see Spyc's Sourceforge project page for information on reporting bugs.
|
||||
speed: >
|
||||
This implementation was not designed for speed. Rather, it
|
||||
was designed for those who need a pure PHP implementation of
|
||||
a YAML parser and who are not overly concerned with performance.
|
||||
If you want speed, check out Syck.
|
||||
depth: >
|
||||
This parser is by no means a comprehensive YAML parser. For supported
|
||||
features and future plans, check the website.
|
||||
unicode: >
|
||||
YAML is supposed to be unicode, but for now we're just using ASCII.
|
||||
PHP has crappy unicode support but who knows what the future holds.
|
||||
|
||||
resources:
|
||||
- http://www.yaml.org
|
||||
- http://www.yaml.org/spec/
|
||||
- http://yaml.kwiki.org/?YamlInFiveMinutes
|
||||
- http://www.whytheluckystiff.net/syck/
|
||||
- http://yaml4r.sourceforge.net/cookbook/
|
||||
- http://www.sourceforge.net/projects/spyc/
|
||||
- http://spyc.sourceforge.net/
|
||||
|
||||
thanks:
|
||||
- Adam Wood
|
||||
- Daniel Ferreira
|
||||
- Aaron Jensen
|
||||
- Mike Thornton
|
||||
- Fabien Potencier
|
||||
- Mustafa Kumas
|
868
thirdparty/spyc/Spyc.php
vendored
Normal file
868
thirdparty/spyc/Spyc.php
vendored
Normal file
@ -0,0 +1,868 @@
|
||||
<?php
|
||||
/**
|
||||
* Spyc -- A Simple PHP YAML Class
|
||||
* @version 0.2.(5) -- 2006-12-31
|
||||
* @author Chris Wanstrath <chris@ozmm.org>
|
||||
* @author Vlad Andersen <vlad@oneiros.ru>
|
||||
* @link http://spyc.sourceforge.net/
|
||||
* @copyright Copyright 2005-2006 Chris Wanstrath
|
||||
* @license http://www.opensource.org/licenses/mit-license.php MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* A node, used by Spyc for parsing YAML.
|
||||
* @package sapphire
|
||||
* @subpackage misc
|
||||
*/
|
||||
class YAMLNode {
|
||||
/**#@+
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
public $parent;
|
||||
public $id;
|
||||
/**#@-*/
|
||||
/**
|
||||
* @access public
|
||||
* @var mixed
|
||||
*/
|
||||
public $data;
|
||||
/**
|
||||
* @access public
|
||||
* @var int
|
||||
*/
|
||||
public $indent;
|
||||
/**
|
||||
* @access public
|
||||
* @var bool
|
||||
*/
|
||||
public $children = false;
|
||||
|
||||
/**
|
||||
* The constructor assigns the node a unique ID.
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function YAMLNode($nodeId) {
|
||||
$this->id = $nodeId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Simple PHP YAML Class.
|
||||
*
|
||||
* This class can be used to read a YAML file and convert its contents
|
||||
* into a PHP array. It currently supports a very limited subsection of
|
||||
* the YAML spec.
|
||||
*
|
||||
* Usage:
|
||||
* <code>
|
||||
* $parser = new Spyc;
|
||||
* $array = $parser->load($file);
|
||||
* </code>
|
||||
* @package sapphire
|
||||
* @subpackage misc
|
||||
*/
|
||||
class Spyc {
|
||||
|
||||
/**
|
||||
* Load YAML into a PHP array statically
|
||||
*
|
||||
* The load method, when supplied with a YAML stream (string or file),
|
||||
* will do its best to convert YAML in a file into a PHP array. Pretty
|
||||
* simple.
|
||||
* Usage:
|
||||
* <code>
|
||||
* $array = Spyc::YAMLLoad('lucky.yaml');
|
||||
* print_r($array);
|
||||
* </code>
|
||||
* @access public
|
||||
* @return array
|
||||
* @param string $input Path of YAML file or string containing YAML
|
||||
*/
|
||||
public static function YAMLLoad($input) {
|
||||
$spyc = new Spyc;
|
||||
return $spyc->load($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump YAML from PHP array statically
|
||||
*
|
||||
* The dump method, when supplied with an array, will do its best
|
||||
* to convert the array into friendly YAML. Pretty simple. Feel free to
|
||||
* save the returned string as nothing.yaml and pass it around.
|
||||
*
|
||||
* Oh, and you can decide how big the indent is and what the wordwrap
|
||||
* for folding is. Pretty cool -- just pass in 'false' for either if
|
||||
* you want to use the default.
|
||||
*
|
||||
* Indent's default is 2 spaces, wordwrap's default is 40 characters. And
|
||||
* you can turn off wordwrap by passing in 0.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
* @param array $array PHP array
|
||||
* @param int $indent Pass in false to use the default, which is 2
|
||||
* @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
|
||||
*/
|
||||
public static function YAMLDump($array,$indent = false,$wordwrap = false) {
|
||||
$spyc = new Spyc;
|
||||
return $spyc->dump($array,$indent,$wordwrap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load YAML into a PHP array from an instantiated object
|
||||
*
|
||||
* The load method, when supplied with a YAML stream (string or file path),
|
||||
* will do its best to convert the YAML into a PHP array. Pretty simple.
|
||||
* Usage:
|
||||
* <code>
|
||||
* $parser = new Spyc;
|
||||
* $array = $parser->load('lucky.yaml');
|
||||
* print_r($array);
|
||||
* </code>
|
||||
* @access public
|
||||
* @return array
|
||||
* @param string $input Path of YAML file or string containing YAML
|
||||
*/
|
||||
public function load($input) {
|
||||
// See what type of input we're talking about
|
||||
// If it's not a file, assume it's a string
|
||||
if (!empty($input) && (strpos($input, "\n") === false)
|
||||
&& file_exists($input)) {
|
||||
$yaml = file($input);
|
||||
} else {
|
||||
$yaml = explode("\n",$input);
|
||||
}
|
||||
// Initiate some objects and values
|
||||
$base = new YAMLNode (1);
|
||||
$base->indent = 0;
|
||||
$this->_lastIndent = 0;
|
||||
$this->_lastNode = $base->id;
|
||||
$this->_inBlock = false;
|
||||
$this->_isInline = false;
|
||||
$this->_nodeId = 2;
|
||||
|
||||
foreach ($yaml as $linenum => $line) {
|
||||
$ifchk = trim($line);
|
||||
|
||||
// If the line starts with a tab (instead of a space), throw a fit.
|
||||
if (preg_match('/^(\t)+(\w+)/', $line)) {
|
||||
$err = 'ERROR: Line '. ($linenum + 1) .' in your input YAML begins'.
|
||||
' with a tab. YAML only recognizes spaces. Please reformat.';
|
||||
die($err);
|
||||
}
|
||||
|
||||
if ($this->_inBlock === false && empty($ifchk)) {
|
||||
continue;
|
||||
} elseif ($this->_inBlock == true && empty($ifchk)) {
|
||||
$last =& $this->_allNodes[$this->_lastNode];
|
||||
$last->data[key($last->data)] .= "\n";
|
||||
} elseif ($ifchk{0} != '#' && substr($ifchk,0,3) != '---') {
|
||||
// Create a new node and get its indent
|
||||
$node = new YAMLNode ($this->_nodeId);
|
||||
$this->_nodeId++;
|
||||
$node->indent = $this->_getIndent($line);
|
||||
|
||||
// Check where the node lies in the hierarchy
|
||||
if ($this->_lastIndent == $node->indent) {
|
||||
// If we're in a block, add the text to the parent's data
|
||||
if ($this->_inBlock === true) {
|
||||
$parent =& $this->_allNodes[$this->_lastNode];
|
||||
$parent->data[key($parent->data)] .= trim($line).$this->_blockEnd;
|
||||
} else {
|
||||
// The current node's parent is the same as the previous node's
|
||||
if (isset($this->_allNodes[$this->_lastNode])) {
|
||||
$node->parent = $this->_allNodes[$this->_lastNode]->parent;
|
||||
}
|
||||
}
|
||||
} elseif ($this->_lastIndent < $node->indent) {
|
||||
if ($this->_inBlock === true) {
|
||||
$parent =& $this->_allNodes[$this->_lastNode];
|
||||
$parent->data[key($parent->data)] .= trim($line).$this->_blockEnd;
|
||||
} elseif ($this->_inBlock === false) {
|
||||
// The current node's parent is the previous node
|
||||
$node->parent = $this->_lastNode;
|
||||
|
||||
// If the value of the last node's data was > or | we need to
|
||||
// start blocking i.e. taking in all lines as a text value until
|
||||
// we drop our indent.
|
||||
$parent =& $this->_allNodes[$node->parent];
|
||||
$this->_allNodes[$node->parent]->children = true;
|
||||
if (is_array($parent->data)) {
|
||||
// if (isset ($parent->data[key($parent->data)]))
|
||||
$chk = $parent->data[key($parent->data)];
|
||||
if ($chk === '>') {
|
||||
$this->_inBlock = true;
|
||||
$this->_blockEnd = ' ';
|
||||
$parent->data[key($parent->data)] =
|
||||
str_replace('>','',$parent->data[key($parent->data)]);
|
||||
$parent->data[key($parent->data)] .= trim($line).' ';
|
||||
$this->_allNodes[$node->parent]->children = false;
|
||||
$this->_lastIndent = $node->indent;
|
||||
} elseif ($chk === '|') {
|
||||
$this->_inBlock = true;
|
||||
$this->_blockEnd = "\n";
|
||||
$parent->data[key($parent->data)] =
|
||||
str_replace('|','',$parent->data[key($parent->data)]);
|
||||
$parent->data[key($parent->data)] .= trim($line)."\n";
|
||||
$this->_allNodes[$node->parent]->children = false;
|
||||
$this->_lastIndent = $node->indent;
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ($this->_lastIndent > $node->indent) {
|
||||
// Any block we had going is dead now
|
||||
if ($this->_inBlock === true) {
|
||||
$this->_inBlock = false;
|
||||
if ($this->_blockEnd = "\n") {
|
||||
$last =& $this->_allNodes[$this->_lastNode];
|
||||
$last->data[key($last->data)] =
|
||||
trim($last->data[key($last->data)]);
|
||||
}
|
||||
}
|
||||
|
||||
// We don't know the parent of the node so we have to find it
|
||||
// foreach ($this->_allNodes as $n) {
|
||||
foreach ($this->_indentSort[$node->indent] as $n) {
|
||||
if ($n->indent == $node->indent) {
|
||||
$node->parent = $n->parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->_inBlock === false) {
|
||||
// Set these properties with information from our current node
|
||||
$this->_lastIndent = $node->indent;
|
||||
// Set the last node
|
||||
$this->_lastNode = $node->id;
|
||||
// Parse the YAML line and return its data
|
||||
$node->data = $this->_parseLine($line);
|
||||
// Add the node to the master list
|
||||
$this->_allNodes[$node->id] = $node;
|
||||
// Add a reference to the parent list
|
||||
$this->_allParent[intval($node->parent)][] = $node->id;
|
||||
// Add a reference to the node in an indent array
|
||||
$this->_indentSort[$node->indent][] =& $this->_allNodes[$node->id];
|
||||
// Add a reference to the node in a References array if this node
|
||||
// has a YAML reference in it.
|
||||
if (
|
||||
( (is_array($node->data)) &&
|
||||
isset($node->data[key($node->data)]) &&
|
||||
(!is_array($node->data[key($node->data)])) )
|
||||
&&
|
||||
( (preg_match('/^&([^ ]+)/',$node->data[key($node->data)]))
|
||||
||
|
||||
(preg_match('/^\*([^ ]+)/',$node->data[key($node->data)])) )
|
||||
) {
|
||||
$this->_haveRefs[] =& $this->_allNodes[$node->id];
|
||||
} elseif (
|
||||
( (is_array($node->data)) &&
|
||||
isset($node->data[key($node->data)]) &&
|
||||
(is_array($node->data[key($node->data)])) )
|
||||
) {
|
||||
// Incomplete reference making code. Ugly, needs cleaned up.
|
||||
foreach ($node->data[key($node->data)] as $d) {
|
||||
if ( !is_array($d) &&
|
||||
( (preg_match('/^&([^ ]+)/',$d))
|
||||
||
|
||||
(preg_match('/^\*([^ ]+)/',$d)) )
|
||||
) {
|
||||
$this->_haveRefs[] =& $this->_allNodes[$node->id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($node);
|
||||
|
||||
// Here we travel through node-space and pick out references (& and *)
|
||||
$this->_linkReferences();
|
||||
|
||||
// Build the PHP array out of node-space
|
||||
$trunk = $this->_buildArray();
|
||||
return $trunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump PHP array to YAML
|
||||
*
|
||||
* The dump method, when supplied with an array, will do its best
|
||||
* to convert the array into friendly YAML. Pretty simple. Feel free to
|
||||
* save the returned string as tasteful.yaml and pass it around.
|
||||
*
|
||||
* Oh, and you can decide how big the indent is and what the wordwrap
|
||||
* for folding is. Pretty cool -- just pass in 'false' for either if
|
||||
* you want to use the default.
|
||||
*
|
||||
* Indent's default is 2 spaces, wordwrap's default is 40 characters. And
|
||||
* you can turn off wordwrap by passing in 0.
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
* @param array $array PHP array
|
||||
* @param int $indent Pass in false to use the default, which is 2
|
||||
* @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
|
||||
*/
|
||||
public function dump($array,$indent = false,$wordwrap = false) {
|
||||
// Dumps to some very clean YAML. We'll have to add some more features
|
||||
// and options soon. And better support for folding.
|
||||
|
||||
// New features and options.
|
||||
if ($indent === false or !is_numeric($indent)) {
|
||||
$this->_dumpIndent = 2;
|
||||
} else {
|
||||
$this->_dumpIndent = $indent;
|
||||
}
|
||||
|
||||
if ($wordwrap === false or !is_numeric($wordwrap)) {
|
||||
$this->_dumpWordWrap = 40;
|
||||
} else {
|
||||
$this->_dumpWordWrap = $wordwrap;
|
||||
}
|
||||
|
||||
// New YAML document
|
||||
$string = "---\n";
|
||||
|
||||
// Start at the base of the array and move through it.
|
||||
foreach ($array as $key => $value) {
|
||||
$string .= $this->_yamlize($key,$value,0);
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**** Private Properties ****/
|
||||
|
||||
/**#@+
|
||||
* @access private
|
||||
* @var mixed
|
||||
*/
|
||||
private $_haveRefs;
|
||||
private $_allNodes;
|
||||
private $_allParent;
|
||||
private $_lastIndent;
|
||||
private $_lastNode;
|
||||
private $_inBlock;
|
||||
private $_isInline;
|
||||
private $_dumpIndent;
|
||||
private $_dumpWordWrap;
|
||||
/**#@-*/
|
||||
|
||||
/**** Public Properties ****/
|
||||
|
||||
/**#@+
|
||||
* @access public
|
||||
* @var mixed
|
||||
*/
|
||||
public $_nodeId;
|
||||
/**#@-*/
|
||||
|
||||
/**** Private Methods ****/
|
||||
|
||||
/**
|
||||
* Attempts to convert a key / value array item to YAML
|
||||
* @access private
|
||||
* @return string
|
||||
* @param $key The name of the key
|
||||
* @param $value The value of the item
|
||||
* @param $indent The indent of the current node
|
||||
*/
|
||||
private function _yamlize($key,$value,$indent) {
|
||||
if (is_array($value)) {
|
||||
// It has children. What to do?
|
||||
// Make it the right kind of item
|
||||
$string = $this->_dumpNode($key,NULL,$indent);
|
||||
// Add the indent
|
||||
$indent += $this->_dumpIndent;
|
||||
// Yamlize the array
|
||||
$string .= $this->_yamlizeArray($value,$indent);
|
||||
} elseif (!is_array($value)) {
|
||||
// It doesn't have children. Yip.
|
||||
$string = $this->_dumpNode($key,$value,$indent);
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to convert an array to YAML
|
||||
* @access private
|
||||
* @return string
|
||||
* @param $array The array you want to convert
|
||||
* @param $indent The indent of the current level
|
||||
*/
|
||||
private function _yamlizeArray($array,$indent) {
|
||||
if (is_array($array)) {
|
||||
$string = '';
|
||||
foreach ($array as $key => $value) {
|
||||
$string .= $this->_yamlize($key,$value,$indent);
|
||||
}
|
||||
return $string;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns YAML from a key and a value
|
||||
* @access private
|
||||
* @return string
|
||||
* @param $key The name of the key
|
||||
* @param $value The value of the item
|
||||
* @param $indent The indent of the current node
|
||||
*/
|
||||
private function _dumpNode($key,$value,$indent) {
|
||||
// do some folding here, for blocks
|
||||
if (strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false) {
|
||||
$value = $this->_doLiteralBlock($value,$indent);
|
||||
} else {
|
||||
$value = $this->_doFolding($value,$indent);
|
||||
}
|
||||
|
||||
if (is_bool($value)) {
|
||||
$value = ($value) ? "true" : "false";
|
||||
}
|
||||
|
||||
$spaces = str_repeat(' ',$indent);
|
||||
|
||||
if (is_int($key)) {
|
||||
// It's a sequence
|
||||
$string = $spaces.'- '.$value."\n";
|
||||
} else {
|
||||
// It's mapped
|
||||
$string = $spaces.$key.': '.$value."\n";
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a literal block for dumping
|
||||
* @access private
|
||||
* @return string
|
||||
* @param $value
|
||||
* @param $indent int The value of the indent
|
||||
*/
|
||||
private function _doLiteralBlock($value,$indent) {
|
||||
$exploded = explode("\n",$value);
|
||||
$newValue = '|';
|
||||
$indent += $this->_dumpIndent;
|
||||
$spaces = str_repeat(' ',$indent);
|
||||
foreach ($exploded as $line) {
|
||||
$newValue .= "\n" . $spaces . trim($line);
|
||||
}
|
||||
return $newValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Folds a string of text, if necessary
|
||||
* @access private
|
||||
* @return string
|
||||
* @param $value The string you wish to fold
|
||||
*/
|
||||
private function _doFolding($value,$indent) {
|
||||
// Don't do anything if wordwrap is set to 0
|
||||
if ($this->_dumpWordWrap === 0) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if (strlen($value) > $this->_dumpWordWrap) {
|
||||
$indent += $this->_dumpIndent;
|
||||
$indent = str_repeat(' ',$indent);
|
||||
$wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent");
|
||||
$value = ">\n".$indent.$wrapped;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/* Methods used in loading */
|
||||
|
||||
/**
|
||||
* Finds and returns the indentation of a YAML line
|
||||
* @access private
|
||||
* @return int
|
||||
* @param string $line A line from the YAML file
|
||||
*/
|
||||
private function _getIndent($line) {
|
||||
preg_match('/^\s{1,}/',$line,$match);
|
||||
if (!empty($match[0])) {
|
||||
$indent = substr_count($match[0],' ');
|
||||
} else {
|
||||
$indent = 0;
|
||||
}
|
||||
return $indent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses YAML code and returns an array for a node
|
||||
* @access private
|
||||
* @return array
|
||||
* @param string $line A line from the YAML file
|
||||
*/
|
||||
private function _parseLine($line) {
|
||||
$line = trim($line);
|
||||
|
||||
$array = array();
|
||||
|
||||
if (preg_match('/^-(.*):$/',$line)) {
|
||||
// It's a mapped sequence
|
||||
$key = trim(substr(substr($line,1),0,-1));
|
||||
$array[$key] = '';
|
||||
} elseif ($line[0] == '-' && substr($line,0,3) != '---') {
|
||||
// It's a list item but not a new stream
|
||||
if (strlen($line) > 1) {
|
||||
$value = trim(substr($line,1));
|
||||
// Set the type of the value. Int, string, etc
|
||||
$value = $this->_toType($value);
|
||||
$array[] = $value;
|
||||
} else {
|
||||
$array[] = array();
|
||||
}
|
||||
} elseif (preg_match('/^(.+):/',$line,$key)) {
|
||||
// It's a key/value pair most likely
|
||||
// If the key is in double quotes pull it out
|
||||
if (preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) {
|
||||
$value = trim(str_replace($matches[1],'',$line));
|
||||
$key = $matches[2];
|
||||
} else {
|
||||
// Do some guesswork as to the key and the value
|
||||
$explode = explode(':',$line);
|
||||
$key = trim($explode[0]);
|
||||
array_shift($explode);
|
||||
$value = trim(implode(':',$explode));
|
||||
}
|
||||
|
||||
// Set the type of the value. Int, string, etc
|
||||
$value = $this->_toType($value);
|
||||
if (empty($key)) {
|
||||
$array[] = $value;
|
||||
} else {
|
||||
$array[$key] = $value;
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the type of the passed value, returns the value as the new type.
|
||||
* @access private
|
||||
* @param string $value
|
||||
* @return mixed
|
||||
*/
|
||||
private function _toType($value) {
|
||||
if (preg_match('/^("(.*)"|\'(.*)\')/',$value,$matches)) {
|
||||
$value = (string)preg_replace('/(\'\'|\\\\\')/',"'",end($matches));
|
||||
$value = preg_replace('/\\\\"/','"',$value);
|
||||
} elseif (preg_match('/^\\[(.+)\\]$/',$value,$matches)) {
|
||||
// Inline Sequence
|
||||
|
||||
// Take out strings sequences and mappings
|
||||
$explode = $this->_inlineEscape($matches[1]);
|
||||
|
||||
// Propogate value array
|
||||
$value = array();
|
||||
foreach ($explode as $v) {
|
||||
$value[] = $this->_toType($v);
|
||||
}
|
||||
} elseif (strpos($value,': ')!==false && !preg_match('/^{(.+)/',$value)) {
|
||||
// It's a map
|
||||
$array = explode(': ',$value);
|
||||
$key = trim($array[0]);
|
||||
array_shift($array);
|
||||
$value = trim(implode(': ',$array));
|
||||
$value = $this->_toType($value);
|
||||
$value = array($key => $value);
|
||||
} elseif (preg_match("/{(.+)}$/",$value,$matches)) {
|
||||
// Inline Mapping
|
||||
|
||||
// Take out strings sequences and mappings
|
||||
$explode = $this->_inlineEscape($matches[1]);
|
||||
|
||||
// Propogate value array
|
||||
$array = array();
|
||||
foreach ($explode as $v) {
|
||||
$array = $array + $this->_toType($v);
|
||||
}
|
||||
$value = $array;
|
||||
} elseif (strtolower($value) == 'null' or $value == '' or $value == '~') {
|
||||
$value = NULL;
|
||||
} elseif (preg_match ('/^[0-9]+$/', $value)) {
|
||||
$value = (int)$value;
|
||||
} elseif (in_array(strtolower($value),
|
||||
array('true', 'on', '+', 'yes', 'y'))) {
|
||||
$value = TRUE;
|
||||
} elseif (in_array(strtolower($value),
|
||||
array('false', 'off', '-', 'no', 'n'))) {
|
||||
$value = FALSE;
|
||||
} elseif (is_numeric($value)) {
|
||||
$value = (float)$value;
|
||||
} else {
|
||||
// Just a normal string, right?
|
||||
$value = trim(preg_replace('/#(.+)$/','',$value));
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in inlines to check for more inlines or quoted strings
|
||||
* @access private
|
||||
* @return array
|
||||
*/
|
||||
private function _inlineEscape($inline) {
|
||||
// There's gotta be a cleaner way to do this...
|
||||
// While pure sequences seem to be nesting just fine,
|
||||
// pure mappings and mappings with sequences inside can't go very
|
||||
// deep. This needs to be fixed.
|
||||
|
||||
$saved_strings = array();
|
||||
|
||||
// Check for strings
|
||||
$regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
|
||||
if (preg_match_all($regex,$inline,$strings)) {
|
||||
$saved_strings = $strings[0];
|
||||
$inline = preg_replace($regex,'YAMLString',$inline);
|
||||
}
|
||||
unset($regex);
|
||||
|
||||
// Check for sequences
|
||||
if (preg_match_all('/\[(.+)\]/U',$inline,$seqs)) {
|
||||
$inline = preg_replace('/\[(.+)\]/U','YAMLSeq',$inline);
|
||||
$seqs = $seqs[0];
|
||||
}
|
||||
|
||||
// Check for mappings
|
||||
if (preg_match_all('/{(.+)}/U',$inline,$maps)) {
|
||||
$inline = preg_replace('/{(.+)}/U','YAMLMap',$inline);
|
||||
$maps = $maps[0];
|
||||
}
|
||||
|
||||
$explode = explode(', ',$inline);
|
||||
|
||||
|
||||
// Re-add the sequences
|
||||
if (!empty($seqs)) {
|
||||
$i = 0;
|
||||
foreach ($explode as $key => $value) {
|
||||
if (strpos($value,'YAMLSeq') !== false) {
|
||||
$explode[$key] = str_replace('YAMLSeq',$seqs[$i],$value);
|
||||
++$i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-add the mappings
|
||||
if (!empty($maps)) {
|
||||
$i = 0;
|
||||
foreach ($explode as $key => $value) {
|
||||
if (strpos($value,'YAMLMap') !== false) {
|
||||
$explode[$key] = str_replace('YAMLMap',$maps[$i],$value);
|
||||
++$i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Re-add the strings
|
||||
if (!empty($saved_strings)) {
|
||||
$i = 0;
|
||||
foreach ($explode as $key => $value) {
|
||||
while (strpos($value,'YAMLString') !== false) {
|
||||
$explode[$key] = preg_replace('/YAMLString/',$saved_strings[$i],$value, 1);
|
||||
++$i;
|
||||
$value = $explode[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $explode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the PHP array from all the YAML nodes we've gathered
|
||||
* @access private
|
||||
* @return array
|
||||
*/
|
||||
private function _buildArray() {
|
||||
$trunk = array();
|
||||
|
||||
if (!isset($this->_indentSort[0])) {
|
||||
return $trunk;
|
||||
}
|
||||
|
||||
foreach ($this->_indentSort[0] as $n) {
|
||||
if (empty($n->parent)) {
|
||||
$this->_nodeArrayizeData($n);
|
||||
// Check for references and copy the needed data to complete them.
|
||||
$this->_makeReferences($n);
|
||||
// Merge our data with the big array we're building
|
||||
$trunk = $this->_array_kmerge($trunk,$n->data);
|
||||
}
|
||||
}
|
||||
|
||||
return $trunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses node-space and sets references (& and *) accordingly
|
||||
* @access private
|
||||
* @return bool
|
||||
*/
|
||||
private function _linkReferences() {
|
||||
if (is_array($this->_haveRefs)) {
|
||||
foreach ($this->_haveRefs as $node) {
|
||||
if (!empty($node->data)) {
|
||||
$key = key($node->data);
|
||||
// If it's an array, don't check.
|
||||
if (is_array($node->data[$key])) {
|
||||
foreach ($node->data[$key] as $k => $v) {
|
||||
$this->_linkRef($node,$key,$k,$v);
|
||||
}
|
||||
} else {
|
||||
$this->_linkRef($node,$key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function _linkRef(&$n,$key,$k = NULL,$v = NULL) {
|
||||
if (empty($k) && empty($v)) {
|
||||
// Look for &refs
|
||||
if (preg_match('/^&([^ ]+)/',$n->data[$key],$matches)) {
|
||||
// Flag the node so we know it's a reference
|
||||
$this->_allNodes[$n->id]->ref = substr($matches[0],1);
|
||||
$this->_allNodes[$n->id]->data[$key] =
|
||||
substr($n->data[$key],strlen($matches[0])+1);
|
||||
// Look for *refs
|
||||
} elseif (preg_match('/^\*([^ ]+)/',$n->data[$key],$matches)) {
|
||||
$ref = substr($matches[0],1);
|
||||
// Flag the node as having a reference
|
||||
$this->_allNodes[$n->id]->refKey = $ref;
|
||||
}
|
||||
} elseif (!empty($k) && !empty($v)) {
|
||||
if (preg_match('/^&([^ ]+)/',$v,$matches)) {
|
||||
// Flag the node so we know it's a reference
|
||||
$this->_allNodes[$n->id]->ref = substr($matches[0],1);
|
||||
$this->_allNodes[$n->id]->data[$key][$k] =
|
||||
substr($v,strlen($matches[0])+1);
|
||||
// Look for *refs
|
||||
} elseif (preg_match('/^\*([^ ]+)/',$v,$matches)) {
|
||||
$ref = substr($matches[0],1);
|
||||
// Flag the node as having a reference
|
||||
$this->_allNodes[$n->id]->refKey = $ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the children of a node and aids in the building of the PHP array
|
||||
* @access private
|
||||
* @param int $nid The id of the node whose children we're gathering
|
||||
* @return array
|
||||
*/
|
||||
private function _gatherChildren($nid) {
|
||||
$return = array();
|
||||
$node =& $this->_allNodes[$nid];
|
||||
if (is_array ($this->_allParent[$node->id])) {
|
||||
foreach ($this->_allParent[$node->id] as $nodeZ) {
|
||||
$z =& $this->_allNodes[$nodeZ];
|
||||
// We found a child
|
||||
$this->_nodeArrayizeData($z);
|
||||
// Check for references
|
||||
$this->_makeReferences($z);
|
||||
// Merge with the big array we're returning
|
||||
// The big array being all the data of the children of our parent node
|
||||
$return = $this->_array_kmerge($return,$z->data);
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a node's data and its children's data into a PHP array
|
||||
*
|
||||
* @access private
|
||||
* @param array $node The node which you want to arrayize
|
||||
* @return boolean
|
||||
*/
|
||||
private function _nodeArrayizeData(&$node) {
|
||||
if (is_array($node->data) && $node->children == true) {
|
||||
// This node has children, so we need to find them
|
||||
$childs = $this->_gatherChildren($node->id);
|
||||
// We've gathered all our children's data and are ready to use it
|
||||
$key = key($node->data);
|
||||
$key = empty($key) ? 0 : $key;
|
||||
// If it's an array, add to it of course
|
||||
if (isset ($node->data[$key])) {
|
||||
if (is_array($node->data[$key])) {
|
||||
$node->data[$key] = $this->_array_kmerge($node->data[$key],$childs);
|
||||
} else {
|
||||
$node->data[$key] = $childs;
|
||||
}
|
||||
} else {
|
||||
$node->data[$key] = $childs;
|
||||
}
|
||||
} elseif (!is_array($node->data) && $node->children == true) {
|
||||
// Same as above, find the children of this node
|
||||
$childs = $this->_gatherChildren($node->id);
|
||||
$node->data = array();
|
||||
$node->data[] = $childs;
|
||||
}
|
||||
|
||||
// We edited $node by reference, so just return true
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverses node-space and copies references to / from this object.
|
||||
* @access private
|
||||
* @param object $z A node whose references we wish to make real
|
||||
* @return bool
|
||||
*/
|
||||
private function _makeReferences(&$z) {
|
||||
// It is a reference
|
||||
if (isset($z->ref)) {
|
||||
$key = key($z->data);
|
||||
// Copy the data to this object for easy retrieval later
|
||||
$this->ref[$z->ref] =& $z->data[$key];
|
||||
// It has a reference
|
||||
} elseif (isset($z->refKey)) {
|
||||
if (isset($this->ref[$z->refKey])) {
|
||||
$key = key($z->data);
|
||||
// Copy the data from this object to make the node a real reference
|
||||
$z->data[$key] =& $this->ref[$z->refKey];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merges arrays and maintains numeric keys.
|
||||
*
|
||||
* An ever-so-slightly modified version of the array_kmerge() function posted
|
||||
* to php.net by mail at nospam dot iaindooley dot com on 2004-04-08.
|
||||
*
|
||||
* http://us3.php.net/manual/en/function.array-merge.php
|
||||
*
|
||||
* @access private
|
||||
* @param array $arr1
|
||||
* @param array $arr2
|
||||
* @return array
|
||||
*/
|
||||
private function _array_kmerge($arr1,$arr2) {
|
||||
if(!is_array($arr1)) $arr1 = array();
|
||||
if(!is_array($arr2)) $arr2 = array();
|
||||
|
||||
$keys = array_merge(array_keys($arr1),array_keys($arr2));
|
||||
$vals = array_merge(array_values($arr1),array_values($arr2));
|
||||
$ret = array();
|
||||
foreach($keys as $key) {
|
||||
list($unused,$val) = each($vals);
|
||||
if (isset($ret[$key]) and is_int($key)) $ret[] = $val; else $ret[$key] = $val;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
?>
|
Loading…
Reference in New Issue
Block a user