Struggeling with relocating
Dieser Commit ist enthalten in:
Commit
89ea01c429
301 geänderte Dateien mit 59926 neuen und 0 gelöschten Zeilen
804
lib/json.php
Normale Datei
804
lib/json.php
Normale Datei
|
|
@ -0,0 +1,804 @@
|
|||
<?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$
|
||||
* @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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
2214
lib/phpmailer/php5/class.phpmailer.php
Normale Datei
2214
lib/phpmailer/php5/class.phpmailer.php
Normale Datei
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
727
lib/phpmailer/php5/class.smtp.php
Normale Datei
727
lib/phpmailer/php5/class.smtp.php
Normale Datei
|
|
@ -0,0 +1,727 @@
|
|||
<?php
|
||||
/*~ class.smtp.php
|
||||
.---------------------------------------------------------------------------.
|
||||
| Software: PHPMailer - PHP email class |
|
||||
| Version: 5.1 |
|
||||
| Contact: via sourceforge.net support pages (also www.codeworxtech.com) |
|
||||
| Info: http://phpmailer.sourceforge.net |
|
||||
| Support: http://sourceforge.net/projects/phpmailer/ |
|
||||
| ------------------------------------------------------------------------- |
|
||||
| Admin: Andy Prevost (project admininistrator) |
|
||||
| Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
|
||||
| : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
|
||||
| Founder: Brent R. Matzelle (original founder) |
|
||||
| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
|
||||
| Copyright (c) 2001-2003, Brent R. Matzelle |
|
||||
| ------------------------------------------------------------------------- |
|
||||
| License: Distributed under the Lesser General Public License (LGPL) |
|
||||
| http://www.gnu.org/copyleft/lesser.html |
|
||||
| This program is distributed in the hope that it will be useful - WITHOUT |
|
||||
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
||||
| FITNESS FOR A PARTICULAR PURPOSE. |
|
||||
| ------------------------------------------------------------------------- |
|
||||
| We offer a number of paid services (www.codeworxtech.com): |
|
||||
| - Web Hosting on highly optimized fast and secure servers |
|
||||
| - Technology Consulting |
|
||||
| - Oursourcing (highly qualified programmers and graphic designers) |
|
||||
'---------------------------------------------------------------------------'
|
||||
*/
|
||||
/**
|
||||
* PHPMailer - PHP SMTP email transport class
|
||||
* NOTE: Designed for use with PHP version 5 and up
|
||||
* @package PHPMailer
|
||||
* @author Andy Prevost
|
||||
* @author Marcus Bointon
|
||||
* @copyright 2004 - 2008 Andy Prevost
|
||||
* @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
|
||||
* @version $Id$
|
||||
*/
|
||||
/**
|
||||
* SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
|
||||
* commands except TURN which will always return a not implemented
|
||||
* error. SMTP also provides some utility methods for sending mail
|
||||
* to an SMTP server.
|
||||
* original author: Chris Ryan
|
||||
*/
|
||||
class SMTP
|
||||
{
|
||||
/**
|
||||
* SMTP server port
|
||||
* @var int
|
||||
*/
|
||||
public $SMTP_PORT = 25;
|
||||
/**
|
||||
* SMTP reply line ending
|
||||
* @var string
|
||||
*/
|
||||
public $CRLF = "\r\n";
|
||||
/**
|
||||
* Sets whether debugging is turned on
|
||||
* @var bool
|
||||
*/
|
||||
public $do_debug; // the level of debug to perform
|
||||
/**
|
||||
* Sets VERP use on/off (default is off)
|
||||
* @var bool
|
||||
*/
|
||||
public $do_verp = false;
|
||||
/////////////////////////////////////////////////
|
||||
// PROPERTIES, PRIVATE AND PROTECTED
|
||||
/////////////////////////////////////////////////
|
||||
private $smtp_conn; // the socket to the server
|
||||
private $error; // error if any on the last call
|
||||
private $helo_rply; // the reply the server sent to us for HELO
|
||||
/**
|
||||
* Initialize the class so that the data is in a known state.
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->smtp_conn = 0;
|
||||
$this->error = null;
|
||||
$this->helo_rply = null;
|
||||
$this->do_debug = 0;
|
||||
}
|
||||
/////////////////////////////////////////////////
|
||||
// CONNECTION FUNCTIONS
|
||||
/////////////////////////////////////////////////
|
||||
/**
|
||||
* Connect to the server specified on the port specified.
|
||||
* If the port is not specified use the default SMTP_PORT.
|
||||
* If tval is specified then a connection will try and be
|
||||
* established with the server for that number of seconds.
|
||||
* If tval is not specified the default is 30 seconds to
|
||||
* try on the connection.
|
||||
*
|
||||
* SMTP CODE SUCCESS: 220
|
||||
* SMTP CODE FAILURE: 421
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function Connect($host, $port = 0, $tval = 30)
|
||||
{
|
||||
// set the error val to null so there is no confusion
|
||||
$this->error = null;
|
||||
// make sure we are __not__ connected
|
||||
if ($this->connected()){
|
||||
// already connected, generate error
|
||||
$this->error = array(
|
||||
"error" => "Already connected to a server");
|
||||
return false;
|
||||
}
|
||||
if (empty($port)){
|
||||
$port = $this->SMTP_PORT;
|
||||
}
|
||||
// connect to the smtp server
|
||||
$this->smtp_conn = @fsockopen($host, // the host of the server
|
||||
$port, // the port to use
|
||||
$errno, // error number if any
|
||||
$errstr, // error message if any
|
||||
$tval); // give up after ? secs
|
||||
// verify we connected properly
|
||||
if (empty($this->smtp_conn)){
|
||||
$this->error = array(
|
||||
"error" => "Failed to connect to server",
|
||||
"errno" => $errno,
|
||||
"errstr" => $errstr);
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// SMTP server can take longer to respond, give longer timeout for first read
|
||||
// Windows does not have support for this timeout function
|
||||
if (substr(PHP_OS, 0, 3) != "WIN")
|
||||
socket_set_timeout($this->smtp_conn, $tval, 0);
|
||||
// get any announcement
|
||||
$announce = $this->get_lines();
|
||||
if ($this->do_debug >= 2){
|
||||
echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Initiate a TLS communication with the server.
|
||||
*
|
||||
* SMTP CODE 220 Ready to start TLS
|
||||
* SMTP CODE 501 Syntax error (no parameters allowed)
|
||||
* SMTP CODE 454 TLS not available due to temporary reason
|
||||
* @access public
|
||||
* @return bool success
|
||||
*/
|
||||
public function StartTLS()
|
||||
{
|
||||
$this->error = null; // to avoid confusion
|
||||
if (!$this->connected()){
|
||||
$this->error = array(
|
||||
"error" => "Called StartTLS() without being connected");
|
||||
return false;
|
||||
}
|
||||
fputs($this->smtp_conn, "STARTTLS" . $this->CRLF);
|
||||
$rply = $this->get_lines();
|
||||
$code = substr($rply, 0, 3);
|
||||
if ($this->do_debug >= 2){
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
if ($code != 220){
|
||||
$this->error = array(
|
||||
"error" => "STARTTLS not accepted from server",
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Begin encrypted connection
|
||||
if (!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Performs SMTP authentication. Must be run after running the
|
||||
* Hello() method. Returns true if successfully authenticated.
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function Authenticate($username, $password)
|
||||
{
|
||||
// Start authentication
|
||||
fputs($this->smtp_conn, "AUTH LOGIN" . $this->CRLF);
|
||||
$rply = $this->get_lines();
|
||||
$code = substr($rply, 0, 3);
|
||||
if ($code != 334){
|
||||
$this->error = array(
|
||||
"error" => "AUTH not accepted from server",
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Send encoded username
|
||||
fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
|
||||
$rply = $this->get_lines();
|
||||
$code = substr($rply, 0, 3);
|
||||
if ($code != 334){
|
||||
$this->error = array(
|
||||
"error" => "Username not accepted from server",
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Send encoded password
|
||||
fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
|
||||
$rply = $this->get_lines();
|
||||
$code = substr($rply, 0, 3);
|
||||
if ($code != 235){
|
||||
$this->error = array(
|
||||
"error" => "Password not accepted from server",
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Returns true if connected to a server otherwise false
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function Connected()
|
||||
{
|
||||
if (!empty($this->smtp_conn)){
|
||||
$sock_status = socket_get_status($this->smtp_conn);
|
||||
if ($sock_status["eof"]){
|
||||
// the socket is valid but we are not connected
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";
|
||||
}
|
||||
$this->Close();
|
||||
return false;
|
||||
}
|
||||
return true; // everything looks good
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Closes the socket and cleans up the state of the class.
|
||||
* It is not considered good to use this function without
|
||||
* first trying to use QUIT.
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function Close()
|
||||
{
|
||||
$this->error = null; // so there is no confusion
|
||||
$this->helo_rply = null;
|
||||
if (!empty($this->smtp_conn)){
|
||||
// close the connection and cleanup
|
||||
fclose($this->smtp_conn);
|
||||
$this->smtp_conn = 0;
|
||||
}
|
||||
}
|
||||
/////////////////////////////////////////////////
|
||||
// SMTP COMMANDS
|
||||
/////////////////////////////////////////////////
|
||||
/**
|
||||
* Issues a data command and sends the msg_data to the server
|
||||
* finializing the mail transaction. $msg_data is the message
|
||||
* that is to be send with the headers. Each header needs to be
|
||||
* on a single line followed by a <CRLF> with the message headers
|
||||
* and the message body being seperated by and additional <CRLF>.
|
||||
*
|
||||
* Implements rfc 821: DATA <CRLF>
|
||||
*
|
||||
* SMTP CODE INTERMEDIATE: 354
|
||||
* [data]
|
||||
* <CRLF>.<CRLF>
|
||||
* SMTP CODE SUCCESS: 250
|
||||
* SMTP CODE FAILURE: 552,554,451,452
|
||||
* SMTP CODE FAILURE: 451,554
|
||||
* SMTP CODE ERROR : 500,501,503,421
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function Data($msg_data)
|
||||
{
|
||||
$this->error = null; // so no confusion is caused
|
||||
if (!$this->connected()){
|
||||
$this->error = array(
|
||||
"error" => "Called Data() without being connected");
|
||||
return false;
|
||||
}
|
||||
fputs($this->smtp_conn, "DATA" . $this->CRLF);
|
||||
$rply = $this->get_lines();
|
||||
$code = substr($rply, 0, 3);
|
||||
if ($this->do_debug >= 2){
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
if ($code != 354){
|
||||
$this->error = array(
|
||||
"error" => "DATA command not accepted from server",
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/* the server is ready to accept data!
|
||||
* according to rfc 821 we should not send more than 1000
|
||||
* including the CRLF
|
||||
* characters on a single line so we will break the data up
|
||||
* into lines by \r and/or \n then if needed we will break
|
||||
* each of those into smaller lines to fit within the limit.
|
||||
* in addition we will be looking for lines that start with
|
||||
* a period '.' and append and additional period '.' to that
|
||||
* line. NOTE: this does not count towards limit.
|
||||
*/
|
||||
// normalize the line breaks so we know the explode works
|
||||
$msg_data = str_replace("\r\n", "\n", $msg_data);
|
||||
$msg_data = str_replace("\r", "\n", $msg_data);
|
||||
$lines = explode("\n", $msg_data);
|
||||
/* we need to find a good way to determine is headers are
|
||||
* in the msg_data or if it is a straight msg body
|
||||
* currently I am assuming rfc 822 definitions of msg headers
|
||||
* and if the first field of the first line (':' sperated)
|
||||
* does not contain a space then it _should_ be a header
|
||||
* and we can process all lines before a blank "" line as
|
||||
* headers.
|
||||
*/
|
||||
$field = substr($lines[0], 0, strpos($lines[0], ":"));
|
||||
$in_headers = false;
|
||||
if (!empty($field) && !strstr($field, " ")){
|
||||
$in_headers = true;
|
||||
}
|
||||
$max_line_length = 998; // used below; set here for ease in change
|
||||
while (list (, $line) = @each($lines)){
|
||||
$lines_out = null;
|
||||
if ($line == "" && $in_headers){
|
||||
$in_headers = false;
|
||||
}
|
||||
// ok we need to break this line up into several smaller lines
|
||||
while (strlen($line) > $max_line_length){
|
||||
$pos = strrpos(substr($line, 0, $max_line_length), " ");
|
||||
// Patch to fix DOS attack
|
||||
if (!$pos){
|
||||
$pos = $max_line_length - 1;
|
||||
$lines_out[] = substr($line, 0, $pos);
|
||||
$line = substr($line, $pos);
|
||||
}else{
|
||||
$lines_out[] = substr($line, 0, $pos);
|
||||
$line = substr($line, $pos + 1);
|
||||
}
|
||||
/* if processing headers add a LWSP-char to the front of new line
|
||||
* rfc 822 on long msg headers
|
||||
*/
|
||||
if ($in_headers){
|
||||
$line = "\t" . $line;
|
||||
}
|
||||
}
|
||||
$lines_out[] = $line;
|
||||
// send the lines to the server
|
||||
while (list (, $line_out) = @each($lines_out)){
|
||||
if (strlen($line_out) > 0){
|
||||
if (substr($line_out, 0, 1) == "."){
|
||||
$line_out = "." . $line_out;
|
||||
}
|
||||
}
|
||||
fputs($this->smtp_conn, $line_out . $this->CRLF);
|
||||
}
|
||||
}
|
||||
// message data has been sent
|
||||
fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
|
||||
$rply = $this->get_lines();
|
||||
$code = substr($rply, 0, 3);
|
||||
if ($this->do_debug >= 2){
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
if ($code != 250){
|
||||
$this->error = array(
|
||||
"error" => "DATA not accepted from server",
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Sends the HELO command to the smtp server.
|
||||
* This makes sure that we and the server are in
|
||||
* the same known state.
|
||||
*
|
||||
* Implements from rfc 821: HELO <SP> <domain> <CRLF>
|
||||
*
|
||||
* SMTP CODE SUCCESS: 250
|
||||
* SMTP CODE ERROR : 500, 501, 504, 421
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function Hello($host = '')
|
||||
{
|
||||
$this->error = null; // so no confusion is caused
|
||||
if (!$this->connected()){
|
||||
$this->error = array(
|
||||
"error" => "Called Hello() without being connected");
|
||||
return false;
|
||||
}
|
||||
// if hostname for HELO was not specified send default
|
||||
if (empty($host)){
|
||||
// determine appropriate default to send to server
|
||||
$host = "localhost";
|
||||
}
|
||||
// Send extended hello first (RFC 2821)
|
||||
if (!$this->SendHello("EHLO", $host)){
|
||||
if (!$this->SendHello("HELO", $host)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Sends a HELO/EHLO command.
|
||||
* @access private
|
||||
* @return bool
|
||||
*/
|
||||
private function SendHello($hello, $host)
|
||||
{
|
||||
fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
|
||||
$rply = $this->get_lines();
|
||||
$code = substr($rply, 0, 3);
|
||||
if ($this->do_debug >= 2){
|
||||
echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
if ($code != 250){
|
||||
$this->error = array(
|
||||
"error" => $hello . " not accepted from server",
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
$this->helo_rply = $rply;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Starts a mail transaction from the email address specified in
|
||||
* $from. Returns true if successful or false otherwise. If True
|
||||
* the mail transaction is started and then one or more Recipient
|
||||
* commands may be called followed by a Data command.
|
||||
*
|
||||
* Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
|
||||
*
|
||||
* SMTP CODE SUCCESS: 250
|
||||
* SMTP CODE SUCCESS: 552,451,452
|
||||
* SMTP CODE SUCCESS: 500,501,421
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function Mail($from)
|
||||
{
|
||||
$this->error = null; // so no confusion is caused
|
||||
if (!$this->connected()){
|
||||
$this->error = array(
|
||||
"error" => "Called Mail() without being connected");
|
||||
return false;
|
||||
}
|
||||
$useVerp = ($this->do_verp ? "XVERP" : "");
|
||||
fputs($this->smtp_conn, "MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
|
||||
$rply = $this->get_lines();
|
||||
$code = substr($rply, 0, 3);
|
||||
if ($this->do_debug >= 2){
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
if ($code != 250){
|
||||
$this->error = array(
|
||||
"error" => "MAIL not accepted from server",
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Sends the quit command to the server and then closes the socket
|
||||
* if there is no error or the $close_on_error argument is true.
|
||||
*
|
||||
* Implements from rfc 821: QUIT <CRLF>
|
||||
*
|
||||
* SMTP CODE SUCCESS: 221
|
||||
* SMTP CODE ERROR : 500
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function Quit($close_on_error = true)
|
||||
{
|
||||
$this->error = null; // so there is no confusion
|
||||
if (!$this->connected()){
|
||||
$this->error = array(
|
||||
"error" => "Called Quit() without being connected");
|
||||
return false;
|
||||
}
|
||||
// send the quit command to the server
|
||||
fputs($this->smtp_conn, "quit" . $this->CRLF);
|
||||
// get any good-bye messages
|
||||
$byemsg = $this->get_lines();
|
||||
if ($this->do_debug >= 2){
|
||||
echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';
|
||||
}
|
||||
$rval = true;
|
||||
$e = null;
|
||||
$code = substr($byemsg, 0, 3);
|
||||
if ($code != 221){
|
||||
// use e as a tmp var cause Close will overwrite $this->error
|
||||
$e = array(
|
||||
"error" => "SMTP server rejected quit command",
|
||||
"smtp_code" => $code,
|
||||
"smtp_rply" => substr($byemsg, 4));
|
||||
$rval = false;
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';
|
||||
}
|
||||
}
|
||||
if (empty($e) || $close_on_error){
|
||||
$this->Close();
|
||||
}
|
||||
return $rval;
|
||||
}
|
||||
/**
|
||||
* Sends the command RCPT to the SMTP server with the TO: argument of $to.
|
||||
* Returns true if the recipient was accepted false if it was rejected.
|
||||
*
|
||||
* Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
|
||||
*
|
||||
* SMTP CODE SUCCESS: 250,251
|
||||
* SMTP CODE FAILURE: 550,551,552,553,450,451,452
|
||||
* SMTP CODE ERROR : 500,501,503,421
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function Recipient($to)
|
||||
{
|
||||
$this->error = null; // so no confusion is caused
|
||||
if (!$this->connected()){
|
||||
$this->error = array(
|
||||
"error" => "Called Recipient() without being connected");
|
||||
return false;
|
||||
}
|
||||
fputs($this->smtp_conn, "RCPT TO:<" . $to . ">" . $this->CRLF);
|
||||
$rply = $this->get_lines();
|
||||
$code = substr($rply, 0, 3);
|
||||
if ($this->do_debug >= 2){
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
if ($code != 250 && $code != 251){
|
||||
$this->error = array(
|
||||
"error" => "RCPT not accepted from server",
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Sends the RSET command to abort and transaction that is
|
||||
* currently in progress. Returns true if successful false
|
||||
* otherwise.
|
||||
*
|
||||
* Implements rfc 821: RSET <CRLF>
|
||||
*
|
||||
* SMTP CODE SUCCESS: 250
|
||||
* SMTP CODE ERROR : 500,501,504,421
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function Reset()
|
||||
{
|
||||
$this->error = null; // so no confusion is caused
|
||||
if (!$this->connected()){
|
||||
$this->error = array(
|
||||
"error" => "Called Reset() without being connected");
|
||||
return false;
|
||||
}
|
||||
fputs($this->smtp_conn, "RSET" . $this->CRLF);
|
||||
$rply = $this->get_lines();
|
||||
$code = substr($rply, 0, 3);
|
||||
if ($this->do_debug >= 2){
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
if ($code != 250){
|
||||
$this->error = array(
|
||||
"error" => "RSET failed",
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Starts a mail transaction from the email address specified in
|
||||
* $from. Returns true if successful or false otherwise. If True
|
||||
* the mail transaction is started and then one or more Recipient
|
||||
* commands may be called followed by a Data command. This command
|
||||
* will send the message to the users terminal if they are logged
|
||||
* in and send them an email.
|
||||
*
|
||||
* Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
|
||||
*
|
||||
* SMTP CODE SUCCESS: 250
|
||||
* SMTP CODE SUCCESS: 552,451,452
|
||||
* SMTP CODE SUCCESS: 500,501,502,421
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function SendAndMail($from)
|
||||
{
|
||||
$this->error = null; // so no confusion is caused
|
||||
if (!$this->connected()){
|
||||
$this->error = array(
|
||||
"error" => "Called SendAndMail() without being connected");
|
||||
return false;
|
||||
}
|
||||
fputs($this->smtp_conn, "SAML FROM:" . $from . $this->CRLF);
|
||||
$rply = $this->get_lines();
|
||||
$code = substr($rply, 0, 3);
|
||||
if ($this->do_debug >= 2){
|
||||
echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
if ($code != 250){
|
||||
$this->error = array(
|
||||
"error" => "SAML not accepted from server",
|
||||
"smtp_code" => $code,
|
||||
"smtp_msg" => substr($rply, 4));
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* This is an optional command for SMTP that this class does not
|
||||
* support. This method is here to make the RFC821 Definition
|
||||
* complete for this class and __may__ be implimented in the future
|
||||
*
|
||||
* Implements from rfc 821: TURN <CRLF>
|
||||
*
|
||||
* SMTP CODE SUCCESS: 250
|
||||
* SMTP CODE FAILURE: 502
|
||||
* SMTP CODE ERROR : 500, 503
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function Turn()
|
||||
{
|
||||
$this->error = array(
|
||||
"error" => "This method, TURN, of the SMTP " . "is not implemented");
|
||||
if ($this->do_debug >= 1){
|
||||
echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Get the current error
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
/////////////////////////////////////////////////
|
||||
// INTERNAL FUNCTIONS
|
||||
/////////////////////////////////////////////////
|
||||
/**
|
||||
* Read in as many lines as possible
|
||||
* either before eof or socket timeout occurs on the operation.
|
||||
* With SMTP we can tell if we have more lines to read if the
|
||||
* 4th character is '-' symbol. If it is a space then we don't
|
||||
* need to read anything else.
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
private function get_lines()
|
||||
{
|
||||
$data = "";
|
||||
while ($str = @fgets($this->smtp_conn, 515)){
|
||||
if ($this->do_debug >= 4){
|
||||
echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';
|
||||
echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';
|
||||
}
|
||||
$data .= $str;
|
||||
if ($this->do_debug >= 4){
|
||||
echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';
|
||||
}
|
||||
// if 4th character is a space, we are done reading, break the loop
|
||||
if (substr($str, 3, 1) == " "){
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
?>
|
||||
388
lib/template.php
Normale Datei
388
lib/template.php
Normale Datei
|
|
@ -0,0 +1,388 @@
|
|||
<?php
|
||||
/**
|
||||
* Template class. By Nathan Codding of the phpBB group.
|
||||
*
|
||||
* The interface was originally inspired by PHPLib templates,
|
||||
* and the template file formats are quite similar.
|
||||
*
|
||||
* Some small modifications for MySQLDumper done by Daniel Schlichtholz
|
||||
*
|
||||
* @author Nathan Codding
|
||||
* @package MySQLDumper
|
||||
* @lastmodified $Date$
|
||||
*/
|
||||
/***************************************************************************
|
||||
* template.php
|
||||
* -------------------
|
||||
* begin : Saturday, Feb 13, 2001
|
||||
* copyright : (C) 2001 The phpBB Group
|
||||
* email : support@phpbb.com
|
||||
*
|
||||
***************************************************************************/
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
if (!defined('MSD_VERSION'))
|
||||
die('No direct access.');
|
||||
define('TPL_DEBUG', 0); // used if evaluationg of template fails
|
||||
class MSDTemplate
|
||||
{
|
||||
var $classname = "MSDTemplate";
|
||||
// variable that holds all the data we'll be substituting into
|
||||
// the compiled templates.
|
||||
// ...
|
||||
// This will end up being a multi-dimensional array like this:
|
||||
// $this->_tpldata[block.][iteration#][child.][iteration#][child2.][iteration#][variablename] == value
|
||||
// if it's a root-level variable, it'll be like this:
|
||||
// $this->_tpldata[.][0][varname] == value
|
||||
var $_tpldata = array();
|
||||
// Hash of filenames for each template handle.
|
||||
var $files = array();
|
||||
// Root template directory.
|
||||
var $root = "";
|
||||
// this will hash handle names to the compiled code for that handle.
|
||||
var $compiled_code = array();
|
||||
// This will hold the uncompiled code for that handle.
|
||||
var $uncompiled_code = array();
|
||||
/**
|
||||
* Constructor. Simply sets the root dir.
|
||||
*
|
||||
*/
|
||||
function MSDTemplate($root = ".")
|
||||
{
|
||||
$this->set_rootdir($root);
|
||||
}
|
||||
/**
|
||||
* Destroys this template object. Should be called when you're done with it, in order
|
||||
* to clear out the template data so you can load/parse a new template set.
|
||||
*/
|
||||
function destroy()
|
||||
{
|
||||
$this->_tpldata = array();
|
||||
}
|
||||
/**
|
||||
* Sets the template root directory for this Template object.
|
||||
*/
|
||||
function set_rootdir($dir)
|
||||
{
|
||||
if (!is_dir($dir)){
|
||||
return false;
|
||||
}
|
||||
$this->root = $dir;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Sets the template filenames for handles. $filename_array
|
||||
* should be a hash of handle => filename pairs.
|
||||
*/
|
||||
function set_filenames($filename_array)
|
||||
{
|
||||
if (!is_array($filename_array)){
|
||||
return false;
|
||||
}
|
||||
reset($filename_array);
|
||||
while (list ($handle, $filename) = each($filename_array)){
|
||||
$this->files[$handle] = $this->make_filename($filename);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Load the file for the handle, compile the file,
|
||||
* and run the compiled code. This will print out
|
||||
* the results of executing the template.
|
||||
*/
|
||||
function pparse($handle)
|
||||
{
|
||||
// Edit DSB: autimatically assign language vars
|
||||
global $lang;
|
||||
$this->assign_vars($lang);
|
||||
if (!$this->loadfile($handle)){
|
||||
die("Template->pparse(): Couldn't load template file for handle $handle");
|
||||
}
|
||||
// actually compile the template now.
|
||||
if (!isset($this->compiled_code[$handle]) || empty($this->compiled_code[$handle])){
|
||||
// Actually compile the code now.
|
||||
$this->compiled_code[$handle] = $this->compile($this->uncompiled_code[$handle]);
|
||||
}
|
||||
// Run the compiled code.
|
||||
if (TPL_DEBUG > 0)
|
||||
echo '<pre>' . htmlspecialchars($this->compiled_code[$handle]) . '</pre>';
|
||||
eval($this->compiled_code[$handle]);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Inserts the uncompiled code for $handle as the
|
||||
* value of $varname in the root-level. This can be used
|
||||
* to effectively include a template in the middle of another
|
||||
* template.
|
||||
* Note that all desired assignments to the variables in $handle should be done
|
||||
* BEFORE calling this function.
|
||||
*/
|
||||
function assign_var_from_handle($varname, $handle)
|
||||
{
|
||||
if (!$this->loadfile($handle)){
|
||||
die("Template->assign_var_from_handle(): Couldn't load template file for handle $handle");
|
||||
}
|
||||
// Compile it, with the "no echo statements" option on.
|
||||
$_str = "";
|
||||
$code = $this->compile($this->uncompiled_code[$handle], true, '_str');
|
||||
// evaluate the variable assignment.
|
||||
eval($code);
|
||||
// assign the value of the generated variable to the given varname.
|
||||
$this->assign_var($varname, $_str);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Block-level variable assignment. Adds a new block iteration with the given
|
||||
* variable assignments. Note that this should only be called once per block
|
||||
* iteration.
|
||||
*/
|
||||
function assign_block_vars($blockname, $vararray)
|
||||
{
|
||||
if (strstr($blockname, '.')){
|
||||
// Nested block.
|
||||
$blocks = explode('.', $blockname);
|
||||
$blockcount = sizeof($blocks) - 1;
|
||||
$str = '$this->_tpldata';
|
||||
for ($i = 0; $i < $blockcount; $i++){
|
||||
$str .= '[\'' . $blocks[$i] . '.\']';
|
||||
eval('$lastiteration = sizeof(' . $str . ') - 1;');
|
||||
$str .= '[' . $lastiteration . ']';
|
||||
}
|
||||
// Now we add the block that we're actually assigning to.
|
||||
// We're adding a new iteration to this block with the given
|
||||
// variable assignments.
|
||||
$str .= '[\'' . $blocks[$blockcount] . '.\'][] = $vararray;';
|
||||
// Now we evaluate this assignment we've built up.
|
||||
eval($str);
|
||||
}else{
|
||||
// Top-level block.
|
||||
// Add a new iteration to this block with the variable assignments
|
||||
// we were given.
|
||||
$this->_tpldata[$blockname . '.'][] = $vararray;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Root-level variable assignment. Adds to current assignments, overriding
|
||||
* any existing variable assignment with the same name.
|
||||
*/
|
||||
function assign_vars($vararray)
|
||||
{
|
||||
global $lang;
|
||||
while (list ($key, $val) = each($vararray)){
|
||||
$this->_tpldata['.'][0][$key] = $val;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Root-level variable assignment. Adds to current assignments, overriding
|
||||
* any existing variable assignment with the same name.
|
||||
*/
|
||||
function assign_var($varname, $varval)
|
||||
{
|
||||
$this->_tpldata['.'][0][$varname] = $varval;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Generates a full path+filename for the given filename, which can either
|
||||
* be an absolute name, or a name relative to the rootdir for this Template
|
||||
* object.
|
||||
*/
|
||||
function make_filename($filename)
|
||||
{
|
||||
// Check if it's an absolute or relative path.
|
||||
/*
|
||||
if (substr($filename, 0, 1) != '/')
|
||||
{
|
||||
$filename = $this->root . '/' . $filename;
|
||||
}
|
||||
*/
|
||||
if (!file_exists($filename)){
|
||||
die("Template->make_filename(): Error - file $filename does not exist");
|
||||
}
|
||||
return $filename;
|
||||
}
|
||||
/**
|
||||
* If not already done, load the file for the given handle and populate
|
||||
* the uncompiled_code[] hash with its code. Do not compile.
|
||||
*/
|
||||
function loadfile($handle)
|
||||
{
|
||||
// If the file for this handle is already loaded and compiled, do nothing.
|
||||
if (isset($this->uncompiled_code[$handle]) && !empty($this->uncompiled_code[$handle])){
|
||||
return true;
|
||||
}
|
||||
// If we don't have a file assigned to this handle, die.
|
||||
if (!isset($this->files[$handle])){
|
||||
die("Template->loadfile(): No file specified for handle $handle");
|
||||
}
|
||||
$filename = $this->files[$handle];
|
||||
$str = implode("", @file($filename));
|
||||
if (empty($str)){
|
||||
die("Template->loadfile(): File $filename for handle $handle is empty");
|
||||
}
|
||||
$this->uncompiled_code[$handle] = $str;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Compiles the given string of code, and returns
|
||||
* the result in a string.
|
||||
* If "do_not_echo" is true, the returned code will not be directly
|
||||
* executable, but can be used as part of a variable assignment
|
||||
* for use in assign_code_from_handle().
|
||||
*/
|
||||
function compile($code, $do_not_echo = false, $retvar = '')
|
||||
{
|
||||
// replace \ with \\ and then ' with \'.
|
||||
$code = str_replace('\\', '\\\\', $code);
|
||||
$code = str_replace('\'', '\\\'', $code);
|
||||
// change template varrefs into PHP varrefs
|
||||
// This one will handle varrefs WITH namespaces
|
||||
$varrefs = array();
|
||||
preg_match_all('#\{(([a-z0-9\-_]+?\.)+?)([a-z0-9\-_]+?)\}#is', $code, $varrefs);
|
||||
$varcount = sizeof($varrefs[1]);
|
||||
for ($i = 0; $i < $varcount; $i++){
|
||||
$namespace = $varrefs[1][$i];
|
||||
$varname = $varrefs[3][$i];
|
||||
$new = $this->generate_block_varref($namespace, $varname);
|
||||
$code = str_replace($varrefs[0][$i], $new, $code);
|
||||
}
|
||||
// This will handle the remaining root-level varrefs
|
||||
$code = preg_replace('#\{([a-z0-9\-_]*?)\}#is', '\' . ( ( isset($this->_tpldata[\'.\'][0][\'\1\']) ) ? $this->_tpldata[\'.\'][0][\'\1\'] : \'\' ) . \'', $code);
|
||||
// Break it up into lines.
|
||||
$code_lines = explode("\n", $code);
|
||||
$block_nesting_level = 0;
|
||||
$block_names = array();
|
||||
$block_names[0] = ".";
|
||||
// Second: prepend echo ', append ' . "\n"; to each line.
|
||||
$line_count = sizeof($code_lines);
|
||||
for ($i = 0; $i < $line_count; $i++){
|
||||
$code_lines[$i] = chop($code_lines[$i]);
|
||||
if (preg_match('#<!-- BEGIN (.*?) -->#', $code_lines[$i], $m)){
|
||||
$n[0] = $m[0];
|
||||
$n[1] = $m[1];
|
||||
// Added: dougk_ff7-Keeps templates from bombing if begin is on the same line as end.. I think. :)
|
||||
if (preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $n)){
|
||||
$block_nesting_level++;
|
||||
$block_names[$block_nesting_level] = $m[1];
|
||||
if ($block_nesting_level < 2){
|
||||
// Block is not nested.
|
||||
$code_lines[$i] = '$_' . $n[1] . '_count = ( isset($this->_tpldata[\'' . $n[1] . '.\']) ) ? sizeof($this->_tpldata[\'' . $n[1] . '.\']) : 0;';
|
||||
$code_lines[$i] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)';
|
||||
$code_lines[$i] .= "\n" . '{';
|
||||
}else{
|
||||
// This block is nested.
|
||||
// Generate a namespace string for this block.
|
||||
$namespace = implode('.', $block_names);
|
||||
// strip leading period from root level..
|
||||
$namespace = substr($namespace, 2);
|
||||
// Get a reference to the data array for this block that depends on the
|
||||
// current indices of all parent blocks.
|
||||
$varref = $this->generate_block_data_ref($namespace, false);
|
||||
// Create the for loop code to iterate over this block.
|
||||
$code_lines[$i] = '$_' . $n[1] . '_count = ( isset(' . $varref . ') ) ? sizeof(' . $varref . ') : 0;';
|
||||
$code_lines[$i] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)';
|
||||
$code_lines[$i] .= "\n" . '{';
|
||||
}
|
||||
// We have the end of a block.
|
||||
unset($block_names[$block_nesting_level]);
|
||||
$block_nesting_level--;
|
||||
$code_lines[$i] .= '} // END ' . $n[1];
|
||||
$m[0] = $n[0];
|
||||
$m[1] = $n[1];
|
||||
}else{
|
||||
// We have the start of a block.
|
||||
$block_nesting_level++;
|
||||
$block_names[$block_nesting_level] = $m[1];
|
||||
if ($block_nesting_level < 2){
|
||||
// Block is not nested.
|
||||
$code_lines[$i] = '$_' . $m[1] . '_count = ( isset($this->_tpldata[\'' . $m[1] . '.\']) ) ? sizeof($this->_tpldata[\'' . $m[1] . '.\']) : 0;';
|
||||
$code_lines[$i] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)';
|
||||
$code_lines[$i] .= "\n" . '{';
|
||||
}else{
|
||||
// This block is nested.
|
||||
// Generate a namespace string for this block.
|
||||
$namespace = implode('.', $block_names);
|
||||
// strip leading period from root level..
|
||||
$namespace = substr($namespace, 2);
|
||||
// Get a reference to the data array for this block that depends on the
|
||||
// current indices of all parent blocks.
|
||||
$varref = $this->generate_block_data_ref($namespace, false);
|
||||
// Create the for loop code to iterate over this block.
|
||||
$code_lines[$i] = '$_' . $m[1] . '_count = ( isset(' . $varref . ') ) ? sizeof(' . $varref . ') : 0;';
|
||||
$code_lines[$i] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)';
|
||||
$code_lines[$i] .= "\n" . '{';
|
||||
}
|
||||
}
|
||||
}else
|
||||
if (preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $m)){
|
||||
// We have the end of a block.
|
||||
unset($block_names[$block_nesting_level]);
|
||||
$block_nesting_level--;
|
||||
$code_lines[$i] = '} // END ' . $m[1];
|
||||
}else{
|
||||
// We have an ordinary line of code.
|
||||
if (!$do_not_echo){
|
||||
$code_lines[$i] = 'echo \'' . $code_lines[$i] . '\' . "\\n";';
|
||||
}else{
|
||||
$code_lines[$i] = '$' . $retvar . '.= \'' . $code_lines[$i] . '\' . "\\n";';
|
||||
}
|
||||
}
|
||||
}
|
||||
// Bring it back into a single string of lines of code.
|
||||
$code = implode("\n", $code_lines);
|
||||
return $code;
|
||||
}
|
||||
/**
|
||||
* Generates a reference to the given variable inside the given (possibly nested)
|
||||
* block namespace. This is a string of the form:
|
||||
* ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . '
|
||||
* It's ready to be inserted into an "echo" line in one of the templates.
|
||||
* NOTE: expects a trailing "." on the namespace.
|
||||
*/
|
||||
function generate_block_varref($namespace, $varname)
|
||||
{
|
||||
// Strip the trailing period.
|
||||
$namespace = substr($namespace, 0, strlen($namespace) - 1);
|
||||
// Get a reference to the data block for this namespace.
|
||||
$varref = $this->generate_block_data_ref($namespace, true);
|
||||
// Prepend the necessary code to stick this in an echo line.
|
||||
// Append the variable reference.
|
||||
$varref .= '[\'' . $varname . '\']';
|
||||
$varref = '\' . ( ( isset(' . $varref . ') ) ? ' . $varref . ' : \'\' ) . \'';
|
||||
return $varref;
|
||||
}
|
||||
/**
|
||||
* Generates a reference to the array of data values for the given
|
||||
* (possibly nested) block namespace. This is a string of the form:
|
||||
* $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
|
||||
*
|
||||
* If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
|
||||
* NOTE: does not expect a trailing "." on the blockname.
|
||||
*/
|
||||
function generate_block_data_ref($blockname, $include_last_iterator)
|
||||
{
|
||||
// Get an array of the blocks involved.
|
||||
$blocks = explode(".", $blockname);
|
||||
$blockcount = sizeof($blocks) - 1;
|
||||
$varref = '$this->_tpldata';
|
||||
// Build up the string with everything but the last child.
|
||||
for ($i = 0; $i < $blockcount; $i++){
|
||||
$varref .= '[\'' . $blocks[$i] . '.\'][$_' . $blocks[$i] . '_i]';
|
||||
}
|
||||
// Add the block reference for the last child.
|
||||
$varref .= '[\'' . $blocks[$blockcount] . '.\']';
|
||||
// Add the iterator for the last child if requried.
|
||||
if ($include_last_iterator){
|
||||
$varref .= '[$_' . $blocks[$blockcount] . '_i]';
|
||||
}
|
||||
return $varref;
|
||||
}
|
||||
}
|
||||
?>
|
||||
Laden …
Tabelle hinzufügen
Einen Link hinzufügen
In neuem Issue referenzieren