diff options
| author | 2013-12-23 13:22:50 +0100 | |
|---|---|---|
| committer | 2013-12-23 13:22:50 +0100 | |
| commit | 24d9d1628d673f68fa0cc7b98a3ef9a8d021b070 (patch) | |
| tree | 2d794dc100d707e53b82a2de7d84b3d13103e461 /lib | |
| parent | 75096e6a39fe5d34d3951991f296f616e62a9fd8 (diff) | |
| parent | 9e46c1ee7fc7f9ad9e2c07f0cf826573dd4c9766 (diff) | |
Fusion 0.7-dev
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/JSON.php | 933 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/ActionController.php (renamed from lib/minz/ActionController.php) | 4 | ||||
| -rw-r--r-- | lib/Minz/ActionException.php | 9 | ||||
| -rw-r--r-- | lib/Minz/BadConfigurationException.php | 9 | ||||
| -rw-r--r-- | lib/Minz/Cache.php (renamed from lib/minz/Minz_Cache.php) | 6 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/Configuration.php (renamed from lib/minz/Configuration.php) | 88 | ||||
| -rw-r--r-- | lib/Minz/ControllerNotActionControllerException.php | 9 | ||||
| -rw-r--r-- | lib/Minz/ControllerNotExistException.php | 9 | ||||
| -rw-r--r-- | lib/Minz/CurrentPagePaginationException.php | 8 | ||||
| -rw-r--r-- | lib/Minz/Dispatcher.php (renamed from lib/minz/Dispatcher.php) | 54 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/Error.php (renamed from lib/minz/Error.php) | 40 | ||||
| -rw-r--r-- | lib/Minz/Exception.php | 16 | ||||
| -rw-r--r-- | lib/Minz/FileNotExistException.php | 8 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/FrontController.php (renamed from lib/minz/FrontController.php) | 82 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/Helper.php (renamed from lib/minz/Helper.php) | 2 | ||||
| -rw-r--r-- | lib/Minz/Log.php (renamed from lib/minz/Minz_Log.php) | 31 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/Model.php (renamed from lib/minz/Model.php) | 2 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/ModelArray.php (renamed from lib/minz/dao/Model_array.php) | 6 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/ModelPdo.php (renamed from lib/minz/dao/Model_pdo.php) | 37 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/ModelTxt.php (renamed from lib/minz/dao/Model_txt.php) | 10 | ||||
| -rw-r--r-- | lib/Minz/PDOConnectionException.php | 9 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/Paginator.php (renamed from lib/minz/Paginator.php) | 2 | ||||
| -rw-r--r-- | lib/Minz/PermissionDeniedException.php | 8 | ||||
| -rw-r--r-- | lib/Minz/Request.php (renamed from lib/minz/Request.php) | 23 | ||||
| -rw-r--r-- | lib/Minz/Response.php (renamed from lib/minz/Response.php) | 2 | ||||
| -rw-r--r-- | lib/Minz/RouteNotFoundException.php | 16 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/Router.php (renamed from lib/minz/Router.php) | 34 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/Session.php (renamed from lib/minz/Session.php) | 6 | ||||
| -rw-r--r-- | lib/Minz/Translate.php (renamed from lib/minz/Translate.php) | 6 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/Url.php (renamed from lib/minz/Url.php) | 18 | ||||
| -rw-r--r--[-rwxr-xr-x] | lib/Minz/View.php (renamed from lib/minz/View.php) | 15 | ||||
| -rw-r--r-- | lib/SimplePie/SimplePie.php | 17 | ||||
| -rw-r--r-- | lib/SimplePie/SimplePie/Misc.php | 4 | ||||
| -rw-r--r-- | lib/SimplePie/SimplePie/Parser.php | 3 | ||||
| -rw-r--r-- | lib/SimplePie/SimplePie/Sanitize.php | 53 | ||||
| -rw-r--r-- | lib/SimplePie_autoloader.php | 86 | ||||
| -rw-r--r-- | lib/http-conditional.php | 4 | ||||
| -rw-r--r-- | lib/lib_rss.php | 207 | ||||
| -rw-r--r-- | lib/minz/exceptions/MinzException.php | 94 |
39 files changed, 1488 insertions, 482 deletions
diff --git a/lib/JSON.php b/lib/JSON.php new file mode 100644 index 000000000..8dc8a6f01 --- /dev/null +++ b/lib/JSON.php @@ -0,0 +1,933 @@ +<?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 305040 2010-11-02 23:19:03Z alan_k $ + * @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); + +/** + * Behavior switch for Services_JSON::decode() + */ +define('SERVICES_JSON_USE_TO_JSON', 64); + +/** + * 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() + * - SERVICES_JSON_USE_TO_JSON: call toJSON when serializing objects + * It serializes the return value from the toJSON call rather + * than the object it'self, toJSON can return associative arrays, + * strings or numbers, if you return an object, make sure it does + * not have a toJSON method, otherwise an error will occur. + */ + function Services_JSON($use = 0) + { + $this->use = $use; + $this->_mb_strlen = function_exists('mb_strlen'); + $this->_mb_convert_encoding = function_exists('mb_convert_encoding'); + $this->_mb_substr = function_exists('mb_substr'); + } + // private - cache the mbstring lookup results.. + var $_mb_strlen = false; + var $_mb_substr = false; + var $_mb_convert_encoding = false; + + /** + * 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($this->_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($this->_mb_convert_encoding) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch($this->strlen8($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 (and sends JSON Header) + * + * @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) + { + header('Content-type: application/json'); + return $this->encodeUnsafe($var); + } + /** + * encodes an arbitrary variable into JSON format without JSON Header - warning - may allow XSS!!!!) + * + * @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 encodeUnsafe($var) + { + // see bug #16908 - regarding numeric locale printing + $lc = setlocale(LC_NUMERIC, 0); + setlocale(LC_NUMERIC, 'C'); + $ret = $this->_encode($var); + setlocale(LC_NUMERIC, $lc); + return $ret; + + } + /** + * PRIVATE CODE that does the work of 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 = $this->strlen8($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 + if ($c+1 >= $strlen_var) { + $c += 1; + $ascii .= '?'; + break; + } + + $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): + if ($c+2 >= $strlen_var) { + $c += 2; + $ascii .= '?'; + break; + } + // 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): + if ($c+3 >= $strlen_var) { + $c += 3; + $ascii .= '?'; + break; + } + // 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 + if ($c+4 >= $strlen_var) { + $c += 4; + $ascii .= '?'; + break; + } + $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): + if ($c+5 >= $strlen_var) { + $c += 5; + $ascii .= '?'; + break; + } + // 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': + + // support toJSON methods. + if (($this->use & SERVICES_JSON_USE_TO_JSON) && method_exists($var, 'toJSON')) { + // this may end up allowing unlimited recursion + // so we check the return value to make sure it's not got the same method. + $recode = $var->toJSON(); + + if (method_exists($recode, 'toJSON')) { + + return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) + ? 'null' + : new Services_JSON_Error(class_name($var). + " toJSON returned an object with a toJSON method."); + + } + + return $this->_encode( $recode ); + } + + $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 = $this->substr8($str, 0, 1); + $chrs = $this->substr8($str, 1, -1); + $utf8 = ''; + $strlen_chrs = $this->strlen8($chrs); + + for ($c = 0; $c < $strlen_chrs; ++$c) { + + $substr_chrs_c_2 = $this->substr8($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', $this->substr8($chrs, $c, 6)): + // single, escaped unicode character + $utf16 = chr(hexdec($this->substr8($chrs, ($c + 2), 2))) + . chr(hexdec($this->substr8($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 .= $this->substr8($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 .= $this->substr8($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 .= $this->substr8($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 .= $this->substr8($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 .= $this->substr8($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 = $this->substr8($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 = $this->strlen8($chrs); + + for ($c = 0; $c <= $strlen_chrs; ++$c) { + + $top = end($stk); + $substr_chrs_c_2 = $this->substr8($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 = $this->substr8($chrs, $top['where'], ($c - $top['where'])); + array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); + //print("Found split at {$c}: ".$this->substr8($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*:/Uis', $slice, $parts)) { + // "name":value pair + $key = $this->decode($parts[1]); + $val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B")); + if ($this->use & SERVICES_JSON_LOOSE_TYPE) { + $obj[$key] = $val; + } else { + $obj->$key = $val; + } + } elseif (preg_match('/^\s*(\w+)\s*:/Uis', $slice, $parts)) { + // name:value pair, where name is unquoted + $key = $parts[1]; + $val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B")); + + 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) && + (($this->strlen8($this->substr8($chrs, 0, $c)) - $this->strlen8(rtrim($this->substr8($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}: ".$this->substr8($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}: ".$this->substr8($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}: ".$this->substr8($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}: ".$this->substr8($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; + } + + /** + * Calculates length of string in bytes + * @param string + * @return integer length + */ + function strlen8( $str ) + { + if ( $this->_mb_strlen ) { + return mb_strlen( $str, "8bit" ); + } + return strlen( $str ); + } + + /** + * Returns part of a string, interpreting $start and $length as number of bytes. + * @param string + * @param integer start + * @param integer length + * @return integer length + */ + function substr8( $string, $start, $length=false ) + { + if ( $length === false ) { + $length = $this->strlen8( $string ) - $start; + } + if ( $this->_mb_substr ) { + return mb_substr( $string, $start, $length, "8bit" ); + } + return substr( $string, $start, $length ); + } + +} + +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) + { + + } + } + +} diff --git a/lib/minz/ActionController.php b/lib/Minz/ActionController.php index ab9389dbd..409d9611f 100755..100644 --- a/lib/minz/ActionController.php +++ b/lib/Minz/ActionController.php @@ -7,7 +7,7 @@ /** * La classe ActionController représente le contrôleur de l'application */ -class ActionController { +class Minz_ActionController { protected $router; protected $view; @@ -18,7 +18,7 @@ class ActionController { */ public function __construct ($router) { $this->router = $router; - $this->view = new View (); + $this->view = new Minz_View (); $this->view->attributeParams (); } diff --git a/lib/Minz/ActionException.php b/lib/Minz/ActionException.php new file mode 100644 index 000000000..c566a076f --- /dev/null +++ b/lib/Minz/ActionException.php @@ -0,0 +1,9 @@ +<?php +class Minz_ActionException extends Minz_Exception { + public function __construct ($controller_name, $action_name, $code = self::ERROR) { + $message = '`' . $action_name . '` cannot be invoked on `' + . $controller_name . '`'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/Minz/BadConfigurationException.php b/lib/Minz/BadConfigurationException.php new file mode 100644 index 000000000..a7b77d687 --- /dev/null +++ b/lib/Minz/BadConfigurationException.php @@ -0,0 +1,9 @@ +<?php +class Minz_BadConfigurationException extends Minz_Exception { + public function __construct ($part_missing, $code = self::ERROR) { + $message = '`' . $part_missing + . '` in the configuration file is missing or is misconfigured'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/minz/Minz_Cache.php b/lib/Minz/Cache.php index 6848e3350..fcb627eb2 100644 --- a/lib/minz/Minz_Cache.php +++ b/lib/Minz/Cache.php @@ -35,7 +35,7 @@ class Minz_Cache { * Setteurs */ public function _fileName () { - $file = md5 (Request::getURI ()); + $file = md5 (Minz_Request::getURI ()); $this->file = CACHE_PATH . '/'.$file; } @@ -43,7 +43,7 @@ class Minz_Cache { public function _expire () { if ($this->exist ()) { $this->expire = filemtime ($this->file) - + Configuration::delayCache (); + + Minz_Configuration::delayCache (); } } @@ -52,7 +52,7 @@ class Minz_Cache { * @return true si activé, false sinon */ public static function isEnabled () { - return Configuration::cacheEnabled () && self::$enabled; + return Minz_Configuration::cacheEnabled () && self::$enabled; } /** diff --git a/lib/minz/Configuration.php b/lib/Minz/Configuration.php index b296ec378..1b108dcdf 100755..100644 --- a/lib/minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -7,8 +7,8 @@ /** * La classe Configuration permet de gérer la configuration de l'application */ -class Configuration { - const CONF_PATH_NAME = '/configuration/application.ini'; +class Minz_Configuration { + const CONF_PATH_NAME = '/config.php'; /** * VERSION est la version actuelle de MINZ @@ -43,13 +43,15 @@ class Configuration { * - base le nom de la base de données */ private static $sel_application = ''; - private static $environment = Configuration::PRODUCTION; + private static $environment = Minz_Configuration::PRODUCTION; private static $base_url = ''; private static $use_url_rewriting = false; private static $title = ''; private static $language = 'en'; private static $cache_enabled = false; private static $delay_cache = 3600; + private static $default_user = ''; + private static $current_user = ''; private static $db = array ( 'host' => false, @@ -74,7 +76,7 @@ class Configuration { return self::$use_url_rewriting; } public static function title () { - return self::$title; + return stripslashes(self::$title); } public static function language () { return self::$language; @@ -88,63 +90,65 @@ class Configuration { public static function dataBase () { return self::$db; } + public static function defaultUser () { + return self::$default_user; + } + public static function currentUser () { + return self::$current_user; + } /** * Initialise les variables de configuration - * @exception FileNotExistException si le CONF_PATH_NAME n'existe pas - * @exception BadConfigurationException si CONF_PATH_NAME mal formaté + * @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas + * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté */ public static function init () { try { self::parseFile (); self::setReporting (); - } catch (FileNotExistException $e) { + } catch (Minz_FileNotExistException $e) { throw $e; - } catch (BadConfigurationException $e) { + } catch (Minz_BadConfigurationException $e) { throw $e; } } /** * Parse un fichier de configuration de type ".ini" - * @exception FileNotExistException si le CONF_PATH_NAME n'existe pas - * @exception BadConfigurationException si CONF_PATH_NAME mal formaté + * @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas + * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté */ private static function parseFile () { - if (!file_exists (APP_PATH . self::CONF_PATH_NAME)) { - throw new FileNotExistException ( - APP_PATH . self::CONF_PATH_NAME, - MinzException::ERROR + if (!file_exists (DATA_PATH . self::CONF_PATH_NAME)) { + throw new Minz_FileNotExistException ( + DATA_PATH . self::CONF_PATH_NAME, + Minz_Exception::ERROR ); } - $ini_array = parse_ini_file ( - APP_PATH . self::CONF_PATH_NAME, - true - ); + $ini_array = include(DATA_PATH . self::CONF_PATH_NAME); if (!$ini_array) { - throw new PermissionDeniedException ( - APP_PATH . self::CONF_PATH_NAME, - MinzException::ERROR + throw new Minz_PermissionDeniedException ( + DATA_PATH . self::CONF_PATH_NAME, + Minz_Exception::ERROR ); } // [general] est obligatoire if (!isset ($ini_array['general'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( '[general]', - MinzException::ERROR + Minz_Exception::ERROR ); } $general = $ini_array['general']; - // sel_application est obligatoire if (!isset ($general['sel_application'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'sel_application', - MinzException::ERROR + Minz_Exception::ERROR ); } self::$sel_application = $general['sel_application']; @@ -152,18 +156,18 @@ class Configuration { if (isset ($general['environment'])) { switch ($general['environment']) { case 'silent': - self::$environment = Configuration::SILENT; + self::$environment = Minz_Configuration::SILENT; break; case 'development': - self::$environment = Configuration::DEVELOPMENT; + self::$environment = Minz_Configuration::DEVELOPMENT; break; case 'production': - self::$environment = Configuration::PRODUCTION; + self::$environment = Minz_Configuration::PRODUCTION; break; default: - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'environment', - MinzException::ERROR + Minz_Exception::ERROR ); } @@ -186,13 +190,17 @@ class Configuration { if (CACHE_PATH === false && self::$cache_enabled) { throw new FileNotExistException ( 'CACHE_PATH', - MinzException::ERROR + Minz_Exception::ERROR ); } } if (isset ($general['delay_cache'])) { self::$delay_cache = $general['delay_cache']; } + if (isset ($general['default_user'])) { + self::$default_user = $general['default_user']; + self::$current_user = self::$default_user; + } // Base de données $db = false; @@ -201,27 +209,27 @@ class Configuration { } if ($db) { if (!isset ($db['host'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'host', - MinzException::ERROR + Minz_Exception::ERROR ); } if (!isset ($db['user'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'user', - MinzException::ERROR + Minz_Exception::ERROR ); } if (!isset ($db['password'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'password', - MinzException::ERROR + Minz_Exception::ERROR ); } if (!isset ($db['base'])) { - throw new BadConfigurationException ( + throw new Minz_BadConfigurationException ( 'base', - MinzException::ERROR + Minz_Exception::ERROR ); } diff --git a/lib/Minz/ControllerNotActionControllerException.php b/lib/Minz/ControllerNotActionControllerException.php new file mode 100644 index 000000000..535a1377e --- /dev/null +++ b/lib/Minz/ControllerNotActionControllerException.php @@ -0,0 +1,9 @@ +<?php +class Minz_ControllerNotActionControllerException extends Minz_Exception { + public function __construct ($controller_name, $code = self::ERROR) { + $message = 'Controller `' . $controller_name + . '` isn\'t instance of ActionController'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/Minz/ControllerNotExistException.php b/lib/Minz/ControllerNotExistException.php new file mode 100644 index 000000000..523867d11 --- /dev/null +++ b/lib/Minz/ControllerNotExistException.php @@ -0,0 +1,9 @@ +<?php +class Minz_ControllerNotExistException extends Minz_Exception { + public function __construct ($controller_name, $code = self::ERROR) { + $message = 'Controller `' . $controller_name + . '` doesn\'t exist'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/Minz/CurrentPagePaginationException.php b/lib/Minz/CurrentPagePaginationException.php new file mode 100644 index 000000000..74214d879 --- /dev/null +++ b/lib/Minz/CurrentPagePaginationException.php @@ -0,0 +1,8 @@ +<?php +class Minz_CurrentPagePaginationException extends Minz_Exception { + public function __construct ($page) { + $message = 'Page number `' . $page . '` doesn\'t exist'; + + parent::__construct ($message, self::ERROR); + } +} diff --git a/lib/minz/Dispatcher.php b/lib/Minz/Dispatcher.php index 0cfdd8e75..2898b5f00 100644 --- a/lib/minz/Dispatcher.php +++ b/lib/Minz/Dispatcher.php @@ -9,8 +9,8 @@ * déterminée dans la Request * C'est un singleton */ -class Dispatcher { - const CONTROLLERS_PATH_NAME = '/controllers'; +class Minz_Dispatcher { + const CONTROLLERS_PATH_NAME = '/Controllers'; /* singleton */ private static $instance = null; @@ -23,7 +23,7 @@ class Dispatcher { */ public static function getInstance ($router) { if (is_null (self::$instance)) { - self::$instance = new Dispatcher ($router); + self::$instance = new Minz_Dispatcher ($router); } return self::$instance; } @@ -38,7 +38,7 @@ class Dispatcher { /** * Lance le controller indiqué dans Request * Remplit le body de Response à partir de la Vue - * @exception MinzException + * @exception Minz_Exception */ public function run () { $cache = new Minz_Cache(); @@ -53,29 +53,25 @@ class Dispatcher { $cache->render (); $text = ob_get_clean(); } else { - while (Request::$reseted) { - Request::$reseted = false; + while (Minz_Request::$reseted) { + Minz_Request::$reseted = false; try { - $this->createController ( - Request::controllerName () - . 'Controller' - ); - + $this->createController ('FreshRSS_' . Minz_Request::controllerName () . '_Controller'); $this->controller->init (); $this->controller->firstAction (); $this->launchAction ( - Request::actionName () + Minz_Request::actionName () . 'Action' ); $this->controller->lastAction (); - if (!Request::$reseted) { + if (!Minz_Request::$reseted) { ob_start (); $this->controller->view ()->build (); $text = ob_get_clean(); } - } catch (MinzException $e) { + } catch (Minz_Exception $e) { throw $e; } } @@ -85,14 +81,12 @@ class Dispatcher { } } - Response::setBody ($text); + Minz_Response::setBody ($text); } /** * Instancie le Controller * @param $controller_name le nom du controller à instancier - * @exception FileNotExistException le fichier correspondant au - * > controller n'existe pas * @exception ControllerNotExistException le controller n'existe pas * @exception ControllerNotActionControllerException controller n'est * > pas une instance de ActionController @@ -101,26 +95,18 @@ class Dispatcher { $filename = APP_PATH . self::CONTROLLERS_PATH_NAME . '/' . $controller_name . '.php'; - if (!file_exists ($filename)) { - throw new FileNotExistException ( - $filename, - MinzException::ERROR - ); - } - require_once ($filename); - if (!class_exists ($controller_name)) { - throw new ControllerNotExistException ( + throw new Minz_ControllerNotExistException ( $controller_name, - MinzException::ERROR + Minz_Exception::ERROR ); } $this->controller = new $controller_name ($this->router); - if (! ($this->controller instanceof ActionController)) { - throw new ControllerNotActionControllerException ( + if (! ($this->controller instanceof Minz_ActionController)) { + throw new Minz_ControllerNotActionControllerException ( $controller_name, - MinzException::ERROR + Minz_Exception::ERROR ); } } @@ -129,18 +115,18 @@ class Dispatcher { * Lance l'action sur le controller du dispatcher * @param $action_name le nom de l'action * @exception ActionException si on ne peut pas exécuter l'action sur - * > le controller + * le controller */ private function launchAction ($action_name) { - if (!Request::$reseted) { + if (!Minz_Request::$reseted) { if (!is_callable (array ( $this->controller, $action_name ))) { - throw new ActionException ( + throw new Minz_ActionException ( get_class ($this->controller), $action_name, - MinzException::ERROR + Minz_Exception::ERROR ); } call_user_func (array ( diff --git a/lib/minz/Error.php b/lib/Minz/Error.php index 0e8c2f60b..1ad0d313c 100755..100644 --- a/lib/minz/Error.php +++ b/lib/Minz/Error.php @@ -1,5 +1,5 @@ <?php -/** +/** * MINZ - Copyright 2011 Marien Fressinaud * Sous licence AGPL3 <http://www.gnu.org/licenses/> */ @@ -7,7 +7,7 @@ /** * La classe Error permet de lancer des erreurs HTTP */ -class Error { +class Minz_Error { public function __construct () { } /** @@ -21,28 +21,28 @@ class Error { */ public static function error ($code = 404, $logs = array (), $redirect = false) { $logs = self::processLogs ($logs); - $error_filename = APP_PATH . '/controllers/errorController.php'; - + $error_filename = APP_PATH . '/Controllers/ErrorController.php'; + if (file_exists ($error_filename)) { $params = array ( 'code' => $code, 'logs' => $logs ); - - Response::setHeader ($code); + + Minz_Response::setHeader ($code); if ($redirect) { - Request::forward (array ( + Minz_Request::forward (array ( 'c' => 'error' ), true); } else { - Request::forward (array ( + Minz_Request::forward (array ( 'c' => 'error', 'params' => $params ), false); } } else { $text = '<h1>An error occured</h1>'."\n"; - + if (!empty ($logs)) { $text .= '<ul>'."\n"; foreach ($logs as $log) { @@ -50,14 +50,14 @@ class Error { } $text .= '</ul>'."\n"; } - - Response::setHeader ($code); - Response::setBody ($text); - Response::send (); + + Minz_Response::setHeader ($code); + Minz_Response::setBody ($text); + Minz_Response::send (); exit (); } } - + /** * Permet de retourner les logs de façon à n'avoir que * ceux que l'on veut réellement @@ -66,12 +66,12 @@ class Error { * > en fonction de l'environment */ private static function processLogs ($logs) { - $env = Configuration::environment (); + $env = Minz_Configuration::environment (); $logs_ok = array (); $error = array (); $warning = array (); $notice = array (); - + if (isset ($logs['error'])) { $error = $logs['error']; } @@ -81,14 +81,14 @@ class Error { if (isset ($logs['notice'])) { $notice = $logs['notice']; } - - if ($env == Configuration::PRODUCTION) { + + if ($env == Minz_Configuration::PRODUCTION) { $logs_ok = $error; } - if ($env == Configuration::DEVELOPMENT) { + if ($env == Minz_Configuration::DEVELOPMENT) { $logs_ok = array_merge ($error, $warning, $notice); } - + return $logs_ok; } } diff --git a/lib/Minz/Exception.php b/lib/Minz/Exception.php new file mode 100644 index 000000000..b5e71e0d8 --- /dev/null +++ b/lib/Minz/Exception.php @@ -0,0 +1,16 @@ +<?php +class Minz_Exception extends Exception { + const ERROR = 0; + const WARNING = 10; + const NOTICE = 20; + + public function __construct ($message, $code = self::ERROR) { + if ($code != Minz_Exception::ERROR + && $code != Minz_Exception::WARNING + && $code != Minz_Exception::NOTICE) { + $code = Minz_Exception::ERROR; + } + + parent::__construct ($message, $code); + } +} diff --git a/lib/Minz/FileNotExistException.php b/lib/Minz/FileNotExistException.php new file mode 100644 index 000000000..df2b8ff6c --- /dev/null +++ b/lib/Minz/FileNotExistException.php @@ -0,0 +1,8 @@ +<?php +class Minz_FileNotExistException extends Minz_Exception { + public function __construct ($file_name, $code = self::ERROR) { + $message = 'File doesn\'t exist : `' . $file_name.'`'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/minz/FrontController.php b/lib/Minz/FrontController.php index d48d43d04..8e9c511a6 100755..100644 --- a/lib/minz/FrontController.php +++ b/lib/Minz/FrontController.php @@ -2,109 +2,79 @@ # ***** BEGIN LICENSE BLOCK ***** # MINZ - a free PHP Framework like Zend Framework # Copyright (C) 2011 Marien Fressinaud -# +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. -# +# # This program 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 Affero General Public License for more details. -# +# # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # ***** END LICENSE BLOCK ***** /** - * La classe FrontController est le noyau du framework, elle lance l'application + * La classe FrontController est le Dispatcher du framework, elle lance l'application * Elle est appelée en général dans le fichier index.php à la racine du serveur */ -class FrontController { +class Minz_FrontController { protected $dispatcher; protected $router; - + /** * Constructeur * Initialise le router et le dispatcher */ public function __construct () { - $this->loadLib (); - if (LOG_PATH === false) { - $this->killApp ('Path doesn\'t exist : LOG_PATH'); + $this->killApp ('Path doesn’t exist : LOG_PATH'); } - + try { - Configuration::init (); + Minz_Configuration::init (); - Request::init (); + Minz_Request::init (); - $this->router = new Router (); + $this->router = new Minz_Router (); $this->router->init (); - } catch (RouteNotFoundException $e) { + } catch (Minz_RouteNotFoundException $e) { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); - Error::error ( + Minz_Error::error ( 404, array ('error' => array ($e->getMessage ())) ); - } catch (MinzException $e) { + } catch (Minz_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); $this->killApp ($e->getMessage ()); } - - $this->dispatcher = Dispatcher::getInstance ($this->router); - } - - /** - * Inclue les fichiers de la librairie - */ - private function loadLib () { - require ('ActionController.php'); - require ('Minz_Cache.php'); - require ('Configuration.php'); - require ('Dispatcher.php'); - require ('Error.php'); - require ('Helper.php'); - require ('Minz_Log.php'); - require ('Model.php'); - require ('Paginator.php'); - require ('Request.php'); - require ('Response.php'); - require ('Router.php'); - require ('Session.php'); - require ('Translate.php'); - require ('Url.php'); - require ('View.php'); - - require ('dao/Model_pdo.php'); - require ('dao/Model_txt.php'); - require ('dao/Model_array.php'); - - require ('exceptions/MinzException.php'); + + $this->dispatcher = Minz_Dispatcher::getInstance ($this->router); } - + /** * Démarre l'application (lance le dispatcher et renvoie la réponse */ public function run () { try { $this->dispatcher->run (); - Response::send (); - } catch (MinzException $e) { + Minz_Response::send (); + } catch (Minz_Exception $e) { try { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); - } catch (PermissionDeniedException $e) { + } catch (Minz_PermissionDeniedException $e) { $this->killApp ($e->getMessage ()); } - if ($e instanceof FileNotExistException || - $e instanceof ControllerNotExistException || - $e instanceof ControllerNotActionControllerException || - $e instanceof ActionException) { - Error::error ( + if ($e instanceof Minz_FileNotExistException || + $e instanceof Minz_ControllerNotExistException || + $e instanceof Minz_ControllerNotActionControllerException || + $e instanceof Minz_ActionException) { + Minz_Error::error ( 404, array ('error' => array ($e->getMessage ())), true @@ -114,7 +84,7 @@ class FrontController { } } } - + /** * Permet d'arrêter le programme en urgence */ diff --git a/lib/minz/Helper.php b/lib/Minz/Helper.php index 4f64ba218..b058211d3 100755..100644 --- a/lib/minz/Helper.php +++ b/lib/Minz/Helper.php @@ -7,7 +7,7 @@ /** * La classe Helper représente une aide pour des tâches récurrentes */ -class Helper { +class Minz_Helper { /** * Annule les effets des magic_quotes pour une variable donnée * @param $var variable à traiter (tableau ou simple variable) diff --git a/lib/minz/Minz_Log.php b/lib/Minz/Log.php index 153870435..a9b657271 100644 --- a/lib/minz/Minz_Log.php +++ b/lib/Minz/Log.php @@ -12,11 +12,13 @@ class Minz_Log { * Les différents niveau de log * ERROR erreurs bloquantes de l'application * WARNING erreurs pouvant géner le bon fonctionnement, mais non bloquantes - * NOTICE messages d'informations, affichés pour le déboggage + * NOTICE erreurs mineures ou messages d'informations + * DEBUG Informations affichées pour le déboggage */ - const ERROR = 0; - const WARNING = 10; - const NOTICE = 20; + const ERROR = 2; + const WARNING = 4; + const NOTICE = 8; + const DEBUG = 16; /** * Enregistre un message dans un fichier de log spécifique @@ -29,11 +31,11 @@ class Minz_Log { * @param $file_name fichier de log, par défaut LOG_PATH/application.log */ public static function record ($information, $level, $file_name = null) { - $env = Configuration::environment (); + $env = Minz_Configuration::environment (); - if (! ($env == Configuration::SILENT - || ($env == Configuration::PRODUCTION - && ($level == Minz_Log::WARNING || $level == Minz_Log::NOTICE)))) { + if (! ($env === Minz_Configuration::SILENT + || ($env === Minz_Configuration::PRODUCTION + && ($level >= Minz_Log::NOTICE)))) { if (is_null ($file_name)) { $file_name = LOG_PATH . '/application.log'; } @@ -48,11 +50,14 @@ class Minz_Log { case Minz_Log::NOTICE : $level_label = 'notice'; break; + case Minz_Log::DEBUG : + $level_label = 'debug'; + break; default : $level_label = 'unknown'; } - if ($env == Configuration::PRODUCTION) { + if ($env == Minz_Configuration::PRODUCTION) { $file = @fopen ($file_name, 'a'); } else { $file = fopen ($file_name, 'a'); @@ -65,9 +70,9 @@ class Minz_Log { fwrite ($file, $log); fclose ($file); } else { - throw new PermissionDeniedException ( + throw new Minz_PermissionDeniedException ( $file_name, - MinzException::ERROR + Minz_Exception::ERROR ); } } @@ -83,7 +88,7 @@ class Minz_Log { $msg_get = str_replace("\n", '', '$_GET content : ' . print_r($_GET, true)); $msg_post = str_replace("\n", '', '$_POST content : ' . print_r($_POST, true)); - self::record($msg_get, Minz_Log::NOTICE, $file_name); - self::record($msg_post, Minz_Log::NOTICE, $file_name); + self::record($msg_get, Minz_Log::DEBUG, $file_name); + self::record($msg_post, Minz_Log::DEBUG, $file_name); } } diff --git a/lib/minz/Model.php b/lib/Minz/Model.php index 37fc19ed1..adbaba942 100755..100644 --- a/lib/minz/Model.php +++ b/lib/Minz/Model.php @@ -7,6 +7,6 @@ /** * La classe Model représente un modèle de l'application (représentation MVC) */ -class Model { +class Minz_Model { } diff --git a/lib/minz/dao/Model_array.php b/lib/Minz/ModelArray.php index 0b9ccf071..4ba022143 100755..100644 --- a/lib/minz/dao/Model_array.php +++ b/lib/Minz/ModelArray.php @@ -7,7 +7,7 @@ /** * La classe Model_array représente le modèle interragissant avec les fichiers de type texte gérant des tableaux php */ -class Model_array extends Model_txt { +class Minz_ModelArray extends Minz_ModelTxt { /** * $array Le tableau php contenu dans le fichier $nameFile */ @@ -22,7 +22,7 @@ class Model_array extends Model_txt { parent::__construct ($nameFile); if (!$this->getLock ('read')) { - throw new PermissionDeniedException ($this->filename); + throw new Minz_PermissionDeniedException ($this->filename); } else { $this->array = include ($this->filename); $this->releaseLock (); @@ -41,7 +41,7 @@ class Model_array extends Model_txt { **/ public function writeFile ($array) { if (!$this->getLock ('write')) { - throw new PermissionDeniedException ($this->namefile); + throw new Minz_PermissionDeniedException ($this->namefile); } else { $this->erase (); diff --git a/lib/minz/dao/Model_pdo.php b/lib/Minz/ModelPdo.php index a91a4fa00..9655539b2 100755..100644 --- a/lib/minz/dao/Model_pdo.php +++ b/lib/Minz/ModelPdo.php @@ -8,7 +8,7 @@ * La classe Model_sql représente le modèle interragissant avec les bases de données * Seul la connexion MySQL est prise en charge pour le moment */ -class Model_pdo { +class Minz_ModelPdo { /** * Partage la connexion à la base de données entre toutes les instances. @@ -35,7 +35,7 @@ class Model_pdo { return; } - $db = Configuration::dataBase (); + $db = Minz_Configuration::dataBase (); $driver_options = null; try { @@ -49,9 +49,7 @@ class Model_pdo { PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8' ); } elseif($type == 'sqlite') { - $string = $type - . ':/' . PUBLIC_PATH - . '/data/' . $db['base'] . '.sqlite'; //TODO: DEBUG UTF-8 http://www.siteduzero.com/forum/sujet/sqlite-connexion-utf-8-18797 + $string = $type . ':/' . DATA_PATH . $db['base'] . '.sqlite'; //TODO: DEBUG UTF-8 http://www.siteduzero.com/forum/sujet/sqlite-connexion-utf-8-18797 } $this->bd = new FreshPDO ( @@ -62,21 +60,42 @@ class Model_pdo { ); self::$sharedBd = $this->bd; - $this->prefix = $db['prefix']; + $userPrefix = Minz_Configuration::currentUser (); + $this->prefix = $db['prefix'] . (empty($userPrefix) ? '' : ($userPrefix . '_')); self::$sharedPrefix = $this->prefix; } catch (Exception $e) { - throw new PDOConnectionException ( + throw new Minz_PDOConnectionException ( $string, - $db['user'], MinzException::WARNING + $db['user'], Minz_Exception::ERROR ); } } + + public function beginTransaction() { + $this->bd->beginTransaction(); + } + public function commit() { + $this->bd->commit(); + } + public function rollBack() { + $this->bd->rollBack(); + } + + public function size() { + $db = Minz_Configuration::dataBase (); + $sql = 'SELECT SUM(data_length + index_length) FROM information_schema.TABLES WHERE table_schema = ?'; + $stm = $this->bd->prepare ($sql); + $values = array ($db['base']); + $stm->execute ($values); + $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0); + return $res[0]; + } } class FreshPDO extends PDO { private static function check($statement) { if (preg_match('/^(?:UPDATE|INSERT|DELETE)/i', $statement)) { - touch(PUBLIC_PATH . '/data/touch.txt'); + invalidateHttpCache(); } } diff --git a/lib/minz/dao/Model_txt.php b/lib/Minz/ModelTxt.php index aed653068..8c5973f4d 100755..100644 --- a/lib/minz/dao/Model_txt.php +++ b/lib/Minz/ModelTxt.php @@ -7,7 +7,7 @@ /** * La classe Model_txt représente le modèle interragissant avec les fichiers de type texte */ -class Model_txt { +class Minz_ModelTxt { /** * $file représente le fichier à ouvrir */ @@ -28,18 +28,18 @@ class Model_txt { public function __construct ($nameFile, $mode = 'a+') { $this->filename = $nameFile; if (!file_exists($this->filename)) { - throw new FileNotExistException ( + throw new Minz_FileNotExistException ( $this->filename, - MinzException::WARNING + Minz_Exception::WARNING ); } $this->file = @fopen ($this->filename, $mode); if (!$this->file) { - throw new PermissionDeniedException ( + throw new Minz_PermissionDeniedException ( $this->filename, - MinzException::WARNING + Minz_Exception::WARNING ); } } diff --git a/lib/Minz/PDOConnectionException.php b/lib/Minz/PDOConnectionException.php new file mode 100644 index 000000000..faf2e0fe9 --- /dev/null +++ b/lib/Minz/PDOConnectionException.php @@ -0,0 +1,9 @@ +<?php +class Minz_PDOConnectionException extends Minz_Exception { + public function __construct ($string_connection, $user, $code = self::ERROR) { + $message = 'Access to database is denied for `' . $user . '`' + . ' (`' . $string_connection . '`)'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/minz/Paginator.php b/lib/Minz/Paginator.php index 1a8376e75..5858e76a5 100755..100644 --- a/lib/minz/Paginator.php +++ b/lib/Minz/Paginator.php @@ -7,7 +7,7 @@ /** * La classe Paginator permet de gérer la pagination de l'application facilement */ -class Paginator { +class Minz_Paginator { /** * $items tableau des éléments à afficher/gérer */ diff --git a/lib/Minz/PermissionDeniedException.php b/lib/Minz/PermissionDeniedException.php new file mode 100644 index 000000000..61be530d3 --- /dev/null +++ b/lib/Minz/PermissionDeniedException.php @@ -0,0 +1,8 @@ +<?php +class Minz_PermissionDeniedException extends Minz_Exception { + public function __construct ($file_name, $code = self::ERROR) { + $message = 'Permission is denied for `' . $file_name.'`'; + + parent::__construct ($message, $code); + } +} diff --git a/lib/minz/Request.php b/lib/Minz/Request.php index ffddbe6ad..fb48bd7a2 100644 --- a/lib/minz/Request.php +++ b/lib/Minz/Request.php @@ -7,7 +7,7 @@ /** * Request représente la requête http */ -class Request { +class Minz_Request { private static $controller_name = ''; private static $action_name = ''; private static $params = array (); @@ -29,15 +29,18 @@ class Request { public static function params () { return self::$params; } + static function htmlspecialchars_utf8 ($p) { + return htmlspecialchars($p, ENT_COMPAT, 'UTF-8'); + } public static function param ($key, $default = false, $specialchars = false) { if (isset (self::$params[$key])) { $p = self::$params[$key]; if(is_object($p) || $specialchars) { return $p; } elseif(is_array($p)) { - return array_map('htmlspecialchars', $p); //TODO: Should use explicit UTF-8 + return array_map('self::htmlspecialchars_utf8', $p); } else { - return htmlspecialchars($p, ENT_NOQUOTES, 'UTF-8'); + return self::htmlspecialchars_utf8($p); } } else { return $default; @@ -93,7 +96,7 @@ class Request { * @return la base de l'url */ public static function getBaseUrl () { - return Configuration::baseUrl (); + return Minz_Configuration::baseUrl (); } /** @@ -121,10 +124,10 @@ class Request { * > sinon, le dispatcher recharge en interne */ public static function forward ($url = array (), $redirect = false) { - $url = Url::checkUrl ($url); + $url = Minz_Url::checkUrl ($url); if ($redirect) { - header ('Location: ' . Url::display ($url, 'php')); + header ('Location: ' . Minz_Url::display ($url, 'php')); exit (); } else { self::$reseted = true; @@ -182,9 +185,9 @@ class Request { */ private static function magicQuotesOff () { if (get_magic_quotes_gpc ()) { - $_GET = Helper::stripslashes_r ($_GET); - $_POST = Helper::stripslashes_r ($_POST); - $_COOKIE = Helper::stripslashes_r ($_COOKIE); + $_GET = Minz_Helper::stripslashes_r ($_GET); + $_POST = Minz_Helper::stripslashes_r ($_POST); + $_COOKIE = Minz_Helper::stripslashes_r ($_COOKIE); } } @@ -192,5 +195,3 @@ class Request { return !empty ($_POST) || !empty ($_FILES); } } - - diff --git a/lib/minz/Response.php b/lib/Minz/Response.php index fcf53c5b1..f8ea3d946 100644 --- a/lib/minz/Response.php +++ b/lib/Minz/Response.php @@ -7,7 +7,7 @@ /** * Response représente la requête http renvoyée à l'utilisateur */ -class Response { +class Minz_Response { private static $header = 'HTTP/1.0 200 OK'; private static $body = ''; diff --git a/lib/Minz/RouteNotFoundException.php b/lib/Minz/RouteNotFoundException.php new file mode 100644 index 000000000..dc4f6fbad --- /dev/null +++ b/lib/Minz/RouteNotFoundException.php @@ -0,0 +1,16 @@ +<?php +class Minz_RouteNotFoundException extends Minz_Exception { + private $route; + + public function __construct ($route, $code = self::ERROR) { + $this->route = $route; + + $message = 'Route `' . $route . '` not found'; + + parent::__construct ($message, $code); + } + + public function route () { + return $this->route; + } +} diff --git a/lib/minz/Router.php b/lib/Minz/Router.php index c5d6f5baa..1ccd72597 100755..100644 --- a/lib/minz/Router.php +++ b/lib/Minz/Router.php @@ -8,7 +8,7 @@ * La classe Router gère le routage de l'application * Les routes sont définies dans APP_PATH.'/configuration/routes.php' */ -class Router { +class Minz_Router { const ROUTES_PATH_NAME = '/configuration/routes.php'; private $routes = array (); @@ -19,7 +19,7 @@ class Router { * et que l'on utilise l'url rewriting */ public function __construct () { - if (Configuration::useUrlRewriting ()) { + if (Minz_Configuration::useUrlRewriting ()) { if (file_exists (APP_PATH . self::ROUTES_PATH_NAME)) { $routes = include ( APP_PATH . self::ROUTES_PATH_NAME @@ -34,9 +34,9 @@ class Router { $routes ); } else { - throw new FileNotExistException ( + throw new Minz_FileNotExistException ( self::ROUTES_PATH_NAME, - MinzException::ERROR + Minz_Exception::ERROR ); } } @@ -51,10 +51,10 @@ class Router { public function init () { $url = array (); - if (Configuration::useUrlRewriting ()) { + if (Minz_Configuration::useUrlRewriting ()) { try { $url = $this->buildWithRewriting (); - } catch (RouteNotFoundException $e) { + } catch (Minz_RouteNotFoundException $e) { throw $e; } } else { @@ -63,10 +63,10 @@ class Router { $url['params'] = array_merge ( $url['params'], - Request::fetchPOST () + Minz_Request::fetchPOST () ); - Request::forward ($url); + Minz_Request::forward ($url); } /** @@ -77,15 +77,15 @@ class Router { public function buildWithoutRewriting () { $url = array (); - $url['c'] = Request::fetchGET ( + $url['c'] = Minz_Request::fetchGET ( 'c', - Request::defaultControllerName () + Minz_Request::defaultControllerName () ); - $url['a'] = Request::fetchGET ( + $url['a'] = Minz_Request::fetchGET ( 'a', - Request::defaultActionName () + Minz_Request::defaultActionName () ); - $url['params'] = Request::fetchGET (); + $url['params'] = Minz_Request::fetchGET (); // post-traitement unset ($url['params']['c']); @@ -103,7 +103,7 @@ class Router { */ public function buildWithRewriting () { $url = array (); - $uri = Request::getURI (); + $uri = Minz_Request::getURI (); $find = false; foreach ($this->routes as $route) { @@ -121,14 +121,14 @@ class Router { } if (!$find && $uri != '/') { - throw new RouteNotFoundException ( + throw new Minz_RouteNotFoundException ( $uri, - MinzException::ERROR + Minz_Exception::ERROR ); } // post-traitement - $url = Url::checkUrl ($url); + $url = Minz_Url::checkUrl ($url); return $url; } diff --git a/lib/minz/Session.php b/lib/Minz/Session.php index f9c9c6754..878caa556 100755..100644 --- a/lib/minz/Session.php +++ b/lib/Minz/Session.php @@ -4,7 +4,7 @@ * La classe Session gère la session utilisateur * C'est un singleton */ -class Session { +class Minz_Session { /** * $session stocke les variables de session */ @@ -15,7 +15,7 @@ class Session { */ public static function init () { // démarre la session - session_name (md5 (Configuration::selApplication ())); + session_name (md5 (Minz_Configuration::selApplication ())); session_start (); if (isset ($_SESSION)) { @@ -55,7 +55,7 @@ class Session { if($p == 'language') { // reset pour remettre à jour le fichier de langue à utiliser - Translate::reset (); + Minz_Translate::reset (); } } } diff --git a/lib/minz/Translate.php b/lib/Minz/Translate.php index e8cbe4852..e14f783f7 100644 --- a/lib/minz/Translate.php +++ b/lib/Minz/Translate.php @@ -8,7 +8,7 @@ * La classe Translate se charge de la traduction * Utilise les fichiers du répertoire /app/i18n/ */ -class Translate { +class Minz_Translate { /** * $language est la langue à afficher */ @@ -25,8 +25,8 @@ class Translate { * l'enregistre dans $translates */ public static function init () { - $l = Configuration::language (); - self::$language = Session::param ('language', $l); + $l = Minz_Configuration::language (); + self::$language = Minz_Session::param ('language', $l); $l_path = APP_PATH . '/i18n/' . self::$language . '.php'; diff --git a/lib/minz/Url.php b/lib/Minz/Url.php index ce051ebd9..30f7f6231 100755..100644 --- a/lib/minz/Url.php +++ b/lib/Minz/Url.php @@ -3,7 +3,7 @@ /** * La classe Url permet de gérer les URL à travers MINZ */ -class Url { +class Minz_Url { /** * Affiche une Url formatée selon que l'on utilise l'url_rewriting ou non * si oui, on cherche dans la table de routage la correspondance pour formater @@ -29,16 +29,16 @@ class Url { } else { $protocol = 'http:'; } - $url_string = $protocol . '//' . Request::getDomainName () . Request::getBaseUrl (); + $url_string = $protocol . '//' . Minz_Request::getDomainName () . Minz_Request::getBaseUrl (); } else { $url_string = '.'; } if (is_array ($url)) { - $router = new Router (); + $router = new Minz_Router (); - if (Configuration::useUrlRewriting ()) { + if (Minz_Configuration::useUrlRewriting ()) { $url_string .= $router->printUriRewrited ($url); } else { $url_string .= self::printUri ($url, $encodage); @@ -67,13 +67,13 @@ class Url { } if (isset ($url['c']) - && $url['c'] != Request::defaultControllerName ()) { + && $url['c'] != Minz_Request::defaultControllerName ()) { $uri .= $separator . 'c=' . $url['c']; $separator = $and; } if (isset ($url['a']) - && $url['a'] != Request::defaultActionName ()) { + && $url['a'] != Minz_Request::defaultActionName ()) { $uri .= $separator . 'a=' . $url['a']; $separator = $and; } @@ -98,10 +98,10 @@ class Url { if (is_array ($url)) { if (!isset ($url['c'])) { - $url_checked['c'] = Request::defaultControllerName (); + $url_checked['c'] = Minz_Request::defaultControllerName (); } if (!isset ($url['a'])) { - $url_checked['a'] = Request::defaultActionName (); + $url_checked['a'] = Minz_Request::defaultActionName (); } if (!isset ($url['params'])) { $url_checked['params'] = array (); @@ -125,5 +125,5 @@ function _url ($controller, $action) { $params[$args[$i]] = $args[$i + 1]; } - return Url::display (array ('c' => $controller, 'a' => $action, 'params' => $params)); + return Minz_Url::display (array ('c' => $controller, 'a' => $action, 'params' => $params)); } diff --git a/lib/minz/View.php b/lib/Minz/View.php index fd92762b3..c8d0aefed 100755..100644 --- a/lib/minz/View.php +++ b/lib/Minz/View.php @@ -7,7 +7,7 @@ /** * La classe View représente la vue de l'application */ -class View { +class Minz_View { const VIEWS_PATH_NAME = '/views'; const LAYOUT_PATH_NAME = '/layout'; const LAYOUT_FILENAME = '/layout.phtml'; @@ -28,8 +28,8 @@ class View { public function __construct () { $this->view_filename = APP_PATH . self::VIEWS_PATH_NAME . '/' - . Request::controllerName () . '/' - . Request::actionName () . '.phtml'; + . Minz_Request::controllerName () . '/' + . Minz_Request::actionName () . '.phtml'; if (file_exists (APP_PATH . self::LAYOUT_PATH_NAME @@ -37,7 +37,7 @@ class View { $this->use_layout = true; } - self::$title = Configuration::title (); + self::$title = Minz_Configuration::title (); } /** @@ -150,8 +150,9 @@ class View { $styles .= '<!--[if ' . $cond . ']>'; } - $styles .= '<link rel="stylesheet" media="' . $style['media'] - . '" href="' . $style['url'] . '" />'; + $styles .= '<link rel="stylesheet" ' . + ($style['media'] === 'all' ? '' : 'media="' . $style['media'] . '" ') . + 'href="' . $style['url'] . '" />'; if ($cond) { $styles .= '<![endif]-->'; @@ -231,7 +232,7 @@ class View { self::$params[$key] = $value; } public function attributeParams () { - foreach (View::$params as $key => $value) { + foreach (Minz_View::$params as $key => $value) { $this->$key = $value; } } diff --git a/lib/SimplePie/SimplePie.php b/lib/SimplePie/SimplePie.php index 9e532023a..d20ab5430 100644 --- a/lib/SimplePie/SimplePie.php +++ b/lib/SimplePie/SimplePie.php @@ -602,6 +602,13 @@ class SimplePie public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'); /** + * @var array Stores the default attributes to add to differet tags by add_attributes(). + * @see SimplePie::add_attributes() + * @access private + */ + public $add_attributes = array('audio' => array('preload' => 'none'), 'iframe' => array('sandbox' => 'allow-scripts allow-same-origin'), 'video' => array('preload' => 'none')); //FreshRSS + + /** * @var array Stores the default tags to be stripped by strip_htmltags(). * @see SimplePie::strip_htmltags() * @access private @@ -1073,6 +1080,7 @@ class SimplePie $this->strip_comments(false); $this->strip_htmltags(false); $this->strip_attributes(false); + $this->add_attributes(false); $this->set_image_handler(false); } } @@ -1119,6 +1127,15 @@ class SimplePie $this->sanitize->strip_attributes($attribs); } + public function add_attributes($attribs = '') + { + if ($attribs === '') + { + $attribs = $this->add_attributes; + } + $this->sanitize->add_attributes($attribs); + } + /** * Set the output encoding * diff --git a/lib/SimplePie/SimplePie/Misc.php b/lib/SimplePie/SimplePie/Misc.php index 621f2c062..347520303 100644 --- a/lib/SimplePie/SimplePie/Misc.php +++ b/lib/SimplePie/SimplePie/Misc.php @@ -79,6 +79,10 @@ class SimplePie_Misc public static function absolutize_url($relative, $base) { + if (substr($relative, 0, 2) === '//') //FreshRSS: disable absolutize_url for "//www.example.net" which will pick HTTP or HTTPS automatically + { + return $relative; + } $iri = SimplePie_IRI::absolutize(new SimplePie_IRI($base), $relative); if ($iri === false) { diff --git a/lib/SimplePie/SimplePie/Parser.php b/lib/SimplePie/SimplePie/Parser.php index 72878c25a..c4c732787 100644 --- a/lib/SimplePie/SimplePie/Parser.php +++ b/lib/SimplePie/SimplePie/Parser.php @@ -132,7 +132,7 @@ class SimplePie_Parser } } - try + try //FreshRSS { $dom = new DOMDocument(); $dom->recover = true; @@ -140,7 +140,6 @@ class SimplePie_Parser $dom->loadXML($data); $this->encoding = $encoding = $dom->encoding = 'UTF-8'; $data = $dom->saveXML(); - //file_put_contents('/home/alex/public_html/alexandre.alapetite.fr/prive/FreshRSS/log/parser.log', date('c') . ' ' . 'OK' . "\n", FILE_APPEND); } catch (Exception $e) { diff --git a/lib/SimplePie/SimplePie/Sanitize.php b/lib/SimplePie/SimplePie/Sanitize.php index 83a274ced..0974c150d 100644 --- a/lib/SimplePie/SimplePie/Sanitize.php +++ b/lib/SimplePie/SimplePie/Sanitize.php @@ -62,6 +62,7 @@ class SimplePie_Sanitize 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', 'lowsrc', 'dynsrc'); + var $add_attributes = array('audio' => array('preload' => 'none'), 'iframe' => array('sandbox' => 'allow-scripts allow-same-origin'), 'video' => array('preload' => 'none')); //FreshRSS var $strip_comments = false; var $output_encoding = 'UTF-8'; var $enable_cache = true; @@ -179,6 +180,25 @@ class SimplePie_Sanitize } } + public function add_attributes($attribs = array('audio' => array('preload' => 'none'), 'iframe' => array('sandbox' => 'allow-scripts allow-same-origin'), 'video' => array('preload' => 'none'))) + { + if ($attribs) + { + if (is_array($attribs)) + { + $this->add_attributes = $attribs; + } + else + { + $this->add_attributes = explode(',', $attribs); + } + } + else + { + $this->add_attributes = false; + } + } + public function strip_comments($strip = false) { $this->strip_comments = (bool) $strip; @@ -255,10 +275,11 @@ class SimplePie_Sanitize $document->loadHTML($data); restore_error_handler(); + $xpath = new DOMXPath($document); //FreshRSS + // Strip comments if ($this->strip_comments) { - $xpath = new DOMXPath($document); $comments = $xpath->query('//comment()'); foreach ($comments as $comment) @@ -274,7 +295,7 @@ class SimplePie_Sanitize { foreach ($this->strip_htmltags as $tag) { - $this->strip_tag($tag, $document, $type); + $this->strip_tag($tag, $document, $xpath, $type); } } @@ -282,7 +303,15 @@ class SimplePie_Sanitize { foreach ($this->strip_attributes as $attrib) { - $this->strip_attr($attrib, $document); + $this->strip_attr($attrib, $xpath); + } + } + + if ($this->add_attributes) + { + foreach ($this->add_attributes as $tag => $valuePairs) + { + $this->add_attr($tag, $valuePairs, $document); } } @@ -452,9 +481,8 @@ class SimplePie_Sanitize } } - protected function strip_tag($tag, $document, $type) + protected function strip_tag($tag, $document, $xpath, $type) { - $xpath = new DOMXPath($document); $elements = $xpath->query('body//' . $tag); if ($this->encode_instead_of_strip) { @@ -537,9 +565,8 @@ class SimplePie_Sanitize } } - protected function strip_attr($attrib, $document) + protected function strip_attr($attrib, $xpath) { - $xpath = new DOMXPath($document); $elements = $xpath->query('//*[@' . $attrib . ']'); foreach ($elements as $element) @@ -547,4 +574,16 @@ class SimplePie_Sanitize $element->removeAttribute($attrib); } } + + protected function add_attr($tag, $valuePairs, $document) + { + $elements = $document->getElementsByTagName($tag); + foreach ($elements as $element) + { + foreach ($valuePairs as $attrib => $value) + { + $element->setAttribute($attrib, $value); + } + } + } } diff --git a/lib/SimplePie_autoloader.php b/lib/SimplePie_autoloader.php deleted file mode 100644 index 3f67635b0..000000000 --- a/lib/SimplePie_autoloader.php +++ /dev/null @@ -1,86 +0,0 @@ -<?php -/** - * SimplePie - * - * A PHP-Based RSS and Atom Feed Framework. - * Takes the hard work out of managing a complete RSS/Atom solution. - * - * Copyright (c) 2004-2009, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors - * 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. - * - * @package SimplePie - * @version 1.3.1 - * @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue - * @author Ryan Parman - * @author Geoffrey Sneddon - * @author Ryan McCue - * @link http://simplepie.org/ SimplePie - * @license http://www.opensource.org/licenses/bsd-license.php BSD License - */ - - -// autoloader -spl_autoload_register(array(new SimplePie_Autoloader(), 'autoload')); - -if (!class_exists('SimplePie')) -{ - trigger_error('Autoloader not registered properly', E_USER_ERROR); -} - -/** - * Autoloader class - * - * @package SimplePie - * @subpackage API - */ -class SimplePie_Autoloader -{ - /** - * Constructor - */ - public function __construct() - { - $this->path = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'SimplePie'; - } - - /** - * Autoloader - * - * @param string $class The name of the class to attempt to load. - */ - public function autoload($class) - { - // Only load the class if it starts with "SimplePie" - if (strpos($class, 'SimplePie') !== 0) - { - return; - } - - $filename = $this->path . DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php'; - include $filename; - } -} diff --git a/lib/http-conditional.php b/lib/http-conditional.php index 6684fd6ac..59fbef41f 100644 --- a/lib/http-conditional.php +++ b/lib/http-conditional.php @@ -35,7 +35,7 @@ ... //Rest of the script, just as you would do normally. ?> - Version 1.7 beta, 2013-11-03, http://alexandre.alapetite.fr/doc-alex/php-http-304/ + Version 1.7 beta, 2013-12-02, http://alexandre.alapetite.fr/doc-alex/php-http-304/ ------------------------------------------------------------------ Written by Alexandre Alapetite, http://alexandre.alapetite.fr/cv/ @@ -124,7 +124,7 @@ function httpConditional($UnixTimeStamp,$cacheSeconds=0,$cachePrivacy=0,$feedMod if ($feedMode) {//Special RSS/ATOM global $clientCacheDate; - $clientCacheDate=strtotime($dateCacheClient); + $clientCacheDate=@strtotime($dateCacheClient); $cachePrivacy=0; } diff --git a/lib/lib_rss.php b/lib/lib_rss.php index a27994e94..dda576b98 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -1,7 +1,64 @@ <?php +if (!function_exists('json_decode')) { + require_once('JSON.php'); + function json_decode($var) { + $JSON = new Services_JSON; + return (array)($JSON->decode($var)); + } +} + +if (!function_exists('json_encode')) { + require_once('JSON.php'); + function json_encode($var) { + $JSON = new Services_JSON; + return $JSON->encodeUnsafe($var); + } +} + +//<Auto-loading> +function classAutoloader($class) { + if (strpos($class, 'FreshRSS') === 0) { + $components = explode('_', $class); + switch (count($components)) { + case 1: + include(APP_PATH . '/' . $components[0] . '.php'); + return; + case 2: + include(APP_PATH . '/Models/' . $components[1] . '.php'); + return; + case 3: //Controllers, Exceptions + include(APP_PATH . '/' . $components[2] . 's/' . $components[1] . $components[2] . '.php'); + return; + } + } elseif (strpos($class, 'Minz') === 0) { + include(LIB_PATH . '/' . str_replace('_', '/', $class) . '.php'); + } elseif (strpos($class, 'SimplePie') === 0) { + include(LIB_PATH . '/SimplePie/' . str_replace('_', '/', $class) . '.php'); + } +} + +spl_autoload_register('classAutoloader'); +//</Auto-loading> + +function checkUrl($url) { + if (empty ($url)) { + return ''; + } + if (!preg_match ('#^https?://#i', $url)) { + $url = 'http://' . $url; + } + if (filter_var($url, FILTER_VALIDATE_URL) || + (version_compare(PHP_VERSION, '5.3.3', '<') && (strpos($url, '-') > 0) && //PHP bug #51192 + ($url === filter_var($url, FILTER_SANITIZE_URL)))) { + return $url; + } else { + return false; + } +} + // vérifie qu'on est connecté function is_logged () { - return Session::param ('mail') != false; + return Minz_Session::param ('mail') != false; } // vérifie que le système d'authentification est configuré @@ -9,25 +66,36 @@ function login_is_conf ($conf) { return $conf->mailLogin () != false; } -// tiré de Shaarli de Seb Sauvage +// tiré de Shaarli de Seb Sauvage //Format RFC 4648 base64url function small_hash ($txt) { $t = rtrim (base64_encode (hash ('crc32', $txt, true)), '='); - $t = str_replace ('+', '-', $t); // Get rid of characters which need encoding in URLs. - $t = str_replace ('/', '_', $t); - $t = str_replace ('=', '@', $t); + return strtr ($t, '+/', '-_'); +} - return $t; +function formatBytes($bytes, $precision = 2, $system = 'IEC') { + if ($system === 'IEC') { + $base = 1024; + $units = array('B', 'KiB', 'MiB', 'GiB', 'TiB'); + } elseif ($system === 'SI') { + $base = 1000; + $units = array('B', 'KB', 'MB', 'GB', 'TB'); + } + $bytes = max(intval($bytes), 0); + $pow = $bytes === 0 ? 0 : floor(log($bytes) / log($base)); + $pow = min($pow, count($units) - 1); + $bytes /= pow($base, $pow); + return round($bytes, $precision) . ' ' . $units[$pow]; } function timestamptodate ($t, $hour = true) { - $month = Translate::t (date('M', $t)); + $month = Minz_Translate::t (date('M', $t)); if ($hour) { - $date = Translate::t ('format_date_hour', $month); + $date = Minz_Translate::t ('format_date_hour', $month); } else { - $date = Translate::t ('format_date', $month); + $date = Minz_Translate::t ('format_date', $month); } - return date ($date, $t); + return @date ($date, $t); } function sortEntriesByDate ($entry1, $entry2) { @@ -48,7 +116,7 @@ function opml_export ($cats) { $txt .= '<outline text="' . $cat['name'] . '">' . "\n"; foreach ($cat['feeds'] as $feed) { - $txt .= "\t" . '<outline text="' . cleanText ($feed->name ()) . '" type="rss" xmlUrl="' . htmlentities ($feed->url (), ENT_COMPAT, 'UTF-8') . '" htmlUrl="' . htmlentities ($feed->website (), ENT_COMPAT, 'UTF-8') . '" />' . "\n"; + $txt .= "\t" . '<outline text="' . $feed->name () . '" type="rss" xmlUrl="' . $feed->url () . '" htmlUrl="' . $feed->website () . '" description="' . htmlspecialchars($feed->description(), ENT_COMPAT, 'UTF-8') . '" />' . "\n"; } $txt .= '</outline>' . "\n"; @@ -57,18 +125,41 @@ function opml_export ($cats) { return $txt; } -function cleanText ($text) { - return preg_replace ('/&[\w]+;/', '', $text); +function html_only_entity_decode($text) { + static $htmlEntitiesOnly = null; + if ($htmlEntitiesOnly === null) { + $htmlEntitiesOnly = array_flip(array_diff( + get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES, 'UTF-8'), //Decode HTML entities + get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES, 'UTF-8') //Preserve XML entities + )); + } + return strtr($text, $htmlEntitiesOnly); +} + +function sanitizeHTML($data) { + static $simplePie = null; + if ($simplePie == null) { + $simplePie = new SimplePie(); + } + return html_only_entity_decode($simplePie->sanitize->sanitize($data, SIMPLEPIE_CONSTRUCT_MAYBE_HTML)); } function opml_import ($xml) { - $opml = @simplexml_load_string ($xml); + $xml = html_only_entity_decode($xml); //!\ Assume UTF-8 + + $dom = new DOMDocument(); + $dom->recover = true; + $dom->strictErrorChecking = false; + $dom->loadXML($xml); + $dom->encoding = 'UTF-8'; + + $opml = simplexml_import_dom($dom); if (!$opml) { - throw new OpmlException (); + throw new FreshRSS_Opml_Exception (); } - $catDAO = new CategoryDAO(); + $catDAO = new FreshRSS_CategoryDAO(); $catDAO->checkDefault(); $defCat = $catDAO->getDefault(); @@ -93,12 +184,17 @@ function opml_import ($xml) { // alors qu'il existe déjà la catégorie X mais avec l'id Z // Y ne sera pas ajouté et le flux non plus vu que l'id // de sa catégorie n'exisera pas - $catDAO = new CategoryDAO (); + $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8'); + $catDAO = new FreshRSS_CategoryDAO (); $cat = $catDAO->searchByName ($title); if ($cat === false) { - $cat = new Category ($title); + $cat = new FreshRSS_Category ($title); + $values = array ( + 'name' => $cat->name (), + 'color' => $cat->color () + ); + $cat->_id ($catDAO->addCategory ($values)); } - $categories[] = $cat; $feeds = array_merge ($feeds, getFeedsOutline ($outline, $cat->id ())); } @@ -133,21 +229,31 @@ function getFeedsOutline ($outline, $cat_id) { function getFeed ($outline, $cat_id) { $url = (string) $outline['xmlUrl']; + $url = htmlspecialchars($url, ENT_COMPAT, 'UTF-8'); $title = ''; if (isset ($outline['text'])) { $title = (string) $outline['text']; } elseif (isset ($outline['title'])) { $title = (string) $outline['title']; } - $feed = new Feed ($url); + $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8'); + $feed = new FreshRSS_Feed ($url); $feed->_category ($cat_id); $feed->_name ($title); + if (isset($outline['htmlUrl'])) { + $feed->_website(htmlspecialchars((string)$outline['htmlUrl'], ENT_COMPAT, 'UTF-8')); + } + if (isset($outline['description'])) { + $feed->_description(sanitizeHTML((string)$outline['description'])); + } return $feed; } /* permet de récupérer le contenu d'un article pour un flux qui n'est pas complet */ function get_content_by_parsing ($url, $path) { + require_once (LIB_PATH . '/lib_phpQuery.php'); + $html = file_get_contents ($url); if ($html) { @@ -169,42 +275,39 @@ function get_content_by_parsing ($url, $path) { } } -/* Télécharge le favicon d'un site, le place sur le serveur et retourne l'URL */ -function dowload_favicon ($website, $id) { - $url = 'http://g.etfv.co/' . $website; - $favicons_dir = PUBLIC_PATH . '/data/favicons'; - $dest = $favicons_dir . '/' . $id . '.ico'; - $favicon_url = '/data/favicons/' . $id . '.ico'; - - if (!is_dir ($favicons_dir)) { - if (!mkdir ($favicons_dir, 0755, true)) { - return $url; - } - } - - if (!file_exists ($dest)) { - $c = curl_init ($url); - curl_setopt ($c, CURLOPT_HEADER, false); - curl_setopt ($c, CURLOPT_RETURNTRANSFER, true); - curl_setopt ($c, CURLOPT_BINARYTRANSFER, true); - $imgRaw = curl_exec ($c); +/** + * Add support of image lazy loading + * Move content from src attribute to data-original + * @param content is the text we want to parse + */ +function lazyimg($content) { + return preg_replace( + '/<img([^>]+?)src=[\'"]([^"\']+)[\'"]([^>]*)>/i', + '<img$1src="' . Minz_Url::display('/themes/icons/grey.gif') . '" data-original="$2"$3>', + $content + ); +} - if (curl_getinfo ($c, CURLINFO_HTTP_CODE) == 200) { - $file = fopen ($dest, 'w'); - if ($file === false) { - return $url; - } +function lazyIframe($content) { + return preg_replace( + '/<iframe([^>]+?)src=[\'"]([^"\']+)[\'"]([^>]*)>/i', + '<iframe$1src="about:blank" data-original="$2"$3>', + $content + ); +} - fwrite ($file, $imgRaw); - fclose ($file); - } else { - return $url; - } +function uTimeString() { + $t = @gettimeofday(); + return $t['sec'] . str_pad($t['usec'], 6, '0'); +} - curl_close ($c); - } +function uSecString() { + $t = @gettimeofday(); + return str_pad($t['usec'], 6, '0'); +} - return $favicon_url; +function invalidateHttpCache() { + file_put_contents(DATA_PATH . '/touch.txt', uTimeString()); } /** diff --git a/lib/minz/exceptions/MinzException.php b/lib/minz/exceptions/MinzException.php deleted file mode 100644 index 4568c4da8..000000000 --- a/lib/minz/exceptions/MinzException.php +++ /dev/null @@ -1,94 +0,0 @@ -<?php - -class MinzException extends Exception { - const ERROR = 0; - const WARNING = 10; - const NOTICE = 20; - - public function __construct ($message, $code = self::ERROR) { - if ($code != MinzException::ERROR - && $code != MinzException::WARNING - && $code != MinzException::NOTICE) { - $code = MinzException::ERROR; - } - - parent::__construct ($message, $code); - } -} - -class PermissionDeniedException extends MinzException { - public function __construct ($file_name, $code = self::ERROR) { - $message = 'Permission is denied for `' . $file_name.'`'; - - parent::__construct ($message, $code); - } -} -class FileNotExistException extends MinzException { - public function __construct ($file_name, $code = self::ERROR) { - $message = 'File doesn\'t exist : `' . $file_name.'`'; - - parent::__construct ($message, $code); - } -} -class BadConfigurationException extends MinzException { - public function __construct ($part_missing, $code = self::ERROR) { - $message = '`' . $part_missing - . '` in the configuration file is missing or is misconfigured'; - - parent::__construct ($message, $code); - } -} -class ControllerNotExistException extends MinzException { - public function __construct ($controller_name, $code = self::ERROR) { - $message = 'Controller `' . $controller_name - . '` doesn\'t exist'; - - parent::__construct ($message, $code); - } -} -class ControllerNotActionControllerException extends MinzException { - public function __construct ($controller_name, $code = self::ERROR) { - $message = 'Controller `' . $controller_name - . '` isn\'t instance of ActionController'; - - parent::__construct ($message, $code); - } -} -class ActionException extends MinzException { - public function __construct ($controller_name, $action_name, $code = self::ERROR) { - $message = '`' . $action_name . '` cannot be invoked on `' - . $controller_name . '`'; - - parent::__construct ($message, $code); - } -} -class RouteNotFoundException extends MinzException { - private $route; - - public function __construct ($route, $code = self::ERROR) { - $this->route = $route; - - $message = 'Route `' . $route . '` not found'; - - parent::__construct ($message, $code); - } - - public function route () { - return $this->route; - } -} -class PDOConnectionException extends MinzException { - public function __construct ($string_connection, $user, $code = self::ERROR) { - $message = 'Access to database is denied for `' . $user . '`' - . ' (`' . $string_connection . '`)'; - - parent::__construct ($message, $code); - } -} -class CurrentPagePaginationException extends MinzException { - public function __construct ($page) { - $message = 'Page number `' . $page . '` doesn\'t exist'; - - parent::__construct ($message, self::ERROR); - } -} |
