summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/.htaccess3
-rw-r--r--lib/JSON.php933
-rw-r--r--[-rwxr-xr-x]lib/Minz/ActionController.php (renamed from lib/minz/ActionController.php)4
-rw-r--r--lib/Minz/ActionException.php9
-rw-r--r--lib/Minz/BadConfigurationException.php9
-rw-r--r--lib/Minz/Cache.php (renamed from lib/minz/Minz_Cache.php)6
-rw-r--r--lib/Minz/Configuration.php340
-rw-r--r--lib/Minz/ControllerNotActionControllerException.php9
-rw-r--r--lib/Minz/ControllerNotExistException.php9
-rw-r--r--lib/Minz/CurrentPagePaginationException.php8
-rw-r--r--lib/Minz/Dispatcher.php (renamed from lib/minz/Dispatcher.php)79
-rw-r--r--[-rwxr-xr-x]lib/Minz/Error.php (renamed from lib/minz/Error.php)40
-rw-r--r--lib/Minz/Exception.php16
-rw-r--r--lib/Minz/FileNotExistException.php8
-rw-r--r--[-rwxr-xr-x]lib/Minz/FrontController.php (renamed from lib/minz/FrontController.php)97
-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)62
-rw-r--r--[-rwxr-xr-x]lib/Minz/Model.php (renamed from lib/minz/Model.php)2
-rw-r--r--lib/Minz/ModelArray.php81
-rw-r--r--[-rwxr-xr-x]lib/Minz/ModelPdo.php (renamed from lib/minz/dao/Model_pdo.php)49
-rw-r--r--lib/Minz/PDOConnectionException.php9
-rw-r--r--[-rwxr-xr-x]lib/Minz/Paginator.php (renamed from lib/minz/Paginator.php)2
-rw-r--r--lib/Minz/PermissionDeniedException.php8
-rw-r--r--lib/Minz/Request.php (renamed from lib/minz/Request.php)30
-rw-r--r--lib/Minz/Response.php (renamed from lib/minz/Response.php)2
-rw-r--r--lib/Minz/RouteNotFoundException.php16
-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)49
-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)33
-rw-r--r--[-rwxr-xr-x]lib/Minz/View.php (renamed from lib/minz/View.php)44
-rw-r--r--lib/SimplePie/SimplePie.php30
-rw-r--r--lib/SimplePie/SimplePie/File.php1
-rw-r--r--lib/SimplePie/SimplePie/Misc.php4
-rw-r--r--lib/SimplePie/SimplePie/Parser.php31
-rw-r--r--lib/SimplePie/SimplePie/Sanitize.php53
-rw-r--r--lib/SimplePie_autoloader.php86
-rw-r--r--lib/http-conditional.php4
-rw-r--r--lib/lib_opml.php121
-rw-r--r--lib/lib_rss.php350
-rwxr-xr-xlib/minz/Configuration.php250
-rwxr-xr-xlib/minz/dao/Model_array.php122
-rwxr-xr-xlib/minz/dao/Model_txt.php84
-rw-r--r--lib/minz/exceptions/MinzException.php94
-rw-r--r--lib/password_compat.php279
45 files changed, 2406 insertions, 1102 deletions
diff --git a/lib/.htaccess b/lib/.htaccess
new file mode 100644
index 000000000..9e768397d
--- /dev/null
+++ b/lib/.htaccess
@@ -0,0 +1,3 @@
+Order Allow,Deny
+Deny from all
+Satisfy all
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
new file mode 100644
index 000000000..572b9984d
--- /dev/null
+++ b/lib/Minz/Configuration.php
@@ -0,0 +1,340 @@
+<?php
+/**
+ * MINZ - Copyright 2011 Marien Fressinaud
+ * Sous licence AGPL3 <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * La classe Configuration permet de gérer la configuration de l'application
+ */
+class Minz_Configuration {
+ const CONF_PATH_NAME = '/config.php';
+
+ /**
+ * VERSION est la version actuelle de MINZ
+ */
+ const VERSION = '1.3.1.freshrss'; // version spéciale FreshRSS
+
+ /**
+ * valeurs possibles pour l'"environment"
+ * SILENT rend l'application muette (pas de log)
+ * PRODUCTION est recommandée pour une appli en production
+ * (log les erreurs critiques)
+ * DEVELOPMENT log toutes les erreurs
+ */
+ const SILENT = 0;
+ const PRODUCTION = 1;
+ const DEVELOPMENT = 2;
+
+ /**
+ * définition des variables de configuration
+ * $salt une chaîne de caractères aléatoires (obligatoire)
+ * $environment gère le niveau d'affichage pour log et erreurs
+ * $use_url_rewriting indique si on utilise l'url_rewriting
+ * $base_url le chemin de base pour accéder à l'application
+ * $title le nom de l'application
+ * $language la langue par défaut de l'application
+ * $cacheEnabled permet de savoir si le cache doit être activé
+ * $delayCache la limite de cache
+ * $db paramètres pour la base de données (tableau)
+ * - host le serveur de la base
+ * - user nom d'utilisateur
+ * - password mot de passe de l'utilisateur
+ * - base le nom de la base de données
+ */
+ private static $salt = '';
+ 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 $allow_anonymous = false;
+ private static $auth_type = 'none';
+
+ private static $db = array (
+ 'type' => 'mysql',
+ 'host' => '',
+ 'user' => '',
+ 'password' => '',
+ 'base' => '',
+ 'prefix' => '',
+ );
+
+ /*
+ * Getteurs
+ */
+ public static function salt () {
+ return self::$salt;
+ }
+ public static function environment ($str = false) {
+ $env = self::$environment;
+
+ if ($str) {
+ switch (self::$environment) {
+ case self::SILENT:
+ $env = 'silent';
+ break;
+ case self::DEVELOPMENT:
+ $env = 'development';
+ break;
+ case self::PRODUCTION:
+ default:
+ $env = 'production';
+ }
+ }
+
+ return $env;
+ }
+ public static function baseUrl () {
+ return self::$base_url;
+ }
+ public static function useUrlRewriting () {
+ return self::$use_url_rewriting;
+ }
+ public static function title () {
+ return self::$title;
+ }
+ public static function language () {
+ return self::$language;
+ }
+ public static function cacheEnabled () {
+ return self::$cache_enabled;
+ }
+ public static function delayCache () {
+ return self::$delay_cache;
+ }
+ public static function dataBase () {
+ return self::$db;
+ }
+ public static function defaultUser () {
+ return self::$default_user;
+ }
+ public static function isAdmin($currentUser) {
+ return $currentUser === self::$default_user;
+ }
+ public static function allowAnonymous() {
+ return self::$allow_anonymous;
+ }
+ public static function authType() {
+ return self::$auth_type;
+ }
+ public static function needsLogin() {
+ return self::$auth_type !== 'none';
+ }
+ public static function canLogIn() {
+ return self::$auth_type === 'form' || self::$auth_type === 'persona';
+ }
+
+ public static function _allowAnonymous($allow = false) {
+ self::$allow_anonymous = ((bool)$allow) && self::canLogIn();
+ }
+ public static function _authType($value) {
+ $value = strtolower($value);
+ switch ($value) {
+ case 'form':
+ case 'http_auth':
+ case 'persona':
+ case 'none':
+ self::$auth_type = $value;
+ break;
+ }
+ self::_allowAnonymous(self::$allow_anonymous);
+ }
+
+ /**
+ * Initialise les variables de configuration
+ * @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 (Minz_FileNotExistException $e) {
+ throw $e;
+ } catch (Minz_BadConfigurationException $e) {
+ throw $e;
+ }
+ }
+
+ public static function writeFile() {
+ $ini_array = array(
+ 'general' => array(
+ 'environment' => self::environment(true),
+ 'use_url_rewriting' => self::$use_url_rewriting,
+ 'salt' => self::$salt,
+ 'base_url' => self::$base_url,
+ 'title' => self::$title,
+ 'default_user' => self::$default_user,
+ 'allow_anonymous' => self::$allow_anonymous,
+ 'auth_type' => self::$auth_type,
+ ),
+ 'db' => self::$db,
+ );
+ @rename(DATA_PATH . self::CONF_PATH_NAME, DATA_PATH . self::CONF_PATH_NAME . '.bak.php');
+ $result = file_put_contents(DATA_PATH . self::CONF_PATH_NAME, "<?php\n return " . var_export($ini_array, true) . ';');
+ if (function_exists('opcache_invalidate')) {
+ opcache_invalidate(DATA_PATH . self::CONF_PATH_NAME); //Clear PHP 5.5+ cache for include
+ }
+ return (bool)$result;
+ }
+
+ /**
+ * Parse un fichier de configuration
+ * @exception Minz_PermissionDeniedException si le CONF_PATH_NAME n'est pas accessible
+ * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté
+ */
+ private static function parseFile () {
+ $ini_array = include(DATA_PATH . self::CONF_PATH_NAME);
+
+ if (!is_array($ini_array)) {
+ throw new Minz_PermissionDeniedException (
+ DATA_PATH . self::CONF_PATH_NAME,
+ Minz_Exception::ERROR
+ );
+ }
+
+ // [general] est obligatoire
+ if (!isset ($ini_array['general'])) {
+ throw new Minz_BadConfigurationException (
+ '[general]',
+ Minz_Exception::ERROR
+ );
+ }
+ $general = $ini_array['general'];
+
+ // salt est obligatoire
+ if (!isset ($general['salt'])) {
+ if (isset($general['sel_application'])) { //v0.6
+ $general['salt'] = $general['sel_application'];
+ } else {
+ throw new Minz_BadConfigurationException (
+ 'salt',
+ Minz_Exception::ERROR
+ );
+ }
+ }
+ self::$salt = $general['salt'];
+
+ if (isset ($general['environment'])) {
+ switch ($general['environment']) {
+ case 'silent':
+ self::$environment = Minz_Configuration::SILENT;
+ break;
+ case 'development':
+ self::$environment = Minz_Configuration::DEVELOPMENT;
+ break;
+ case 'production':
+ self::$environment = Minz_Configuration::PRODUCTION;
+ break;
+ default:
+ if ($general['environment'] >= 0 &&
+ $general['environment'] <= 2) {
+ // fallback 0.7-beta
+ self::$environment = $general['environment'];
+ } else {
+ throw new Minz_BadConfigurationException (
+ 'environment',
+ Minz_Exception::ERROR
+ );
+ }
+ }
+
+ }
+ if (isset ($general['base_url'])) {
+ self::$base_url = $general['base_url'];
+ }
+ if (isset ($general['use_url_rewriting'])) {
+ self::$use_url_rewriting = $general['use_url_rewriting'];
+ }
+
+ if (isset ($general['title'])) {
+ self::$title = $general['title'];
+ }
+ if (isset ($general['language'])) {
+ self::$language = $general['language'];
+ }
+ if (isset ($general['cache_enabled'])) {
+ self::$cache_enabled = $general['cache_enabled'];
+ if (CACHE_PATH === false && self::$cache_enabled) {
+ throw new FileNotExistException (
+ 'CACHE_PATH',
+ Minz_Exception::ERROR
+ );
+ }
+ }
+ if (isset ($general['delay_cache'])) {
+ self::$delay_cache = inval($general['delay_cache']);
+ }
+ if (isset ($general['default_user'])) {
+ self::$default_user = $general['default_user'];
+ }
+ if (isset ($general['auth_type'])) {
+ self::_authType($general['auth_type']);
+ }
+ if (isset ($general['allow_anonymous'])) {
+ self::$allow_anonymous = ((bool)($general['allow_anonymous'])) && ($general['allow_anonymous'] !== 'no');
+ }
+
+ // Base de données
+ if (isset ($ini_array['db'])) {
+ $db = $ini_array['db'];
+ if (empty($db['host'])) {
+ throw new Minz_BadConfigurationException (
+ 'host',
+ Minz_Exception::ERROR
+ );
+ }
+ if (empty($db['user'])) {
+ throw new Minz_BadConfigurationException (
+ 'user',
+ Minz_Exception::ERROR
+ );
+ }
+ if (!isset ($db['password'])) {
+ throw new Minz_BadConfigurationException (
+ 'password',
+ Minz_Exception::ERROR
+ );
+ }
+ if (empty($db['base'])) {
+ throw new Minz_BadConfigurationException (
+ 'base',
+ Minz_Exception::ERROR
+ );
+ }
+
+ if (!empty($db['type'])) {
+ self::$db['type'] = $db['type'];
+ }
+ self::$db['host'] = $db['host'];
+ self::$db['user'] = $db['user'];
+ self::$db['password'] = $db['password'];
+ self::$db['base'] = $db['base'];
+ if (isset($db['prefix'])) {
+ self::$db['prefix'] = $db['prefix'];
+ }
+ }
+ }
+
+ private static function setReporting() {
+ switch (self::$environment) {
+ case self::PRODUCTION:
+ error_reporting(E_ALL);
+ ini_set('display_errors','Off');
+ ini_set('log_errors', 'On');
+ break;
+ case self::DEVELOPMENT:
+ error_reporting(E_ALL);
+ ini_set('display_errors','On');
+ ini_set('log_errors', 'On');
+ break;
+ case self::SILENT:
+ error_reporting(0);
+ break;
+ }
+ }
+}
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..71dfe8ac6 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;
@@ -22,8 +22,8 @@ class Dispatcher {
* Récupère l'instance du Dispatcher
*/
public static function getInstance ($router) {
- if (is_null (self::$instance)) {
- self::$instance = new Dispatcher ($router);
+ if (self::$instance === null) {
+ self::$instance = new Minz_Dispatcher ($router);
}
return self::$instance;
}
@@ -38,44 +38,51 @@ 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 () {
+ public function run ($ob = true) {
$cache = new Minz_Cache();
// Le ob_start est dupliqué : sans ça il y a un bug sous Firefox
// ici on l'appelle avec 'ob_gzhandler', après sans.
// Vraisemblablement la compression fonctionne mais c'est sale
// J'ignore les effets de bord :(
- ob_start ('ob_gzhandler');
+ if ($ob) {
+ ob_start ('ob_gzhandler');
+ }
if (Minz_Cache::isEnabled () && !$cache->expired ()) {
- ob_start ();
+ if ($ob) {
+ ob_start ();
+ }
$cache->render ();
- $text = ob_get_clean();
+ if ($ob) {
+ $text = ob_get_clean();
+ }
} else {
- while (Request::$reseted) {
- Request::$reseted = false;
+ $text = ''; //TODO: Clean this code
+ 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) {
- ob_start ();
+ if (!Minz_Request::$reseted) {
+ if ($ob) {
+ ob_start ();
+ }
$this->controller->view ()->build ();
- $text = ob_get_clean();
+ if ($ob) {
+ $text = ob_get_clean();
+ }
}
- } catch (MinzException $e) {
+ } catch (Minz_Exception $e) {
throw $e;
}
}
@@ -85,14 +92,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 +106,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 +126,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..337ab6c0a 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..f8dfbdf66
--- /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 not found: `' . $file_name.'`';
+
+ parent::__construct ($message, $code);
+ }
+}
diff --git a/lib/minz/FrontController.php b/lib/Minz/FrontController.php
index d48d43d04..80eda8877 100755..100644
--- a/lib/minz/FrontController.php
+++ b/lib/Minz/FrontController.php
@@ -2,109 +2,81 @@
# ***** 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;
-
+
+ private $useOb = true;
+
/**
* 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 not found: 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) {
+ $this->dispatcher->run ($this->useOb);
+ 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 +86,7 @@ class FrontController {
}
}
}
-
+
/**
* Permet d'arrêter le programme en urgence
*/
@@ -124,4 +96,15 @@ class FrontController {
}
exit ('### Application problem ###<br />'."\n".$txt);
}
+
+ public function useOb() {
+ return $this->useOb;
+ }
+
+ /**
+ * Use ob_start('ob_gzhandler') or not.
+ */
+ public function _useOb($ob) {
+ return $this->useOb = (bool)$ob;
+ }
}
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..e710aad4a 100644
--- a/lib/minz/Minz_Log.php
+++ b/lib/Minz/Log.php
@@ -1,5 +1,5 @@
<?php
-/**
+/**
* MINZ - Copyright 2011 Marien Fressinaud
* Sous licence AGPL3 <http://www.gnu.org/licenses/>
*/
@@ -12,12 +12,14 @@ 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
* Message non loggué si
@@ -29,15 +31,15 @@ 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 ();
-
- if (! ($env == Configuration::SILENT
- || ($env == Configuration::PRODUCTION
- && ($level == Minz_Log::WARNING || $level == Minz_Log::NOTICE)))) {
- if (is_null ($file_name)) {
- $file_name = LOG_PATH . '/application.log';
+ $env = Minz_Configuration::environment ();
+
+ if (! ($env === Minz_Configuration::SILENT
+ || ($env === Minz_Configuration::PRODUCTION
+ && ($level >= Minz_Log::NOTICE)))) {
+ if ($file_name === null) {
+ $file_name = LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log';
}
-
+
switch ($level) {
case Minz_Log::ERROR :
$level_label = 'error';
@@ -48,27 +50,19 @@ 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) {
- $file = @fopen ($file_name, 'a');
- } else {
- $file = fopen ($file_name, 'a');
- }
-
- if ($file !== false) {
- $log = '[' . date('r') . ']';
- $log .= ' [' . $level_label . ']';
- $log .= ' --- ' . $information . "\n";
- fwrite ($file, $log);
- fclose ($file);
- } else {
- throw new PermissionDeniedException (
- $file_name,
- MinzException::ERROR
- );
+
+ $log = '[' . date('r') . ']'
+ . ' [' . $level_label . ']'
+ . ' --- ' . $information . "\n";
+
+ if (file_put_contents($file_name, $log, FILE_APPEND | LOCK_EX) === false) {
+ throw new Minz_PermissionDeniedException($file_name, Minz_Exception::ERROR);
}
}
}
@@ -83,7 +77,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/ModelArray.php b/lib/Minz/ModelArray.php
new file mode 100644
index 000000000..ff23dbc83
--- /dev/null
+++ b/lib/Minz/ModelArray.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * MINZ - Copyright 2011 Marien Fressinaud
+ * Sous licence AGPL3 <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * La classe Model_array représente le modèle interragissant avec les fichiers de type texte gérant des tableaux php
+ */
+class Minz_ModelArray {
+ /**
+ * $filename est le nom du fichier
+ */
+ protected $filename;
+
+ /**
+ * Ouvre le fichier indiqué, charge le tableau dans $array et le $filename
+ * @param $filename le nom du fichier à ouvrir contenant un tableau
+ * Remarque : $array sera obligatoirement un tableau
+ */
+ public function __construct ($filename) {
+ $this->filename = $filename;
+ }
+
+ protected function loadArray() {
+ if (!file_exists($this->filename)) {
+ throw new Minz_FileNotExistException($this->filename, Minz_Exception::WARNING);
+ }
+ elseif (($handle = $this->getLock()) === false) {
+ throw new Minz_PermissionDeniedException($this->filename);
+ } else {
+ $data = include($this->filename);
+ $this->releaseLock($handle);
+
+ if ($data === false) {
+ throw new Minz_PermissionDeniedException($this->filename);
+ } elseif (!is_array($data)) {
+ $data = array();
+ }
+ return $data;
+ }
+ }
+
+ /**
+ * Sauve le tableau $array dans le fichier $filename
+ **/
+ protected function writeArray($array) {
+ if (file_put_contents($this->filename, "<?php\n return " . var_export($array, true) . ';', LOCK_EX) === false) {
+ throw new Minz_PermissionDeniedException($this->filename);
+ }
+ if (function_exists('opcache_invalidate')) {
+ opcache_invalidate($this->filename); //Clear PHP 5.5+ cache for include
+ }
+ return true;
+ }
+
+ private function getLock() {
+ $handle = fopen($this->filename, 'r');
+ if ($handle === false) {
+ return false;
+ }
+
+ $count = 50;
+ while (!flock($handle, LOCK_SH) && $count > 0) {
+ $count--;
+ usleep(1000);
+ }
+
+ if ($count > 0) {
+ return $handle;
+ } else {
+ fclose($handle);
+ return false;
+ }
+ }
+
+ private function releaseLock($handle) {
+ flock($handle, LOCK_UN);
+ fclose($handle);
+ }
+}
diff --git a/lib/minz/dao/Model_pdo.php b/lib/Minz/ModelPdo.php
index a91a4fa00..831df13a2 100755..100644
--- a/lib/minz/dao/Model_pdo.php
+++ b/lib/Minz/ModelPdo.php
@@ -1,5 +1,5 @@
<?php
-/**
+/**
* MINZ - Copyright 2011 Marien Fressinaud
* Sous licence AGPL3 <http://www.gnu.org/licenses/>
*/
@@ -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.
@@ -23,7 +23,7 @@ class Model_pdo {
protected $bd;
protected $prefix;
-
+
/**
* Créé la connexion à la base de données à l'aide des variables
* HOST, BASE, USER et PASS définies dans le fichier de configuration
@@ -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,50 @@ class Model_pdo {
);
self::$sharedBd = $this->bd;
- $this->prefix = $db['prefix'];
+ $this->prefix = $db['prefix'] . Minz_Session::param('currentUser', '_') . '_';
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($all = false) {
+ $db = Minz_Configuration::dataBase ();
+ $sql = 'SELECT SUM(data_length + index_length) FROM information_schema.TABLES WHERE table_schema = ?';
+ $values = array ($db['base']);
+ if (!$all) {
+ $sql .= ' AND table_name LIKE ?';
+ $values[] = $this->prefix . '%';
+ }
+ $stm = $this->bd->prepare ($sql);
+ $stm->execute ($values);
+ $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0);
+ return $res[0];
+ }
+
+ public static function clean() {
+ self::$sharedBd = null;
+ self::$sharedPrefix = '';
+ }
}
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/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..d4e1355d7 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,14 @@ class Request {
* @return la base de l'url
*/
public static function getBaseUrl () {
- return Configuration::baseUrl ();
+ $defaultBaseUrl = Minz_Configuration::baseUrl();
+ if (!empty($defaultBaseUrl)) {
+ return $defaultBaseUrl;
+ } elseif (isset($_SERVER['REQUEST_URI'])) {
+ return dirname($_SERVER['REQUEST_URI']) . '/';
+ } else {
+ return '/';
+ }
}
/**
@@ -121,10 +131,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 +192,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 +202,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..ddabc4658 100755..100644
--- a/lib/minz/Session.php
+++ b/lib/Minz/Session.php
@@ -4,42 +4,39 @@
* La classe Session gère la session utilisateur
* C'est un singleton
*/
-class Session {
+class Minz_Session {
/**
* $session stocke les variables de session
*/
- private static $session = array ();
-
+ private static $session = array (); //TODO: Try to avoid having another local copy
+
/**
- * Initialise la session
+ * Initialise la session, avec un nom
+ * Le nom de session est utilisé comme nom pour les cookies et les URLs (i.e. PHPSESSID).
+ * Il ne doit contenir que des caractères alphanumériques ; il doit être court et descriptif
*/
- public static function init () {
+ public static function init ($name) {
// démarre la session
- session_name (md5 (Configuration::selApplication ()));
+ session_name ($name);
+ session_set_cookie_params (0, dirname(empty($_SERVER['REQUEST_URI']) ? '/' : dirname($_SERVER['REQUEST_URI'])), null, false, true);
session_start ();
-
+
if (isset ($_SESSION)) {
self::$session = $_SESSION;
}
}
-
-
+
+
/**
* Permet de récupérer une variable de session
* @param $p le paramètre à récupérer
* @return la valeur de la variable de session, false si n'existe pas
*/
public static function param ($p, $default = false) {
- if (isset (self::$session[$p])) {
- $return = self::$session[$p];
- } else {
- $return = $default;
- }
-
- return $return;
+ return isset(self::$session[$p]) ? self::$session[$p] : $default;
}
-
-
+
+
/**
* Permet de créer ou mettre à jour une variable de session
* @param $p le paramètre à créer ou modifier
@@ -52,27 +49,23 @@ class Session {
} else {
$_SESSION[$p] = $v;
self::$session[$p] = $v;
-
- if($p == 'language') {
- // reset pour remettre à jour le fichier de langue à utiliser
- Translate::reset ();
- }
}
}
-
-
+
+
/**
* Permet d'effacer une session
* @param $force si à false, n'efface pas le paramètre de langue
*/
public static function unset_session ($force = false) {
$language = self::param ('language');
-
- session_unset ();
+
+ session_destroy();
self::$session = array ();
-
+
if (!$force) {
self::_param ('language', $language);
+ 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..17f1ddece 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
@@ -17,28 +17,31 @@ class Url {
* @return l'url formatée
*/
public static function display ($url = array (), $encodage = 'html', $absolute = false) {
- $url = self::checkUrl ($url);
+ $isArray = is_array($url);
+
+ if ($isArray) {
+ $url = self::checkUrl ($url);
+ }
$url_string = '';
if ($absolute) {
- if (is_array ($url) && isset ($url['protocol'])) {
+ if ($isArray && isset ($url['protocol'])) {
$protocol = $url['protocol'];
} elseif (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
$protocol = 'https:';
} else {
$protocol = 'http:';
}
- $url_string = $protocol . '//' . Request::getDomainName () . Request::getBaseUrl ();
- }
- else {
- $url_string = '.';
+ $url_string = $protocol . '//' . Minz_Request::getDomainName () . Minz_Request::getBaseUrl ();
+ } else {
+ $url_string = $isArray ? '.' : PUBLIC_RELATIVE;
}
- if (is_array ($url)) {
- $router = new Router ();
+ if ($isArray) {
+ $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 +70,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 +101,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 +128,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..e170bd406 100755..100644
--- a/lib/minz/View.php
+++ b/lib/Minz/View.php
@@ -7,13 +7,13 @@
/**
* 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';
private $view_filename = '';
- private $use_layout = false;
+ private $use_layout = null;
private static $title = '';
private static $styles = array ();
@@ -28,22 +28,19 @@ 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
- . self::LAYOUT_FILENAME)) {
- $this->use_layout = true;
- }
-
- self::$title = Configuration::title ();
+ self::$title = Minz_Configuration::title ();
}
/**
* Construit la vue
*/
public function build () {
+ if ($this->use_layout === null) { //TODO: avoid file_exists and require views to be explicit
+ $this->use_layout = file_exists (APP_PATH . self::LAYOUT_PATH_NAME . self::LAYOUT_FILENAME);
+ }
if ($this->use_layout) {
$this->buildLayout ();
} else {
@@ -66,10 +63,8 @@ class View {
* Affiche la Vue en elle-même
*/
public function render () {
- if (file_exists ($this->view_filename)) {
- include ($this->view_filename);
- } else {
- Minz_Log::record ('File doesn\'t exist : `'
+ if ((include($this->view_filename)) === false) {
+ Minz_Log::record ('File not found: `'
. $this->view_filename . '`',
Minz_Log::NOTICE);
}
@@ -84,10 +79,8 @@ class View {
. self::LAYOUT_PATH_NAME . '/'
. $part . '.phtml';
- if (file_exists ($fic_partial)) {
- include ($fic_partial);
- } else {
- Minz_Log::record ('File doesn\'t exist : `'
+ if ((include($fic_partial)) === false) {
+ Minz_Log::record ('File not found: `'
. $fic_partial . '`',
Minz_Log::WARNING);
}
@@ -102,10 +95,8 @@ class View {
. '/views/helpers/'
. $helper . '.phtml';
- if (file_exists ($fic_helper)) {
- include ($fic_helper);
- } else {
- Minz_Log::record ('File doesn\'t exist : `'
+ if ((include($fic_helper)) === false) {;
+ Minz_Log::record ('File not found: `'
. $fic_helper . '`',
Minz_Log::WARNING);
}
@@ -150,8 +141,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 +223,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..f02037c10 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
*
@@ -1296,7 +1313,7 @@ class SimplePie
// First check to see if input has been overridden.
if ($this->input_encoding !== false)
{
- $encodings[] = $this->input_encoding;
+ $encodings[] = strtoupper($this->input_encoding);
}
$application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
@@ -1313,18 +1330,18 @@ class SimplePie
}
else
{
- $encodings[] = ''; //Let the DOM parser decide first
+ $encodings[] = ''; //FreshRSS: Let the DOM parser decide first
}
}
elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
{
if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
{
- $encodings[] = $charset[1];
+ $encodings[] = strtoupper($charset[1]);
}
else
{
- $encodings[] = '';
+ $encodings[] = ''; //FreshRSS: Let the DOM parser decide first
}
$encodings[] = 'US-ASCII';
}
@@ -1347,13 +1364,14 @@ class SimplePie
foreach ($encodings as $encoding)
{
// Change the encoding to UTF-8 (as we always use UTF-8 internally)
- if ($utf8_data = (empty($encoding) || $encoding === 'UTF-8') ? $this->raw_data : $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
+ if ($utf8_data = (empty($encoding) || $encoding === 'UTF-8') ? $this->raw_data : //FreshRSS
+ $this->registry->call('Misc', 'change_encoding', array($this->raw_data, $encoding, 'UTF-8')))
{
// Create new parser
$parser = $this->registry->create('Parser');
// If it's parsed fine
- if ($parser->parse($utf8_data, 'UTF-8'))
+ if ($parser->parse($utf8_data, empty($encoding) ? '' : 'UTF-8')) //FreshRSS
{
$this->data = $parser->get_data();
if (!($this->get_type() & ~SIMPLEPIE_TYPE_NONE))
diff --git a/lib/SimplePie/SimplePie/File.php b/lib/SimplePie/SimplePie/File.php
index 063ad955e..cf926cf5a 100644
--- a/lib/SimplePie/SimplePie/File.php
+++ b/lib/SimplePie/SimplePie/File.php
@@ -77,6 +77,7 @@ class SimplePie_File
$this->useragent = $useragent;
if (preg_match('/^http(s)?:\/\//i', $url))
{
+ syslog(LOG_INFO, 'SimplePie GET ' . $url); //FreshRSS
if ($useragent === null)
{
$useragent = ini_get('user_agent');
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..bd6c4efd8 100644
--- a/lib/SimplePie/SimplePie/Parser.php
+++ b/lib/SimplePie/SimplePie/Parser.php
@@ -77,6 +77,8 @@ class SimplePie_Parser
public function parse(&$data, $encoding)
{
+ $xmlEncoding = '';
+
if (!empty($encoding))
{
// Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
@@ -121,6 +123,7 @@ class SimplePie_Parser
$declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
if ($declaration->parse())
{
+ $xmlEncoding = strtoupper($declaration->encoding); //FreshRSS
$data = substr($data, $pos + 2);
$data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
}
@@ -132,18 +135,24 @@ class SimplePie_Parser
}
}
- try
- {
- $dom = new DOMDocument();
- $dom->recover = true;
- $dom->strictErrorChecking = false;
- $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)
+ if ($xmlEncoding === '' || $xmlEncoding === 'UTF-8') //FreshRSS: case of no explicit HTTP encoding, and lax UTF-8
{
+ try
+ {
+ $dom = new DOMDocument();
+ $dom->recover = true;
+ $dom->strictErrorChecking = false;
+ $dom->loadXML($data);
+ $this->encoding = $encoding = $dom->encoding = 'UTF-8';
+ $data2 = $dom->saveXML();
+ if (strlen($data2) > (strlen($data) / 2.0))
+ {
+ $data = $data2;
+ }
+ }
+ catch (Exception $e)
+ {
+ }
}
$return = true;
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_opml.php b/lib/lib_opml.php
new file mode 100644
index 000000000..1b5517d7f
--- /dev/null
+++ b/lib/lib_opml.php
@@ -0,0 +1,121 @@
+<?php
+function opml_export ($cats) {
+ $txt = '';
+
+ foreach ($cats as $cat) {
+ $txt .= '<outline text="' . $cat['name'] . '">' . "\n";
+
+ foreach ($cat['feeds'] as $feed) {
+ $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";
+ }
+
+ return $txt;
+}
+
+function opml_import ($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 FreshRSS_Opml_Exception ();
+ }
+
+ $catDAO = new FreshRSS_CategoryDAO();
+ $catDAO->checkDefault();
+ $defCat = $catDAO->getDefault();
+
+ $categories = array ();
+ $feeds = array ();
+
+ foreach ($opml->body->outline as $outline) {
+ if (!isset ($outline['xmlUrl'])) {
+ // Catégorie
+ $title = '';
+
+ if (isset ($outline['text'])) {
+ $title = (string) $outline['text'];
+ } elseif (isset ($outline['title'])) {
+ $title = (string) $outline['title'];
+ }
+
+ if ($title) {
+ // Permet d'éviter les soucis au niveau des id :
+ // ceux-ci sont générés en fonction de la date,
+ // un flux pourrait être dans une catégorie X avec l'id Y
+ // 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
+ $title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8');
+ $catDAO = new FreshRSS_CategoryDAO ();
+ $cat = $catDAO->searchByName ($title);
+ if ($cat === false) {
+ $cat = new FreshRSS_Category ($title);
+ $values = array (
+ 'name' => $cat->name (),
+ 'color' => $cat->color ()
+ );
+ $cat->_id ($catDAO->addCategory ($values));
+ }
+
+ $feeds = array_merge ($feeds, getFeedsOutline ($outline, $cat->id ()));
+ }
+ } else {
+ // Flux rss sans catégorie, on récupère l'ajoute dans la catégorie par défaut
+ $feeds[] = getFeed ($outline, $defCat->id());
+ }
+ }
+
+ return array ($categories, $feeds);
+}
+
+/**
+ * import all feeds of a given outline tag
+ */
+function getFeedsOutline ($outline, $cat_id) {
+ $feeds = array ();
+
+ foreach ($outline->children () as $child) {
+ if (isset ($child['xmlUrl'])) {
+ $feeds[] = getFeed ($child, $cat_id);
+ } else {
+ $feeds = array_merge(
+ $feeds,
+ getFeedsOutline ($child, $cat_id)
+ );
+ }
+ }
+
+ return $feeds;
+}
+
+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'];
+ }
+ $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;
+}
diff --git a/lib/lib_rss.php b/lib/lib_rss.php
index a27994e94..1bb117ab6 100644
--- a/lib/lib_rss.php
+++ b/lib/lib_rss.php
@@ -1,212 +1,187 @@
<?php
-// vérifie qu'on est connecté
-function is_logged () {
- return Session::param ('mail') != false;
+if (!function_exists('json_decode')) {
+ require_once('JSON.php');
+ function json_decode($var) {
+ $JSON = new Services_JSON;
+ return (array)($JSON->decode($var));
+ }
}
-// vérifie que le système d'authentification est configuré
-function login_is_conf ($conf) {
- return $conf->mailLogin () != false;
+if (!function_exists('json_encode')) {
+ require_once('JSON.php');
+ function json_encode($var) {
+ $JSON = new Services_JSON;
+ return $JSON->encodeUnsafe($var);
+ }
}
-// tiré de Shaarli de Seb Sauvage
-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 $t;
+//<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');
+ }
}
-function timestamptodate ($t, $hour = true) {
- $month = Translate::t (date('M', $t));
- if ($hour) {
- $date = Translate::t ('format_date_hour', $month);
+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 {
- $date = Translate::t ('format_date', $month);
+ return false;
}
-
- return date ($date, $t);
}
-function sortEntriesByDate ($entry1, $entry2) {
- return $entry2->date (true) - $entry1->date (true);
-}
-function sortReverseEntriesByDate ($entry1, $entry2) {
- return $entry1->date (true) - $entry2->date (true);
+// tiré de Shaarli de Seb Sauvage //Format RFC 4648 base64url
+function small_hash ($txt) {
+ $t = rtrim (base64_encode (hash ('crc32', $txt, true)), '=');
+ return strtr ($t, '+/', '-_');
}
-function get_domain ($url) {
- return parse_url($url, PHP_URL_HOST);
+function formatNumber($n, $precision = 0) {
+ return str_replace(' ', ' ', //Espace insécable //TODO: remplacer par une espace _fine_ insécable
+ number_format($n, $precision, '.', ' ')); //number_format does not seem to be Unicode-compatible
}
-function opml_export ($cats) {
- $txt = '';
-
- foreach ($cats as $cat) {
- $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 .= '</outline>' . "\n";
+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');
}
-
- return $txt;
+ $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 formatNumber($bytes, $precision) . ' ' . $units[$pow];
}
-function cleanText ($text) {
- return preg_replace ('/&[\w]+;/', '', $text);
-}
-
-function opml_import ($xml) {
- $opml = @simplexml_load_string ($xml);
-
- if (!$opml) {
- throw new OpmlException ();
- }
-
- $catDAO = new CategoryDAO();
- $catDAO->checkDefault();
- $defCat = $catDAO->getDefault();
-
- $categories = array ();
- $feeds = array ();
-
- foreach ($opml->body->outline as $outline) {
- if (!isset ($outline['xmlUrl'])) {
- // Catégorie
- $title = '';
-
- if (isset ($outline['text'])) {
- $title = (string) $outline['text'];
- } elseif (isset ($outline['title'])) {
- $title = (string) $outline['title'];
- }
-
- if ($title) {
- // Permet d'éviter les soucis au niveau des id :
- // ceux-ci sont générés en fonction de la date,
- // un flux pourrait être dans une catégorie X avec l'id Y
- // 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 ();
- $cat = $catDAO->searchByName ($title);
- if ($cat === false) {
- $cat = new Category ($title);
- }
- $categories[] = $cat;
-
- $feeds = array_merge ($feeds, getFeedsOutline ($outline, $cat->id ()));
- }
- } else {
- // Flux rss sans catégorie, on récupère l'ajoute dans la catégorie par défaut
- $feeds[] = getFeed ($outline, $defCat->id());
- }
+function timestamptodate ($t, $hour = true) {
+ $month = Minz_Translate::t (date('M', $t));
+ if ($hour) {
+ $date = Minz_Translate::t ('format_date_hour', $month);
+ } else {
+ $date = Minz_Translate::t ('format_date', $month);
}
- return array ($categories, $feeds);
+ return @date ($date, $t);
}
-/**
- * import all feeds of a given outline tag
- */
-function getFeedsOutline ($outline, $cat_id) {
- $feeds = array ();
-
- foreach ($outline->children () as $child) {
- if (isset ($child['xmlUrl'])) {
- $feeds[] = getFeed ($child, $cat_id);
+function html_only_entity_decode($text) {
+ static $htmlEntitiesOnly = null;
+ if ($htmlEntitiesOnly === null) {
+ if (version_compare(PHP_VERSION, '5.3.4') >= 0) {
+ $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
+ ));
} else {
- $feeds = array_merge(
- $feeds,
- getFeedsOutline ($child, $cat_id)
- );
+ $htmlEntitiesOnly = array_map('utf8_encode', array_flip(array_diff(
+ get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES), //Decode HTML entities
+ get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES) //Preserve XML entities
+ )));
}
}
+ return strtr($text, $htmlEntitiesOnly);
+}
- return $feeds;
+function customSimplePie() {
+ $simplePie = new SimplePie();
+ $simplePie->set_useragent(Minz_Translate::t('freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION);
+ $simplePie->set_cache_location(CACHE_PATH);
+ $simplePie->set_cache_duration(1500);
+ $simplePie->strip_htmltags(array(
+ 'base', 'blink', 'body', 'doctype', 'embed',
+ 'font', 'form', 'frame', 'frameset', 'html',
+ 'link', 'input', 'marquee', 'meta', 'noscript',
+ 'object', 'param', 'plaintext', 'script', 'style',
+ ));
+ $simplePie->strip_attributes(array_merge($simplePie->strip_attributes, array(
+ 'autoplay', 'onload', 'onunload', 'onclick', 'ondblclick', 'onmousedown', 'onmouseup',
+ 'onmouseover', 'onmousemove', 'onmouseout', 'onfocus', 'onblur',
+ 'onkeypress', 'onkeydown', 'onkeyup', 'onselect', 'onchange', 'seamless')));
+ $simplePie->add_attributes(array(
+ 'img' => array('lazyload' => ''), //http://www.w3.org/TR/resource-priorities/
+ 'audio' => array('preload' => 'none'),
+ 'iframe' => array('postpone' => '', 'sandbox' => 'allow-scripts allow-same-origin'),
+ 'video' => array('postpone' => '', 'preload' => 'none'),
+ ));
+ $simplePie->set_url_replacements(array(
+ 'a' => 'href',
+ 'area' => 'href',
+ 'audio' => 'src',
+ 'blockquote' => 'cite',
+ 'del' => 'cite',
+ 'form' => 'action',
+ 'iframe' => 'src',
+ 'img' => array(
+ 'longdesc',
+ 'src'
+ ),
+ 'input' => 'src',
+ 'ins' => 'cite',
+ 'q' => 'cite',
+ 'source' => 'src',
+ 'track' => 'src',
+ 'video' => array(
+ 'poster',
+ 'src',
+ ),
+ ));
+ return $simplePie;
}
-function getFeed ($outline, $cat_id) {
- $url = (string) $outline['xmlUrl'];
- $title = '';
- if (isset ($outline['text'])) {
- $title = (string) $outline['text'];
- } elseif (isset ($outline['title'])) {
- $title = (string) $outline['title'];
+function sanitizeHTML($data, $base = '') {
+ static $simplePie = null;
+ if ($simplePie == null) {
+ $simplePie = customSimplePie();
+ $simplePie->init();
}
- $feed = new Feed ($url);
- $feed->_category ($cat_id);
- $feed->_name ($title);
- return $feed;
+ return html_only_entity_decode($simplePie->sanitize->sanitize($data, SIMPLEPIE_CONSTRUCT_HTML, $base));
}
-
/* 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');
+
+ syslog(LOG_INFO, 'FreshRSS GET ' . $url);
$html = file_get_contents ($url);
if ($html) {
$doc = phpQuery::newDocument ($html);
$content = $doc->find ($path);
- $content->find ('*')->removeAttr ('style')
- ->removeAttr ('id')
- ->removeAttr ('class')
- ->removeAttr ('onload')
- ->removeAttr ('target');
- $content->removeAttr ('style')
- ->removeAttr ('id')
- ->removeAttr ('class')
- ->removeAttr ('onload')
- ->removeAttr ('target');
- return $content->__toString ();
+ return sanitizeHTML($content->__toString(), $url);
} else {
throw new Exception ();
}
}
-/* 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);
-
- if (curl_getinfo ($c, CURLINFO_HTTP_CODE) == 200) {
- $file = fopen ($dest, 'w');
- if ($file === false) {
- return $url;
- }
-
- fwrite ($file, $imgRaw);
- fclose ($file);
- } else {
- return $url;
- }
-
- curl_close ($c);
- }
-
- return $favicon_url;
-}
-
/**
* Add support of image lazy loading
* Move content from src attribute to data-original
@@ -214,8 +189,47 @@ function dowload_favicon ($website, $id) {
*/
function lazyimg($content) {
return preg_replace(
- '/<img([^<]+)src=([\'"])([^"\']*)([\'"])([^<]*)>/i',
- '<img$1src="' . Url::display('/data/grey.gif') . '" data-original="$3"$5>',
+ '/<img([^>]+?)src=[\'"]([^"\']+)[\'"]([^>]*)>/i',
+ '<img$1src="' . Minz_Url::display('/themes/icons/grey.gif') . '" data-original="$2"$3>',
$content
);
}
+
+function lazyIframe($content) {
+ return preg_replace(
+ '/<iframe([^>]+?)src=[\'"]([^"\']+)[\'"]([^>]*)>/i',
+ '<iframe$1src="about:blank" data-original="$2"$3>',
+ $content
+ );
+}
+
+function uTimeString() {
+ $t = @gettimeofday();
+ return $t['sec'] . str_pad($t['usec'], 6, '0');
+}
+
+function uSecString() {
+ $t = @gettimeofday();
+ return str_pad($t['usec'], 6, '0');
+}
+
+function invalidateHttpCache() {
+ touch(LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log');
+ Minz_Session::_param('touch', uTimeString());
+}
+
+function usernameFromPath($userPath) {
+ if (preg_match('%/([a-z0-9]{1,16})_user\.php$%', $userPath, $matches)) {
+ return $matches[1];
+ } else {
+ return '';
+ }
+}
+
+function listUsers() {
+ return array_map('usernameFromPath', glob(DATA_PATH . '/*_user.php'));
+}
+
+function httpAuthUser() {
+ return isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : '';
+}
diff --git a/lib/minz/Configuration.php b/lib/minz/Configuration.php
deleted file mode 100755
index b296ec378..000000000
--- a/lib/minz/Configuration.php
+++ /dev/null
@@ -1,250 +0,0 @@
-<?php
-/**
- * MINZ - Copyright 2011 Marien Fressinaud
- * Sous licence AGPL3 <http://www.gnu.org/licenses/>
-*/
-
-/**
- * La classe Configuration permet de gérer la configuration de l'application
- */
-class Configuration {
- const CONF_PATH_NAME = '/configuration/application.ini';
-
- /**
- * VERSION est la version actuelle de MINZ
- */
- const VERSION = '1.3.1.freshrss'; // version spéciale FreshRSS
-
- /**
- * valeurs possibles pour l'"environment"
- * SILENT rend l'application muette (pas de log)
- * PRODUCTION est recommandée pour une appli en production
- * (log les erreurs critiques)
- * DEVELOPMENT log toutes les erreurs
- */
- const SILENT = 0;
- const PRODUCTION = 1;
- const DEVELOPMENT = 2;
-
- /**
- * définition des variables de configuration
- * $sel_application une chaîne de caractères aléatoires (obligatoire)
- * $environment gère le niveau d'affichage pour log et erreurs
- * $use_url_rewriting indique si on utilise l'url_rewriting
- * $base_url le chemin de base pour accéder à l'application
- * $title le nom de l'application
- * $language la langue par défaut de l'application
- * $cacheEnabled permet de savoir si le cache doit être activé
- * $delayCache la limite de cache
- * $db paramètres pour la base de données (tableau)
- * - host le serveur de la base
- * - user nom d'utilisateur
- * - password mot de passe de l'utilisateur
- * - base le nom de la base de données
- */
- private static $sel_application = '';
- private static $environment = 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 $db = array (
- 'host' => false,
- 'user' => false,
- 'password' => false,
- 'base' => false
- );
-
- /*
- * Getteurs
- */
- public static function selApplication () {
- return self::$sel_application;
- }
- public static function environment () {
- return self::$environment;
- }
- public static function baseUrl () {
- return self::$base_url;
- }
- public static function useUrlRewriting () {
- return self::$use_url_rewriting;
- }
- public static function title () {
- return self::$title;
- }
- public static function language () {
- return self::$language;
- }
- public static function cacheEnabled () {
- return self::$cache_enabled;
- }
- public static function delayCache () {
- return self::$delay_cache;
- }
- public static function dataBase () {
- return self::$db;
- }
-
- /**
- * Initialise les variables de configuration
- * @exception FileNotExistException si le CONF_PATH_NAME n'existe pas
- * @exception BadConfigurationException si CONF_PATH_NAME mal formaté
- */
- public static function init () {
- try {
- self::parseFile ();
- self::setReporting ();
- } catch (FileNotExistException $e) {
- throw $e;
- } catch (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é
- */
- private static function parseFile () {
- if (!file_exists (APP_PATH . self::CONF_PATH_NAME)) {
- throw new FileNotExistException (
- APP_PATH . self::CONF_PATH_NAME,
- MinzException::ERROR
- );
- }
-
- $ini_array = parse_ini_file (
- APP_PATH . self::CONF_PATH_NAME,
- true
- );
-
- if (!$ini_array) {
- throw new PermissionDeniedException (
- APP_PATH . self::CONF_PATH_NAME,
- MinzException::ERROR
- );
- }
-
- // [general] est obligatoire
- if (!isset ($ini_array['general'])) {
- throw new BadConfigurationException (
- '[general]',
- MinzException::ERROR
- );
- }
- $general = $ini_array['general'];
-
-
- // sel_application est obligatoire
- if (!isset ($general['sel_application'])) {
- throw new BadConfigurationException (
- 'sel_application',
- MinzException::ERROR
- );
- }
- self::$sel_application = $general['sel_application'];
-
- if (isset ($general['environment'])) {
- switch ($general['environment']) {
- case 'silent':
- self::$environment = Configuration::SILENT;
- break;
- case 'development':
- self::$environment = Configuration::DEVELOPMENT;
- break;
- case 'production':
- self::$environment = Configuration::PRODUCTION;
- break;
- default:
- throw new BadConfigurationException (
- 'environment',
- MinzException::ERROR
- );
- }
-
- }
- if (isset ($general['base_url'])) {
- self::$base_url = $general['base_url'];
- }
- if (isset ($general['use_url_rewriting'])) {
- self::$use_url_rewriting = $general['use_url_rewriting'];
- }
-
- if (isset ($general['title'])) {
- self::$title = $general['title'];
- }
- if (isset ($general['language'])) {
- self::$language = $general['language'];
- }
- if (isset ($general['cache_enabled'])) {
- self::$cache_enabled = $general['cache_enabled'];
- if (CACHE_PATH === false && self::$cache_enabled) {
- throw new FileNotExistException (
- 'CACHE_PATH',
- MinzException::ERROR
- );
- }
- }
- if (isset ($general['delay_cache'])) {
- self::$delay_cache = $general['delay_cache'];
- }
-
- // Base de données
- $db = false;
- if (isset ($ini_array['db'])) {
- $db = $ini_array['db'];
- }
- if ($db) {
- if (!isset ($db['host'])) {
- throw new BadConfigurationException (
- 'host',
- MinzException::ERROR
- );
- }
- if (!isset ($db['user'])) {
- throw new BadConfigurationException (
- 'user',
- MinzException::ERROR
- );
- }
- if (!isset ($db['password'])) {
- throw new BadConfigurationException (
- 'password',
- MinzException::ERROR
- );
- }
- if (!isset ($db['base'])) {
- throw new BadConfigurationException (
- 'base',
- MinzException::ERROR
- );
- }
-
- self::$db['type'] = isset ($db['type']) ? $db['type'] : 'mysql';
- self::$db['host'] = $db['host'];
- self::$db['user'] = $db['user'];
- self::$db['password'] = $db['password'];
- self::$db['base'] = $db['base'];
- self::$db['prefix'] = isset ($db['prefix']) ? $db['prefix'] : '';
- }
- }
-
- private static function setReporting () {
- if (self::environment () == self::DEVELOPMENT) {
- error_reporting (E_ALL);
- ini_set ('display_errors','On');
- ini_set('log_errors', 'On');
- } elseif (self::environment () == self::PRODUCTION) {
- error_reporting(E_ALL);
- ini_set('display_errors','Off');
- ini_set('log_errors', 'On');
- } else {
- error_reporting(0);
- }
- }
-}
diff --git a/lib/minz/dao/Model_array.php b/lib/minz/dao/Model_array.php
deleted file mode 100755
index 0b9ccf071..000000000
--- a/lib/minz/dao/Model_array.php
+++ /dev/null
@@ -1,122 +0,0 @@
-<?php
-/**
- * MINZ - Copyright 2011 Marien Fressinaud
- * Sous licence AGPL3 <http://www.gnu.org/licenses/>
-*/
-
-/**
- * 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 {
- /**
- * $array Le tableau php contenu dans le fichier $nameFile
- */
- protected $array = array ();
-
- /**
- * Ouvre le fichier indiqué, charge le tableau dans $array et le $nameFile
- * @param $nameFile le nom du fichier à ouvrir contenant un tableau
- * Remarque : $array sera obligatoirement un tableau
- */
- public function __construct ($nameFile) {
- parent::__construct ($nameFile);
-
- if (!$this->getLock ('read')) {
- throw new PermissionDeniedException ($this->filename);
- } else {
- $this->array = include ($this->filename);
- $this->releaseLock ();
-
- if (!is_array ($this->array)) {
- $this->array = array ();
- }
-
- $this->array = $this->decodeArray ($this->array);
- }
- }
-
- /**
- * Écrit un tableau dans le fichier $nameFile
- * @param $array le tableau php à enregistrer
- **/
- public function writeFile ($array) {
- if (!$this->getLock ('write')) {
- throw new PermissionDeniedException ($this->namefile);
- } else {
- $this->erase ();
-
- $this->writeLine ('<?php');
- $this->writeLine ('return ', false);
- $this->writeArray ($array);
- $this->writeLine (';');
-
- $this->releaseLock ();
- }
- }
-
- private function writeArray ($array, $profondeur = 0) {
- $tab = '';
- for ($i = 0; $i < $profondeur; $i++) {
- $tab .= "\t";
- }
- $this->writeLine ('array (');
-
- foreach ($array as $key => $value) {
- if (is_int ($key)) {
- $this->writeLine ($tab . "\t" . $key . ' => ', false);
- } else {
- $this->writeLine ($tab . "\t" . '\'' . $key . '\'' . ' => ', false);
- }
-
- if (is_array ($value)) {
- $this->writeArray ($value, $profondeur + 1);
- $this->writeLine (',');
- } else {
- if (is_numeric ($value)) {
- $this->writeLine ($value . ',');
- } else {
- $this->writeLine ('\'' . addslashes ($value) . '\',');
- }
- }
- }
-
- $this->writeLine ($tab . ')', false);
- }
-
- private function decodeArray ($array) {
- $new_array = array ();
-
- foreach ($array as $key => $value) {
- if (is_array ($value)) {
- $new_array[$key] = $this->decodeArray ($value);
- } else {
- $new_array[$key] = stripslashes ($value);
- }
- }
-
- return $new_array;
- }
-
- private function getLock ($type) {
- if ($type == 'write') {
- $lock = LOCK_EX;
- } else {
- $lock = LOCK_SH;
- }
-
- $count = 1;
- while (!flock ($this->file, $lock) && $count <= 50) {
- $count++;
- }
-
- if ($count >= 50) {
- return false;
- } else {
- return true;
- }
- }
-
- private function releaseLock () {
- flock ($this->file, LOCK_UN);
- }
-}
diff --git a/lib/minz/dao/Model_txt.php b/lib/minz/dao/Model_txt.php
deleted file mode 100755
index aed653068..000000000
--- a/lib/minz/dao/Model_txt.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-/**
- * MINZ - Copyright 2011 Marien Fressinaud
- * Sous licence AGPL3 <http://www.gnu.org/licenses/>
-*/
-
-/**
- * La classe Model_txt représente le modèle interragissant avec les fichiers de type texte
- */
-class Model_txt {
- /**
- * $file représente le fichier à ouvrir
- */
- protected $file;
-
- /**
- * $filename est le nom du fichier
- */
- protected $filename;
-
- /**
- * Ouvre un fichier dans $file
- * @param $nameFile nom du fichier à ouvrir
- * @param $mode mode d'ouverture du fichier ('a+' par défaut)
- * @exception FileNotExistException si le fichier n'existe pas
- * > ou ne peux pas être ouvert
- */
- public function __construct ($nameFile, $mode = 'a+') {
- $this->filename = $nameFile;
- if (!file_exists($this->filename)) {
- throw new FileNotExistException (
- $this->filename,
- MinzException::WARNING
- );
- }
-
- $this->file = @fopen ($this->filename, $mode);
-
- if (!$this->file) {
- throw new PermissionDeniedException (
- $this->filename,
- MinzException::WARNING
- );
- }
- }
-
- /**
- * Lit une ligne de $file
- * @return une ligne du fichier
- */
- public function readLine () {
- return fgets ($this->file);
- }
-
- /**
- * Écrit une ligne dans $file
- * @param $line la ligne à écrire
- */
- public function writeLine ($line, $newLine = true) {
- $char = '';
- if ($newLine) {
- $char = "\n";
- }
-
- fwrite ($this->file, $line . $char);
- }
-
- /**
- * Efface le fichier $file
- * @return true en cas de succès, false sinon
- */
- public function erase () {
- return ftruncate ($this->file, 0);
- }
-
- /**
- * Ferme $file
- */
- public function __destruct () {
- if (isset ($this->file)) {
- fclose ($this->file);
- }
- }
-}
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);
- }
-}
diff --git a/lib/password_compat.php b/lib/password_compat.php
new file mode 100644
index 000000000..e8ec02885
--- /dev/null
+++ b/lib/password_compat.php
@@ -0,0 +1,279 @@
+<?php
+/**
+ * A Compatibility library with PHP 5.5's simplified password hashing API.
+ *
+ * @author Anthony Ferrara <ircmaxell@php.net>
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @copyright 2012 The Authors
+ */
+
+namespace {
+
+if (!defined('PASSWORD_DEFAULT')) {
+
+ define('PASSWORD_BCRYPT', 1);
+ define('PASSWORD_DEFAULT', PASSWORD_BCRYPT);
+
+ /**
+ * Hash the password using the specified algorithm
+ *
+ * @param string $password The password to hash
+ * @param int $algo The algorithm to use (Defined by PASSWORD_* constants)
+ * @param array $options The options for the algorithm to use
+ *
+ * @return string|false The hashed password, or false on error.
+ */
+ function password_hash($password, $algo, array $options = array()) {
+ if (!function_exists('crypt')) {
+ trigger_error("Crypt must be loaded for password_hash to function", E_USER_WARNING);
+ return null;
+ }
+ if (!is_string($password)) {
+ trigger_error("password_hash(): Password must be a string", E_USER_WARNING);
+ return null;
+ }
+ if (!is_int($algo)) {
+ trigger_error("password_hash() expects parameter 2 to be long, " . gettype($algo) . " given", E_USER_WARNING);
+ return null;
+ }
+ $resultLength = 0;
+ switch ($algo) {
+ case PASSWORD_BCRYPT:
+ // Note that this is a C constant, but not exposed to PHP, so we don't define it here.
+ $cost = 10;
+ if (isset($options['cost'])) {
+ $cost = $options['cost'];
+ if ($cost < 4 || $cost > 31) {
+ trigger_error(sprintf("password_hash(): Invalid bcrypt cost parameter specified: %d", $cost), E_USER_WARNING);
+ return null;
+ }
+ }
+ // The length of salt to generate
+ $raw_salt_len = 16;
+ // The length required in the final serialization
+ $required_salt_len = 22;
+ $hash_format = sprintf("$2y$%02d$", $cost);
+ // The expected length of the final crypt() output
+ $resultLength = 60;
+ break;
+ default:
+ trigger_error(sprintf("password_hash(): Unknown password hashing algorithm: %s", $algo), E_USER_WARNING);
+ return null;
+ }
+ $salt_requires_encoding = false;
+ if (isset($options['salt'])) {
+ switch (gettype($options['salt'])) {
+ case 'NULL':
+ case 'boolean':
+ case 'integer':
+ case 'double':
+ case 'string':
+ $salt = (string) $options['salt'];
+ break;
+ case 'object':
+ if (method_exists($options['salt'], '__tostring')) {
+ $salt = (string) $options['salt'];
+ break;
+ }
+ case 'array':
+ case 'resource':
+ default:
+ trigger_error('password_hash(): Non-string salt parameter supplied', E_USER_WARNING);
+ return null;
+ }
+ if (PasswordCompat\binary\_strlen($salt) < $required_salt_len) {
+ trigger_error(sprintf("password_hash(): Provided salt is too short: %d expecting %d", PasswordCompat\binary\_strlen($salt), $required_salt_len), E_USER_WARNING);
+ return null;
+ } elseif (0 == preg_match('#^[a-zA-Z0-9./]+$#D', $salt)) {
+ $salt_requires_encoding = true;
+ }
+ } else {
+ $buffer = '';
+ $buffer_valid = false;
+ if (function_exists('mcrypt_create_iv') && !defined('PHALANGER')) {
+ $buffer = mcrypt_create_iv($raw_salt_len, MCRYPT_DEV_URANDOM);
+ if ($buffer) {
+ $buffer_valid = true;
+ }
+ }
+ if (!$buffer_valid && function_exists('openssl_random_pseudo_bytes')) {
+ $buffer = openssl_random_pseudo_bytes($raw_salt_len);
+ if ($buffer) {
+ $buffer_valid = true;
+ }
+ }
+ if (!$buffer_valid && @is_readable('/dev/urandom')) {
+ $f = fopen('/dev/urandom', 'r');
+ $read = PasswordCompat\binary\_strlen($buffer);
+ while ($read < $raw_salt_len) {
+ $buffer .= fread($f, $raw_salt_len - $read);
+ $read = PasswordCompat\binary\_strlen($buffer);
+ }
+ fclose($f);
+ if ($read >= $raw_salt_len) {
+ $buffer_valid = true;
+ }
+ }
+ if (!$buffer_valid || PasswordCompat\binary\_strlen($buffer) < $raw_salt_len) {
+ $bl = PasswordCompat\binary\_strlen($buffer);
+ for ($i = 0; $i < $raw_salt_len; $i++) {
+ if ($i < $bl) {
+ $buffer[$i] = $buffer[$i] ^ chr(mt_rand(0, 255));
+ } else {
+ $buffer .= chr(mt_rand(0, 255));
+ }
+ }
+ }
+ $salt = $buffer;
+ $salt_requires_encoding = true;
+ }
+ if ($salt_requires_encoding) {
+ // encode string with the Base64 variant used by crypt
+ $base64_digits =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+ $bcrypt64_digits =
+ './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+
+ $base64_string = base64_encode($salt);
+ $salt = strtr(rtrim($base64_string, '='), $base64_digits, $bcrypt64_digits);
+ }
+ $salt = PasswordCompat\binary\_substr($salt, 0, $required_salt_len);
+
+ $hash = $hash_format . $salt;
+
+ $ret = crypt($password, $hash);
+
+ if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != $resultLength) {
+ return false;
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Get information about the password hash. Returns an array of the information
+ * that was used to generate the password hash.
+ *
+ * array(
+ * 'algo' => 1,
+ * 'algoName' => 'bcrypt',
+ * 'options' => array(
+ * 'cost' => 10,
+ * ),
+ * )
+ *
+ * @param string $hash The password hash to extract info from
+ *
+ * @return array The array of information about the hash.
+ */
+ function password_get_info($hash) {
+ $return = array(
+ 'algo' => 0,
+ 'algoName' => 'unknown',
+ 'options' => array(),
+ );
+ if (PasswordCompat\binary\_substr($hash, 0, 4) == '$2y$' && PasswordCompat\binary\_strlen($hash) == 60) {
+ $return['algo'] = PASSWORD_BCRYPT;
+ $return['algoName'] = 'bcrypt';
+ list($cost) = sscanf($hash, "$2y$%d$");
+ $return['options']['cost'] = $cost;
+ }
+ return $return;
+ }
+
+ /**
+ * Determine if the password hash needs to be rehashed according to the options provided
+ *
+ * If the answer is true, after validating the password using password_verify, rehash it.
+ *
+ * @param string $hash The hash to test
+ * @param int $algo The algorithm used for new password hashes
+ * @param array $options The options array passed to password_hash
+ *
+ * @return boolean True if the password needs to be rehashed.
+ */
+ function password_needs_rehash($hash, $algo, array $options = array()) {
+ $info = password_get_info($hash);
+ if ($info['algo'] != $algo) {
+ return true;
+ }
+ switch ($algo) {
+ case PASSWORD_BCRYPT:
+ $cost = isset($options['cost']) ? $options['cost'] : 10;
+ if ($cost != $info['options']['cost']) {
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ /**
+ * Verify a password against a hash using a timing attack resistant approach
+ *
+ * @param string $password The password to verify
+ * @param string $hash The hash to verify against
+ *
+ * @return boolean If the password matches the hash
+ */
+ function password_verify($password, $hash) {
+ if (!function_exists('crypt')) {
+ trigger_error("Crypt must be loaded for password_verify to function", E_USER_WARNING);
+ return false;
+ }
+ $ret = crypt($password, $hash);
+ if (!is_string($ret) || PasswordCompat\binary\_strlen($ret) != PasswordCompat\binary\_strlen($hash) || PasswordCompat\binary\_strlen($ret) <= 13) {
+ return false;
+ }
+
+ $status = 0;
+ for ($i = 0; $i < PasswordCompat\binary\_strlen($ret); $i++) {
+ $status |= (ord($ret[$i]) ^ ord($hash[$i]));
+ }
+
+ return $status === 0;
+ }
+}
+
+}
+
+namespace PasswordCompat\binary {
+ /**
+ * Count the number of bytes in a string
+ *
+ * We cannot simply use strlen() for this, because it might be overwritten by the mbstring extension.
+ * In this case, strlen() will count the number of *characters* based on the internal encoding. A
+ * sequence of bytes might be regarded as a single multibyte character.
+ *
+ * @param string $binary_string The input string
+ *
+ * @internal
+ * @return int The number of bytes
+ */
+ function _strlen($binary_string) {
+ if (function_exists('mb_strlen')) {
+ return mb_strlen($binary_string, '8bit');
+ }
+ return strlen($binary_string);
+ }
+
+ /**
+ * Get a substring based on byte limits
+ *
+ * @see _strlen()
+ *
+ * @param string $binary_string The input string
+ * @param int $start
+ * @param int $length
+ *
+ * @internal
+ * @return string The substring
+ */
+ function _substr($binary_string, $start, $length) {
+ if (function_exists('mb_substr')) {
+ return mb_substr($binary_string, $start, $length, '8bit');
+ }
+ return substr($binary_string, $start, $length);
+ }
+
+}