aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGravatar Marien Fressinaud <dev@marienfressinaud.fr> 2014-10-09 15:53:10 +0200
committerGravatar Marien Fressinaud <dev@marienfressinaud.fr> 2014-10-09 15:53:10 +0200
commitf97d4b3b6cca4a55636bbd50158f3c57666b0f08 (patch)
tree3ca9dd42155228292f0842d65b9b6d90e9140639 /lib
parente51ceb6812e3736aa9b9ce1f2d5181f5b4b6aaa3 (diff)
parent444b1552364b39761c3278c7da5152fd3998f216 (diff)
Merge branch 'master' into hotfixes
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)10
-rw-r--r--lib/Minz/ActionException.php9
-rw-r--r--lib/Minz/BadConfigurationException.php9
-rw-r--r--lib/Minz/Configuration.php375
-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.php117
-rw-r--r--[-rwxr-xr-x]lib/Minz/Error.php (renamed from lib/minz/Error.php)64
-rw-r--r--lib/Minz/Exception.php16
-rw-r--r--lib/Minz/FileNotExistException.php8
-rw-r--r--lib/Minz/FrontController.php117
-rw-r--r--lib/Minz/Helper.php33
-rw-r--r--[-rwxr-xr-x]lib/Minz/Log.php (renamed from lib/minz/Log.php)82
-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--lib/Minz/ModelPdo.php124
-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.php227
-rw-r--r--lib/Minz/Session.php93
-rw-r--r--lib/Minz/Translate.php (renamed from lib/minz/Translate.php)36
-rw-r--r--[-rwxr-xr-x]lib/Minz/Url.php (renamed from lib/minz/Url.php)65
-rw-r--r--[-rwxr-xr-x]lib/Minz/View.php (renamed from lib/minz/View.php)87
-rw-r--r--lib/SimplePie/SimplePie.php141
-rw-r--r--lib/SimplePie/SimplePie/Author.php2
-rw-r--r--lib/SimplePie/SimplePie/Cache.php2
-rw-r--r--lib/SimplePie/SimplePie/Cache/Base.php2
-rw-r--r--lib/SimplePie/SimplePie/Cache/DB.php2
-rw-r--r--lib/SimplePie/SimplePie/Cache/File.php2
-rw-r--r--lib/SimplePie/SimplePie/Cache/Memcache.php12
-rw-r--r--lib/SimplePie/SimplePie/Cache/MySQL.php7
-rw-r--r--lib/SimplePie/SimplePie/Caption.php2
-rw-r--r--lib/SimplePie/SimplePie/Category.php2
-rw-r--r--lib/SimplePie/SimplePie/Content/Type/Sniffer.php2
-rw-r--r--lib/SimplePie/SimplePie/Copyright.php2
-rw-r--r--lib/SimplePie/SimplePie/Core.php2
-rw-r--r--lib/SimplePie/SimplePie/Credit.php2
-rw-r--r--lib/SimplePie/SimplePie/Decode/HTML/Entities.php2
-rw-r--r--lib/SimplePie/SimplePie/Enclosure.php4
-rw-r--r--lib/SimplePie/SimplePie/File.php19
-rw-r--r--lib/SimplePie/SimplePie/HTTP/Parser.php2
-rw-r--r--lib/SimplePie/SimplePie/IRI.php2
-rw-r--r--lib/SimplePie/SimplePie/Item.php6
-rw-r--r--lib/SimplePie/SimplePie/Locator.php4
-rw-r--r--lib/SimplePie/SimplePie/Misc.php57
-rw-r--r--lib/SimplePie/SimplePie/Net/IPv6.php2
-rw-r--r--lib/SimplePie/SimplePie/Parse/Date.php2
-rw-r--r--lib/SimplePie/SimplePie/Parser.php115
-rw-r--r--lib/SimplePie/SimplePie/Rating.php2
-rwxr-xr-xlib/SimplePie/SimplePie/Registry.php2
-rw-r--r--lib/SimplePie/SimplePie/Restriction.php2
-rw-r--r--lib/SimplePie/SimplePie/Sanitize.php61
-rw-r--r--lib/SimplePie/SimplePie/Source.php2
-rw-r--r--lib/SimplePie/SimplePie/XML/Declaration/Parser.php2
-rw-r--r--lib/SimplePie/SimplePie/gzdecode.php2
-rw-r--r--lib/SimplePie_autoloader.php86
-rw-r--r--lib/http-conditional.php212
-rw-r--r--lib/lib_date.php131
-rw-r--r--lib/lib_opml.php231
-rw-r--r--lib/lib_phpQuery.php42
-rw-r--r--lib/lib_rss.php360
-rw-r--r--lib/lib_text.php96
-rw-r--r--lib/minz/Cache.php116
-rwxr-xr-xlib/minz/Configuration.php242
-rw-r--r--lib/minz/Dispatcher.php152
-rwxr-xr-xlib/minz/FrontController.php123
-rwxr-xr-xlib/minz/Helper.php22
-rw-r--r--lib/minz/Request.php196
-rw-r--r--lib/minz/Response.php60
-rwxr-xr-xlib/minz/Router.php209
-rwxr-xr-xlib/minz/Session.php78
-rwxr-xr-xlib/minz/dao/Model_array.php122
-rwxr-xr-xlib/minz/dao/Model_pdo.php58
-rwxr-xr-xlib/minz/dao/Model_txt.php77
-rw-r--r--lib/minz/exceptions/MinzException.php94
-rw-r--r--lib/password_compat.php279
80 files changed, 3777 insertions, 2215 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..b47c54554 100755..100644
--- a/lib/minz/ActionController.php
+++ b/lib/Minz/ActionController.php
@@ -7,18 +7,14 @@
/**
* La classe ActionController représente le contrôleur de l'application
*/
-class ActionController {
- protected $router;
+class Minz_ActionController {
protected $view;
/**
* Constructeur
- * @param $controller nom du controller
- * @param $action nom de l'action à lancer
*/
- public function __construct ($router) {
- $this->router = $router;
- $this->view = new View ();
+ public function __construct () {
+ $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/Configuration.php b/lib/Minz/Configuration.php
new file mode 100644
index 000000000..4e9da58b4
--- /dev/null
+++ b/lib/Minz/Configuration.php
@@ -0,0 +1,375 @@
+<?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
+ * $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
+ * $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 $title = '';
+ private static $language = 'en';
+ private static $default_user = '';
+ private static $allow_anonymous = false;
+ private static $allow_anonymous_refresh = false;
+ private static $auth_type = 'none';
+ private static $api_enabled = false;
+ private static $unsafe_autologin_enabled = false;
+
+ 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 title () {
+ return self::$title;
+ }
+ public static function language () {
+ return self::$language;
+ }
+ 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 allowAnonymousRefresh() {
+ return self::$allow_anonymous_refresh;
+ }
+ 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 apiEnabled() {
+ return self::$api_enabled;
+ }
+ public static function unsafeAutologinEnabled() {
+ return self::$unsafe_autologin_enabled;
+ }
+
+ public static function _allowAnonymous($allow = false) {
+ self::$allow_anonymous = ((bool)$allow) && self::canLogIn();
+ }
+ public static function _allowAnonymousRefresh($allow = false) {
+ self::$allow_anonymous_refresh = ((bool)$allow) && self::allowAnonymous();
+ }
+ 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);
+ }
+
+ public static function _enableApi($value = false) {
+ self::$api_enabled = (bool)$value;
+ }
+ public static function _enableAutologin($value = false) {
+ self::$unsafe_autologin_enabled = (bool)$value;
+ }
+
+ /**
+ * 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),
+ 'salt' => self::$salt,
+ 'base_url' => self::$base_url,
+ 'title' => self::$title,
+ 'default_user' => self::$default_user,
+ 'allow_anonymous' => self::$allow_anonymous,
+ 'allow_anonymous_refresh' => self::$allow_anonymous_refresh,
+ 'auth_type' => self::$auth_type,
+ 'api_enabled' => self::$api_enabled,
+ 'unsafe_autologin_enabled' => self::$unsafe_autologin_enabled,
+ ),
+ '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['title'])) {
+ self::$title = $general['title'];
+ }
+ if (isset ($general['language'])) {
+ self::$language = $general['language'];
+ }
+ 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')
+ );
+ }
+ if (isset ($general['allow_anonymous_refresh'])) {
+ self::$allow_anonymous_refresh = (
+ ((bool)($general['allow_anonymous_refresh'])) &&
+ ($general['allow_anonymous_refresh'] !== 'no')
+ );
+ }
+ if (isset ($general['api_enabled'])) {
+ self::$api_enabled = (
+ ((bool)($general['api_enabled'])) &&
+ ($general['api_enabled'] !== 'no')
+ );
+ }
+ if (isset ($general['unsafe_autologin_enabled'])) {
+ self::$unsafe_autologin_enabled = (
+ ((bool)($general['unsafe_autologin_enabled'])) &&
+ ($general['unsafe_autologin_enabled'] !== 'no')
+ );
+ }
+
+ // Base de données
+ if (isset ($ini_array['db'])) {
+ $db = $ini_array['db'];
+ if (empty($db['type'])) {
+ throw new Minz_BadConfigurationException (
+ 'type',
+ Minz_Exception::ERROR
+ );
+ }
+ switch ($db['type']) {
+ case 'mysql':
+ 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
+ );
+ }
+ 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'];
+ }
+ break;
+ case 'sqlite':
+ self::$db['host'] = '';
+ self::$db['user'] = '';
+ self::$db['password'] = '';
+ self::$db['base'] = '';
+ self::$db['prefix'] = '';
+ break;
+ default:
+ throw new Minz_BadConfigurationException (
+ 'type',
+ Minz_Exception::ERROR
+ );
+ break;
+ }
+ self::$db['type'] = $db['type'];
+ }
+ }
+
+ 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
new file mode 100644
index 000000000..f62a92911
--- /dev/null
+++ b/lib/Minz/Dispatcher.php
@@ -0,0 +1,117 @@
+<?php
+/**
+ * MINZ - Copyright 2011 Marien Fressinaud
+ * Sous licence AGPL3 <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * Le Dispatcher s'occupe d'initialiser le Controller et d'executer l'action
+ * déterminée dans la Request
+ * C'est un singleton
+ */
+class Minz_Dispatcher {
+ const CONTROLLERS_PATH_NAME = '/Controllers';
+
+ /* singleton */
+ private static $instance = null;
+ private static $needsReset;
+
+ private $controller;
+
+ /**
+ * Récupère l'instance du Dispatcher
+ */
+ public static function getInstance () {
+ if (self::$instance === null) {
+ self::$instance = new Minz_Dispatcher ();
+ }
+ return self::$instance;
+ }
+
+ /**
+ * Lance le controller indiqué dans Request
+ * Remplit le body de Response à partir de la Vue
+ * @exception Minz_Exception
+ */
+ public function run () {
+ do {
+ self::$needsReset = false;
+
+ try {
+ $this->createController ('FreshRSS_' . Minz_Request::controllerName () . '_Controller');
+ $this->controller->init ();
+ $this->controller->firstAction ();
+ if (!self::$needsReset) {
+ $this->launchAction (
+ Minz_Request::actionName ()
+ . 'Action'
+ );
+ }
+ $this->controller->lastAction ();
+
+ if (!self::$needsReset) {
+ $this->controller->view ()->build ();
+ }
+ } catch (Minz_Exception $e) {
+ throw $e;
+ }
+ } while (self::$needsReset);
+ }
+
+ /**
+ * Informe le contrôleur qu'il doit recommancer car la requête a été modifiée
+ */
+ public static function reset() {
+ self::$needsReset = true;
+ }
+
+ /**
+ * Instancie le Controller
+ * @param $controller_name le nom du controller à instancier
+ * @exception ControllerNotExistException le controller n'existe pas
+ * @exception ControllerNotActionControllerException controller n'est
+ * > pas une instance de ActionController
+ */
+ private function createController ($controller_name) {
+ $filename = APP_PATH . self::CONTROLLERS_PATH_NAME . '/'
+ . $controller_name . '.php';
+
+ if (!class_exists ($controller_name)) {
+ throw new Minz_ControllerNotExistException (
+ $controller_name,
+ Minz_Exception::ERROR
+ );
+ }
+ $this->controller = new $controller_name ();
+
+ if (! ($this->controller instanceof Minz_ActionController)) {
+ throw new Minz_ControllerNotActionControllerException (
+ $controller_name,
+ Minz_Exception::ERROR
+ );
+ }
+ }
+
+ /**
+ * 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
+ */
+ private function launchAction ($action_name) {
+ if (!is_callable (array (
+ $this->controller,
+ $action_name
+ ))) {
+ throw new Minz_ActionException (
+ get_class ($this->controller),
+ $action_name,
+ Minz_Exception::ERROR
+ );
+ }
+ call_user_func (array (
+ $this->controller,
+ $action_name
+ ));
+ }
+}
diff --git a/lib/minz/Error.php b/lib/Minz/Error.php
index 0e8c2f60b..c8222a430 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,43 +21,59 @@ 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';
+
+ switch ($code) {
+ case 200 :
+ header('HTTP/1.1 200 OK');
+ break;
+ case 403 :
+ header('HTTP/1.1 403 Forbidden');
+ break;
+ case 404 :
+ header('HTTP/1.1 404 Not Found');
+ break;
+ case 500 :
+ header('HTTP/1.1 500 Internal Server Error');
+ break;
+ case 503 :
+ header('HTTP/1.1 503 Service Unavailable');
+ break;
+ default :
+ header('HTTP/1.1 500 Internal Server Error');
+ }
+
if (file_exists ($error_filename)) {
$params = array (
'code' => $code,
'logs' => $logs
);
-
- 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";
-
+ echo '<h1>An error occured</h1>' . "\n";
+
if (!empty ($logs)) {
- $text .= '<ul>'."\n";
+ echo '<ul>' . "\n";
foreach ($logs as $log) {
- $text .= '<li>' . $log . '</li>'."\n";
+ echo '<li>' . $log . '</li>' . "\n";
}
- $text .= '</ul>'."\n";
+ echo '</ul>' . "\n";
}
-
- Response::setHeader ($code);
- Response::setBody ($text);
- Response::send ();
+
exit ();
}
}
-
+
/**
* Permet de retourner les logs de façon à n'avoir que
* ceux que l'on veut réellement
@@ -66,12 +82,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 +97,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
new file mode 100644
index 000000000..f13882801
--- /dev/null
+++ b/lib/Minz/FrontController.php
@@ -0,0 +1,117 @@
+<?php
+# ***** 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 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 Minz_FrontController {
+ protected $dispatcher;
+
+ /**
+ * Constructeur
+ * Initialise le dispatcher, met à jour la Request
+ */
+ public function __construct () {
+ if (LOG_PATH === false) {
+ $this->killApp ('Path not found: LOG_PATH');
+ }
+
+ try {
+ Minz_Configuration::init ();
+
+ Minz_Request::init ();
+
+ $url = $this->buildUrl();
+ $url['params'] = array_merge (
+ $url['params'],
+ Minz_Request::fetchPOST ()
+ );
+ Minz_Request::forward ($url);
+ } catch (Minz_Exception $e) {
+ Minz_Log::record ($e->getMessage (), Minz_Log::ERROR);
+ $this->killApp ($e->getMessage ());
+ }
+
+ $this->dispatcher = Minz_Dispatcher::getInstance();
+ }
+
+ /**
+ * Retourne un tableau représentant l'url passée par la barre d'adresses
+ * @return tableau représentant l'url
+ */
+ private function buildUrl() {
+ $url = array ();
+
+ $url['c'] = Minz_Request::fetchGET (
+ 'c',
+ Minz_Request::defaultControllerName ()
+ );
+ $url['a'] = Minz_Request::fetchGET (
+ 'a',
+ Minz_Request::defaultActionName ()
+ );
+ $url['params'] = Minz_Request::fetchGET ();
+
+ // post-traitement
+ unset ($url['params']['c']);
+ unset ($url['params']['a']);
+
+ return $url;
+ }
+
+ /**
+ * Démarre l'application (lance le dispatcher et renvoie la réponse)
+ */
+ public function run () {
+ try {
+ $this->dispatcher->run();
+ } catch (Minz_Exception $e) {
+ try {
+ Minz_Log::record ($e->getMessage (), Minz_Log::ERROR);
+ } catch (Minz_PermissionDeniedException $e) {
+ $this->killApp ($e->getMessage ());
+ }
+
+ 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
+ );
+ } else {
+ $this->killApp ();
+ }
+ }
+ }
+
+ /**
+ * Permet d'arrêter le programme en urgence
+ */
+ private function killApp ($txt = '') {
+ if ($txt == '') {
+ $txt = 'See logs files';
+ }
+ exit ('### Application problem ###<br />'."\n".$txt);
+ }
+}
diff --git a/lib/Minz/Helper.php b/lib/Minz/Helper.php
new file mode 100644
index 000000000..f4a547c4e
--- /dev/null
+++ b/lib/Minz/Helper.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * MINZ - Copyright 2011 Marien Fressinaud
+ * Sous licence AGPL3 <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * La classe Helper représente une aide pour des tâches récurrentes
+ */
+class Minz_Helper {
+ /**
+ * Annule les effets des magic_quotes pour une variable donnée
+ * @param $var variable à traiter (tableau ou simple variable)
+ */
+ public static function stripslashes_r($var) {
+ if (is_array($var)){
+ return array_map(array('Minz_Helper', 'stripslashes_r'), $var);
+ } else {
+ return stripslashes($var);
+ }
+ }
+
+ /**
+ * Wrapper for htmlspecialchars.
+ * Force UTf-8 value and can be used on array too.
+ */
+ public static function htmlspecialchars_utf8($var) {
+ if (is_array($var)) {
+ return array_map(array('Minz_Helper', 'htmlspecialchars_utf8'), $var);
+ }
+ return htmlspecialchars($var, ENT_COMPAT, 'UTF-8');
+ }
+}
diff --git a/lib/minz/Log.php b/lib/Minz/Log.php
index c6f23d900..d3eaec2ae 100755..100644
--- a/lib/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,30 +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 {
- Error::error (
- 500,
- array ('error' => array (
- 'Permission is denied for `'
- . $file_name . '`')
- )
- );
+
+ $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);
}
}
}
@@ -86,7 +77,24 @@ 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);
+ }
+
+ /**
+ * Some helpers to Minz_Log::record() method
+ * Parameters are the same of those of the record() method.
+ */
+ public static function debug($msg, $file_name = null) {
+ self::record($msg, Minz_Log::DEBUG, $file_name);
+ }
+ public static function notice($msg, $file_name = null) {
+ self::record($msg, Minz_Log::NOTICE, $file_name);
+ }
+ public static function warning($msg, $file_name = null) {
+ self::record($msg, Minz_Log::WARNING, $file_name);
+ }
+ public static function error($msg, $file_name = null) {
+ self::record($msg, Minz_Log::ERROR, $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/ModelPdo.php b/lib/Minz/ModelPdo.php
new file mode 100644
index 000000000..b4bfca746
--- /dev/null
+++ b/lib/Minz/ModelPdo.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ * MINZ - Copyright 2011 Marien Fressinaud
+ * Sous licence AGPL3 <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * 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 Minz_ModelPdo {
+
+ /**
+ * Partage la connexion à la base de données entre toutes les instances.
+ */
+ public static $useSharedBd = true;
+ private static $sharedBd = null;
+ private static $sharedPrefix;
+ protected static $sharedDbType;
+
+ /**
+ * $bd variable représentant la base de données
+ */
+ protected $bd;
+
+ protected $prefix;
+
+ public function dbType() {
+ return self::$sharedDbType;
+ }
+
+ /**
+ * Créé la connexion à la base de données à l'aide des variables
+ * HOST, BASE, USER et PASS définies dans le fichier de configuration
+ */
+ public function __construct($currentUser = null) {
+ if (self::$useSharedBd && self::$sharedBd != null && $currentUser === null) {
+ $this->bd = self::$sharedBd;
+ $this->prefix = self::$sharedPrefix;
+ return;
+ }
+
+ $db = Minz_Configuration::dataBase();
+
+ if ($currentUser === null) {
+ $currentUser = Minz_Session::param('currentUser', '_');
+ }
+
+ try {
+ $type = $db['type'];
+ if ($type === 'mysql') {
+ $string = 'mysql:host=' . $db['host']
+ . ';dbname=' . $db['base']
+ . ';charset=utf8';
+ $driver_options = array(
+ PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
+ );
+ $this->prefix = $db['prefix'] . $currentUser . '_';
+ } elseif ($type === 'sqlite') {
+ $string = 'sqlite:' . DATA_PATH . '/' . $currentUser . '.sqlite';
+ $driver_options = array(
+ //PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
+ );
+ $this->prefix = '';
+ } else {
+ throw new Minz_PDOConnectionException(
+ 'Invalid database type!',
+ $db['user'], Minz_Exception::ERROR
+ );
+ }
+ self::$sharedDbType = $type;
+ self::$sharedPrefix = $this->prefix;
+
+ $this->bd = new MinzPDO(
+ $string,
+ $db['user'],
+ $db['password'],
+ $driver_options
+ );
+ if ($type === 'sqlite') {
+ $this->bd->exec('PRAGMA foreign_keys = ON;');
+ }
+ self::$sharedBd = $this->bd;
+ } catch (Exception $e) {
+ throw new Minz_PDOConnectionException(
+ $string,
+ $db['user'], Minz_Exception::ERROR
+ );
+ }
+ }
+
+ public function beginTransaction() {
+ $this->bd->beginTransaction();
+ }
+ public function commit() {
+ $this->bd->commit();
+ }
+ public function rollBack() {
+ $this->bd->rollBack();
+ }
+
+ public static function clean() {
+ self::$sharedBd = null;
+ self::$sharedPrefix = '';
+ }
+}
+
+class MinzPDO extends PDO {
+ private static function check($statement) {
+ if (preg_match('/^(?:UPDATE|INSERT|DELETE)/i', $statement)) {
+ invalidateHttpCache();
+ }
+ }
+
+ public function prepare($statement, $driver_options = array()) {
+ MinzPDO::check($statement);
+ return parent::prepare($statement, $driver_options);
+ }
+
+ public function exec($statement) {
+ MinzPDO::check($statement);
+ return parent::exec($statement);
+ }
+}
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
new file mode 100644
index 000000000..f7a24c026
--- /dev/null
+++ b/lib/Minz/Request.php
@@ -0,0 +1,227 @@
+<?php
+/**
+ * MINZ - Copyright 2011 Marien Fressinaud
+ * Sous licence AGPL3 <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * Request représente la requête http
+ */
+class Minz_Request {
+ private static $controller_name = '';
+ private static $action_name = '';
+ private static $params = array();
+
+ private static $default_controller_name = 'index';
+ private static $default_action_name = 'index';
+
+ /**
+ * Getteurs
+ */
+ public static function controllerName() {
+ return self::$controller_name;
+ }
+ public static function actionName() {
+ return self::$action_name;
+ }
+ public static function params() {
+ return self::$params;
+ }
+ 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;
+ } else {
+ return Minz_Helper::htmlspecialchars_utf8($p);
+ }
+ } else {
+ return $default;
+ }
+ }
+ public static function defaultControllerName() {
+ return self::$default_controller_name;
+ }
+ public static function defaultActionName() {
+ return self::$default_action_name;
+ }
+
+ /**
+ * Setteurs
+ */
+ public static function _controllerName($controller_name) {
+ self::$controller_name = $controller_name;
+ }
+ public static function _actionName($action_name) {
+ self::$action_name = $action_name;
+ }
+ public static function _params($params) {
+ if (!is_array($params)) {
+ $params = array($params);
+ }
+
+ self::$params = $params;
+ }
+ public static function _param($key, $value = false) {
+ if ($value === false) {
+ unset(self::$params[$key]);
+ } else {
+ self::$params[$key] = $value;
+ }
+ }
+
+ /**
+ * Initialise la Request
+ */
+ public static function init() {
+ self::magicQuotesOff();
+ }
+
+ /**
+ * Retourn le nom de domaine du site
+ */
+ public static function getDomainName() {
+ return $_SERVER['HTTP_HOST'];
+ }
+
+ /**
+ * Détermine la base de l'url
+ * @return la base de l'url
+ */
+ public static function getBaseUrl() {
+ $defaultBaseUrl = Minz_Configuration::baseUrl();
+ if (!empty($defaultBaseUrl)) {
+ return $defaultBaseUrl;
+ } elseif (isset($_SERVER['REQUEST_URI'])) {
+ return dirname($_SERVER['REQUEST_URI']) . '/';
+ } else {
+ return '/';
+ }
+ }
+
+ /**
+ * Récupère l'URI de la requête
+ * @return l'URI
+ */
+ public static function getURI() {
+ if (isset($_SERVER['REQUEST_URI'])) {
+ $base_url = self::getBaseUrl();
+ $uri = $_SERVER['REQUEST_URI'];
+
+ $len_base_url = strlen($base_url);
+ $real_uri = substr($uri, $len_base_url);
+ } else {
+ $real_uri = '';
+ }
+
+ return $real_uri;
+ }
+
+ /**
+ * Relance une requête
+ * @param $url l'url vers laquelle est relancée la requête
+ * @param $redirect si vrai, force la redirection http
+ * > sinon, le dispatcher recharge en interne
+ */
+ public static function forward($url = array(), $redirect = false) {
+ if (!is_array($url)) {
+ header('Location: ' . $url);
+ exit();
+ }
+
+ $url = Minz_Url::checkUrl($url);
+
+ if ($redirect) {
+ header('Location: ' . Minz_Url::display($url, 'php'));
+ exit();
+ } else {
+ self::_controllerName($url['c']);
+ self::_actionName($url['a']);
+ self::_params(array_merge(
+ self::$params,
+ $url['params']
+ ));
+ Minz_Dispatcher::reset();
+ }
+ }
+
+
+ /**
+ * Wrappers good notifications + redirection
+ * @param $msg notification content
+ * @param $url url array to where we should be forwarded
+ */
+ public static function good($msg, $url = array()) {
+ Minz_Session::_param('notification', array(
+ 'type' => 'good',
+ 'content' => $msg
+ ));
+
+ Minz_Request::forward($url, true);
+ }
+
+ public static function bad($msg, $url = array()) {
+ Minz_Session::_param('notification', array(
+ 'type' => 'bad',
+ 'content' => $msg
+ ));
+
+ Minz_Request::forward($url, true);
+ }
+
+
+ /**
+ * Permet de récupérer une variable de type $_GET
+ * @param $param nom de la variable
+ * @param $default valeur par défaut à attribuer à la variable
+ * @return $_GET[$param]
+ * $_GET si $param = false
+ * $default si $_GET[$param] n'existe pas
+ */
+ public static function fetchGET($param = false, $default = false) {
+ if ($param === false) {
+ return $_GET;
+ } elseif (isset($_GET[$param])) {
+ return $_GET[$param];
+ } else {
+ return $default;
+ }
+ }
+
+ /**
+ * Permet de récupérer une variable de type $_POST
+ * @param $param nom de la variable
+ * @param $default valeur par défaut à attribuer à la variable
+ * @return $_POST[$param]
+ * $_POST si $param = false
+ * $default si $_POST[$param] n'existe pas
+ */
+ public static function fetchPOST($param = false, $default = false) {
+ if ($param === false) {
+ return $_POST;
+ } elseif (isset($_POST[$param])) {
+ return $_POST[$param];
+ } else {
+ return $default;
+ }
+ }
+
+ /**
+ * Méthode désactivant les magic_quotes pour les variables
+ * $_GET
+ * $_POST
+ * $_COOKIE
+ */
+ private static function magicQuotesOff() {
+ if (get_magic_quotes_gpc()) {
+ $_GET = Minz_Helper::stripslashes_r($_GET);
+ $_POST = Minz_Helper::stripslashes_r($_POST);
+ $_COOKIE = Minz_Helper::stripslashes_r($_COOKIE);
+ }
+ }
+
+ public static function isPost() {
+ return isset($_SERVER['REQUEST_METHOD']) &&
+ $_SERVER['REQUEST_METHOD'] === 'POST';
+ }
+}
diff --git a/lib/Minz/Session.php b/lib/Minz/Session.php
new file mode 100644
index 000000000..af4de75bb
--- /dev/null
+++ b/lib/Minz/Session.php
@@ -0,0 +1,93 @@
+<?php
+
+/**
+ * La classe Session gère la session utilisateur
+ */
+class Minz_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($name) {
+ $cookie = session_get_cookie_params();
+ self::keepCookie($cookie['lifetime']);
+
+ // démarre la session
+ session_name($name);
+ session_start();
+ }
+
+
+ /**
+ * 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) {
+ return isset($_SESSION[$p]) ? $_SESSION[$p] : $default;
+ }
+
+
+ /**
+ * Permet de créer ou mettre à jour une variable de session
+ * @param $p le paramètre à créer ou modifier
+ * @param $v la valeur à attribuer, false pour supprimer
+ */
+ public static function _param($p, $v = false) {
+ if ($v === false) {
+ unset($_SESSION[$p]);
+ } else {
+ $_SESSION[$p] = $v;
+ }
+ }
+
+
+ /**
+ * 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_destroy();
+ $_SESSION = array();
+
+ if (!$force) {
+ self::_param('language', $language);
+ Minz_Translate::reset();
+ }
+ }
+
+
+ /**
+ * Spécifie la durée de vie des cookies
+ * @param $l la durée de vie
+ */
+ public static function keepCookie($l) {
+ $cookie_dir = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI'];
+ session_set_cookie_params($l, $cookie_dir, '', false, true);
+ }
+
+
+ /**
+ * Régénère un id de session.
+ * Utile pour appeler session_set_cookie_params après session_start()
+ */
+ public static function regenerateID() {
+ session_regenerate_id(true);
+ }
+
+ public static function deleteLongTermCookie($name) {
+ setcookie($name, '', 1, '', '', false, true);
+ }
+
+ public static function setLongTermCookie($name, $value, $expire) {
+ setcookie($name, $value, $expire, '', '', false, true);
+ }
+
+ public static function getLongTermCookie($name) {
+ return isset($_COOKIE[$name]) ? $_COOKIE[$name] : null;
+ }
+
+}
diff --git a/lib/minz/Translate.php b/lib/Minz/Translate.php
index e8cbe4852..8c2f90041 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
*/
@@ -18,28 +18,28 @@ class Translate {
* $translates est le tableau de correspondance
* $key => $traduction
*/
- private static $translates = array ();
+ private static $translates = array();
/**
* Inclus le fichier de langue qui va bien
* l'enregistre dans $translates
*/
- public static function init () {
- $l = Configuration::language ();
- self::$language = Session::param ('language', $l);
+ public static function init() {
+ $l = Minz_Configuration::language();
+ self::$language = Minz_Session::param('language', $l);
$l_path = APP_PATH . '/i18n/' . self::$language . '.php';
- if (file_exists ($l_path)) {
- self::$translates = include ($l_path);
+ if (file_exists($l_path)) {
+ self::$translates = include($l_path);
}
}
/**
* Alias de init
*/
- public static function reset () {
- self::init ();
+ public static function reset() {
+ self::init();
}
/**
@@ -48,24 +48,32 @@ class Translate {
* @return la valeur correspondante à la clé
* > si non présente dans le tableau, on retourne la clé elle-même
*/
- public static function t ($key) {
+ public static function t($key) {
$translate = $key;
- if (isset (self::$translates[$key])) {
+ if (isset(self::$translates[$key])) {
$translate = self::$translates[$key];
}
- $args = func_get_args ();
+ $args = func_get_args();
unset($args[0]);
- return vsprintf ($translate, $args);
+ return vsprintf($translate, $args);
}
/**
* Retourne la langue utilisée actuellement
* @return la langue
*/
- public static function language () {
+ public static function language() {
return self::$language;
}
}
+
+function _t($key) {
+ $args = func_get_args();
+ unset($args[0]);
+ array_unshift($args, $key);
+
+ return call_user_func_array('Minz_Translate::t', $args);
+}
diff --git a/lib/minz/Url.php b/lib/Minz/Url.php
index c1c3e9a0f..e9f9a69ba 100755..100644
--- a/lib/minz/Url.php
+++ b/lib/Minz/Url.php
@@ -3,10 +3,9 @@
/**
* 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
+ * Affiche une Url formatée
* @param $url l'url à formater définie comme un tableau :
* $url['c'] = controller
* $url['a'] = action
@@ -16,50 +15,46 @@ class Url {
* @param $encodage pour indiquer comment encoder les & (& ou &amp; pour html)
* @return l'url formatée
*/
- public static function display ($url = array (), $encodage = 'html') {
- $url = self::checkUrl ($url);
-
+ public static function display ($url = array (), $encodage = 'html', $absolute = false) {
+ $isArray = is_array($url);
+
+ if ($isArray) {
+ $url = self::checkUrl ($url);
+ }
+
$url_string = '';
-
- if (is_array ($url) && isset ($url['protocol'])) {
- $protocol = $url['protocol'];
- } else {
- if(isset($_SERVER['HTTPS']) && $_SERVER["HTTPS"] == 'on') {
- $protocol = 'https';
+
+ if ($absolute) {
+ if ($isArray && isset ($url['protocol'])) {
+ $protocol = $url['protocol'];
+ } elseif (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
+ $protocol = 'https:';
} else {
- $protocol = 'http';
+ $protocol = 'http:';
}
+ $url_string = $protocol . '//' . Minz_Request::getDomainName () . Minz_Request::getBaseUrl ();
+ } else {
+ $url_string = $isArray ? '.' : PUBLIC_RELATIVE;
}
- $url_string .= $protocol . '://';
-
- $url_string .= Request::getDomainName ();
-
- $url_string .= Request::getBaseUrl ();
-
- if (is_array ($url)) {
- $router = new Router ();
-
- if (Configuration::useUrlRewriting ()) {
- $url_string .= $router->printUriRewrited ($url);
- } else {
- $url_string .= self::printUri ($url, $encodage);
- }
+
+ if ($isArray) {
+ $url_string .= self::printUri ($url, $encodage);
} else {
$url_string .= $url;
}
-
+
return $url_string;
}
/**
- * Construit l'URI d'une URL sans url rewriting
+ * Construit l'URI d'une URL
* @param l'url sous forme de tableau
* @param $encodage pour indiquer comment encoder les & (& ou &amp; pour html)
* @return l'uri sous la forme ?key=value&key2=value2
*/
private static function printUri ($url, $encodage) {
$uri = '';
- $separator = '/?';
+ $separator = '?';
if($encodage == 'html') {
$and = '&amp;';
@@ -68,13 +63,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;
}
@@ -99,10 +94,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 ();
@@ -126,5 +121,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 1bfa0a61f..a0dec1824 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 ();
@@ -26,24 +26,28 @@ class View {
* Détermine si on utilise un layout ou non
*/
public function __construct () {
+ $this->change_view(Minz_Request::controllerName(),
+ Minz_Request::actionName());
+ self::$title = Minz_Configuration::title ();
+ }
+
+ /**
+ * Change le fichier de vue en fonction d'un controller / action
+ */
+ public function change_view($controller_name, $action_name) {
$this->view_filename = APP_PATH
. self::VIEWS_PATH_NAME . '/'
- . Request::controllerName () . '/'
- . Request::actionName () . '.phtml';
-
- if (file_exists (APP_PATH
- . self::LAYOUT_PATH_NAME
- . self::LAYOUT_FILENAME)) {
- $this->use_layout = true;
- }
-
- self::$title = Configuration::title ();
+ . $controller_name . '/'
+ . $action_name . '.phtml';
}
/**
* 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 +70,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 +86,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,16 +102,24 @@ 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);
}
}
/**
+ * Retourne renderHelper() dans une chaîne
+ * @param $helper l'élément à traîter
+ */
+ public function helperToString($helper) {
+ ob_start();
+ $this->renderHelper($helper);
+ return ob_get_clean();
+ }
+
+ /**
* Permet de choisir si on souhaite utiliser le layout
* @param $use true si on souhaite utiliser le layout, false sinon
*/
@@ -150,9 +158,9 @@ class View {
$styles .= '<!--[if ' . $cond . ']>';
}
- $styles .= '<link rel="stylesheet" type="text/css"';
- $styles .= ' media="' . $style['media'] . '"';
- $styles .= ' href="' . $style['url'] . '" />';
+ $styles .= '<link rel="stylesheet" ' .
+ ($style['media'] === 'all' ? '' : 'media="' . $style['media'] . '" ') .
+ 'href="' . $style['url'] . '" />';
if ($cond) {
$styles .= '<![endif]-->';
@@ -190,9 +198,14 @@ class View {
$scripts .= '<!--[if ' . $cond . ']>';
}
- $scripts .= '<script type="text/javascript"';
- $scripts .= ' src="' . $script['url'] . '">';
- $scripts .= '</script>';
+ $scripts .= '<script src="' . $script['url'] . '"';
+ if ($script['defer']) {
+ $scripts .= ' defer="defer"';
+ }
+ if ($script['async']) {
+ $scripts .= ' async="async"';
+ }
+ $scripts .= '></script>';
if ($cond) {
$scripts .= '<![endif]-->';
@@ -203,16 +216,20 @@ class View {
return $scripts;
}
- public static function prependScript ($url, $cond = false) {
+ public static function prependScript ($url, $cond = false, $defer = true, $async = true) {
array_unshift(self::$scripts, array (
'url' => $url,
- 'cond' => $cond
+ 'cond' => $cond,
+ 'defer' => $defer,
+ 'async' => $async,
));
}
- public static function appendScript ($url, $cond = false) {
+ public static function appendScript ($url, $cond = false, $defer = true, $async = true) {
self::$scripts[] = array (
'url' => $url,
- 'cond' => $cond
+ 'cond' => $cond,
+ 'defer' => $defer,
+ 'async' => $async,
);
}
@@ -223,7 +240,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 b33c635f1..06c100f59 100644
--- a/lib/SimplePie/SimplePie.php
+++ b/lib/SimplePie/SimplePie.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev-FreshRSS
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
@@ -50,7 +50,7 @@ define('SIMPLEPIE_NAME', 'SimplePie');
/**
* SimplePie Version
*/
-define('SIMPLEPIE_VERSION', '1.3.1');
+define('SIMPLEPIE_VERSION', '1.4-dev-FreshRSS');
/**
* SimplePie Build
@@ -446,6 +446,13 @@ class SimplePie
public $feed_url;
/**
+ * @var string Original feed URL, or new feed URL iff HTTP 301 Moved Permanently
+ * @see SimplePie::subscribe_url()
+ * @access private
+ */
+ public $permanent_url = null; //FreshRSS
+
+ /**
* @var object Instance of SimplePie_File to use as a feed
* @see SimplePie::set_file()
* @access private
@@ -602,6 +609,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 different 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
@@ -637,7 +651,7 @@ class SimplePie
if (func_num_args() > 0)
{
$level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
- trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.', $level);
+ trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_duration() directly.', $level);
$args = func_get_args();
switch (count($args)) {
@@ -728,6 +742,7 @@ class SimplePie
else
{
$this->feed_url = $this->registry->call('Misc', 'fix_protocol', array($url, 1));
+ $this->permanent_url = $this->feed_url; //FreshRSS
}
}
@@ -742,6 +757,7 @@ class SimplePie
if ($file instanceof SimplePie_File)
{
$this->feed_url = $file->url;
+ $this->permanent_url = $this->feed_url; //FreshRSS
$this->file =& $file;
return true;
}
@@ -1073,6 +1089,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 +1136,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
*
@@ -1196,13 +1222,27 @@ class SimplePie
}
/**
+ * Enable throwing exceptions
+ *
+ * @param boolean $enable Should we throw exceptions, or use the old-style error property?
+ */
+ public function enable_exceptions($enable = true)
+ {
+ $this->enable_exceptions = $enable;
+ }
+
+ function cleanMd5($rss) { //FreshRSS
+ return md5(preg_replace(array('#<(lastBuildDate|pubDate|updated|feedDate|dc:date|slash:comments)>[^<]+</\\1>#', '#<!--.+?-->#s'), '', $rss));
+ }
+
+ /**
* Initialize the feed object
*
* This is what makes everything happen. Period. This is where all of the
* configuration options get processed, feeds are fetched, cached, and
* parsed, and all of that other good stuff.
*
- * @return boolean True if successful, false otherwise
+ * @return positive integer with modification time if using cache, boolean true if otherwise successful, false otherwise
*/
public function init()
{
@@ -1281,13 +1321,17 @@ class SimplePie
// Fetch the data via SimplePie_File into $this->raw_data
if (($fetched = $this->fetch_data($cache)) === true)
{
- return true;
+ return $this->data['mtime']; //FreshRSS
}
elseif ($fetched === false) {
return false;
}
list($headers, $sniffed) = $fetched;
+
+ if (isset($this->data['md5'])) { //FreshRSS
+ $md5 = $this->data['md5'];
+ }
}
// Set up array of possible encodings
@@ -1296,7 +1340,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');
@@ -1311,14 +1355,20 @@ class SimplePie
{
$encodings[] = strtoupper($charset[1]);
}
- $encodings = array_merge($encodings, $this->registry->call('Misc', 'xml_encoding', array($this->raw_data, &$this->registry)));
- $encodings[] = 'UTF-8';
+ else
+ {
+ $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[] = ''; //FreshRSS: Let the DOM parser decide first
}
$encodings[] = 'US-ASCII';
}
@@ -1341,13 +1391,14 @@ class SimplePie
foreach ($encodings as $encoding)
{
// Change the encoding to UTF-8 (as we always use UTF-8 internally)
- if ($utf8_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))
@@ -1362,6 +1413,8 @@ class SimplePie
$this->data['headers'] = $headers;
}
$this->data['build'] = SIMPLEPIE_BUILD;
+ $this->data['mtime'] = time(); //FreshRSS
+ $this->data['md5'] = empty($md5) ? $this->cleanMd5($this->raw_data) : $md5; //FreshRSS
// Cache the file if caching is enabled
if ($cache && !$cache->save($this))
@@ -1437,7 +1490,7 @@ class SimplePie
elseif ($cache->mtime() + $this->cache_duration < time())
{
// If we have last-modified and/or etag set
- if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
+ //if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag'])) //FreshRSS removed
{
$headers = array(
'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
@@ -1451,7 +1504,7 @@ class SimplePie
$headers['if-none-match'] = $this->data['headers']['etag'];
}
- $file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
+ $file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen)); //FreshRSS
if ($file->success)
{
@@ -1463,7 +1516,20 @@ class SimplePie
}
else
{
- unset($file);
+ $this->error = $file->error; //FreshRSS
+ return !empty($this->data); //FreshRSS
+ //unset($file); //FreshRSS removed
+ }
+ }
+ { //FreshRSS
+ $md5 = $this->cleanMd5($file->body);
+ if ($this->data['md5'] === $md5) {
+ syslog(LOG_DEBUG, 'SimplePie MD5 cache match for ' . $this->feed_url);
+ $cache->touch();
+ return true; //Content unchanged even though server did not send a 304
+ } else {
+ syslog(LOG_DEBUG, 'SimplePie MD5 cache no match for ' . $this->feed_url);
+ $this->data['md5'] = $md5;
}
}
}
@@ -1531,6 +1597,8 @@ class SimplePie
if ($cache)
{
$this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
+ $this->data['mtime'] = time(); //FreshRSS
+ $this->data['md5'] = empty($md5) ? $this->cleanMd5($file->body) : $md5; //FreshRSS
if (!$cache->save($this))
{
trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
@@ -1543,7 +1611,7 @@ class SimplePie
}
$this->raw_data = $file->body;
-
+ $this->permanent_url = $file->permanent_url; //FreshRSS
$headers = $file->headers;
$sniffer = $this->registry->create('Content_Type_Sniffer', array(&$file));
$sniffed = $sniffer->get_type();
@@ -1729,26 +1797,39 @@ class SimplePie
/**
* Get the URL for the feed
+ *
+ * When the 'permanent' mode is enabled, returns the original feed URL,
+ * except in the case of an `HTTP 301 Moved Permanently` status response,
+ * in which case the location of the first redirection is returned.
*
- * May or may not be different from the URL passed to {@see set_feed_url()},
+ * When the 'permanent' mode is disabled (default),
+ * may or may not be different from the URL passed to {@see set_feed_url()},
* depending on whether auto-discovery was used.
*
* @since Preview Release (previously called `get_feed_url()` since SimplePie 0.8.)
- * @todo If we have a perm redirect we should return the new URL
- * @todo When we make the above change, let's support <itunes:new-feed-url> as well
+ * @todo Support <itunes:new-feed-url>
* @todo Also, |atom:link|@rel=self
+ * @param bool $permanent Permanent mode to return only the original URL or the first redirection
+ * iff it is a 301 redirection
* @return string|null
*/
- public function subscribe_url()
+ public function subscribe_url($permanent = false)
{
- if ($this->feed_url !== null)
+ if ($permanent) //FreshRSS
{
- return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
+ if ($this->permanent_url !== null)
+ {
+ return $this->sanitize($this->permanent_url, SIMPLEPIE_CONSTRUCT_IRI);
+ }
}
else
{
- return null;
+ if ($this->feed_url !== null)
+ {
+ return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
+ }
}
+ return null;
}
/**
@@ -1963,7 +2044,21 @@ class SimplePie
*/
public function sanitize($data, $type, $base = '')
{
- return $this->sanitize->sanitize($data, $type, $base);
+ try
+ {
+ return $this->sanitize->sanitize($data, $type, $base);
+ }
+ catch (SimplePie_Exception $e)
+ {
+ if (!$this->enable_exceptions)
+ {
+ $this->error = $e->getMessage();
+ $this->registry->call('Misc', 'error', array($this->error, E_USER_WARNING, $e->getFile(), $e->getLine()));
+ return '';
+ }
+
+ throw $e;
+ }
}
/**
diff --git a/lib/SimplePie/SimplePie/Author.php b/lib/SimplePie/SimplePie/Author.php
index bbf3812ff..19563c5cc 100644
--- a/lib/SimplePie/SimplePie/Author.php
+++ b/lib/SimplePie/SimplePie/Author.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Cache.php b/lib/SimplePie/SimplePie/Cache.php
index 75586d749..86b618693 100644
--- a/lib/SimplePie/SimplePie/Cache.php
+++ b/lib/SimplePie/SimplePie/Cache.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Cache/Base.php b/lib/SimplePie/SimplePie/Cache/Base.php
index 937e34631..d3f353961 100644
--- a/lib/SimplePie/SimplePie/Cache/Base.php
+++ b/lib/SimplePie/SimplePie/Cache/Base.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Cache/DB.php b/lib/SimplePie/SimplePie/Cache/DB.php
index ac509ae08..d728a9a6d 100644
--- a/lib/SimplePie/SimplePie/Cache/DB.php
+++ b/lib/SimplePie/SimplePie/Cache/DB.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Cache/File.php b/lib/SimplePie/SimplePie/Cache/File.php
index 5797b3aed..3b163545b 100644
--- a/lib/SimplePie/SimplePie/Cache/File.php
+++ b/lib/SimplePie/SimplePie/Cache/File.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Cache/Memcache.php b/lib/SimplePie/SimplePie/Cache/Memcache.php
index fd4478060..23b1c9367 100644
--- a/lib/SimplePie/SimplePie/Cache/Memcache.php
+++ b/lib/SimplePie/SimplePie/Cache/Memcache.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
@@ -95,10 +95,8 @@ class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
'prefix' => 'simplepie_',
),
);
- $parsed = SimplePie_Cache::parse_URL($location);
- $this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
- $this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
- $this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
+ $this->options = SimplePie_Misc::array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
+
$this->name = $this->options['extras']['prefix'] . md5("$name:$type");
$this->cache = new Memcache();
@@ -147,7 +145,7 @@ class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
if ($data !== false)
{
- // essentially ignore the mtime because Memcache expires on it's own
+ // essentially ignore the mtime because Memcache expires on its own
return time();
}
@@ -165,7 +163,7 @@ class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
if ($data !== false)
{
- return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
+ return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
}
return false;
diff --git a/lib/SimplePie/SimplePie/Cache/MySQL.php b/lib/SimplePie/SimplePie/Cache/MySQL.php
index d53ebc117..511ef6d3a 100644
--- a/lib/SimplePie/SimplePie/Cache/MySQL.php
+++ b/lib/SimplePie/SimplePie/Cache/MySQL.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
@@ -96,7 +96,8 @@ class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
'prefix' => '',
),
);
- $this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
+
+ $this->options = SimplePie_Misc::array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
// Path is prefixed with a "/"
$this->options['dbname'] = substr($this->options['path'], 1);
@@ -136,7 +137,7 @@ class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
if (!in_array($this->options['extras']['prefix'] . 'items', $db))
{
- $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
+ $query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` MEDIUMBLOB CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
if ($query === false)
{
$this->mysql = null;
diff --git a/lib/SimplePie/SimplePie/Caption.php b/lib/SimplePie/SimplePie/Caption.php
index 52922c5d9..a77b02ef1 100644
--- a/lib/SimplePie/SimplePie/Caption.php
+++ b/lib/SimplePie/SimplePie/Caption.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Category.php b/lib/SimplePie/SimplePie/Category.php
index ad0407b4e..c6a273989 100644
--- a/lib/SimplePie/SimplePie/Category.php
+++ b/lib/SimplePie/SimplePie/Category.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Content/Type/Sniffer.php b/lib/SimplePie/SimplePie/Content/Type/Sniffer.php
index 20d053dca..a32f47f59 100644
--- a/lib/SimplePie/SimplePie/Content/Type/Sniffer.php
+++ b/lib/SimplePie/SimplePie/Content/Type/Sniffer.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Copyright.php b/lib/SimplePie/SimplePie/Copyright.php
index 57c535a64..09f22f8df 100644
--- a/lib/SimplePie/SimplePie/Copyright.php
+++ b/lib/SimplePie/SimplePie/Copyright.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Core.php b/lib/SimplePie/SimplePie/Core.php
index 46d996628..7cf34876f 100644
--- a/lib/SimplePie/SimplePie/Core.php
+++ b/lib/SimplePie/SimplePie/Core.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Credit.php b/lib/SimplePie/SimplePie/Credit.php
index d3a3442ad..50aef1c68 100644
--- a/lib/SimplePie/SimplePie/Credit.php
+++ b/lib/SimplePie/SimplePie/Credit.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Decode/HTML/Entities.php b/lib/SimplePie/SimplePie/Decode/HTML/Entities.php
index 069e8d8e5..cde06c884 100644
--- a/lib/SimplePie/SimplePie/Decode/HTML/Entities.php
+++ b/lib/SimplePie/SimplePie/Decode/HTML/Entities.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Enclosure.php b/lib/SimplePie/SimplePie/Enclosure.php
index 55674379c..fa0217800 100644
--- a/lib/SimplePie/SimplePie/Enclosure.php
+++ b/lib/SimplePie/SimplePie/Enclosure.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
@@ -942,7 +942,7 @@ class SimplePie_Enclosure
* - `height` (integer): The height of the embedded media. Accepts any
* numeric pixel value (such as `360`) or `auto`. Defaults to `auto`,
* and it is recommended that you use this default.
- * - `loop` (boolean): Do you want the media to loop when its done?
+ * - `loop` (boolean): Do you want the media to loop when it's done?
* Defaults to `false`.
* - `mediaplayer` (string): The location of the included
* `mediaplayer.swf` file. This allows for the playback of Flash Video
diff --git a/lib/SimplePie/SimplePie/File.php b/lib/SimplePie/SimplePie/File.php
index 063ad955e..b1bbe4420 100644
--- a/lib/SimplePie/SimplePie/File.php
+++ b/lib/SimplePie/SimplePie/File.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
@@ -64,6 +64,7 @@ class SimplePie_File
var $redirects = 0;
var $error;
var $method = SIMPLEPIE_FILE_SOURCE_NONE;
+ var $permanent_url; //FreshRSS
public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
{
@@ -74,9 +75,11 @@ class SimplePie_File
$url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
}
$this->url = $url;
+ $this->permanent_url = $url; //FreshRSS
$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');
@@ -107,7 +110,7 @@ class SimplePie_File
curl_setopt($fp, CURLOPT_REFERER, $url);
curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
- curl_setopt($fp, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($fp, CURLOPT_SSL_VERIFYPEER, false); //FreshRSS
if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
{
curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
@@ -141,7 +144,10 @@ class SimplePie_File
{
$this->redirects++;
$location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
- return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+ $previousStatusCode = $this->status_code;
+ $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+ $this->permanent_url = ($previousStatusCode == 301) ? $location : $url; //FreshRSS
+ return;
}
}
}
@@ -223,7 +229,10 @@ class SimplePie_File
{
$this->redirects++;
$location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
- return $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+ $previousStatusCode = $this->status_code;
+ $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+ $this->permanent_url = ($previousStatusCode == 301) ? $location : $url; //FreshRSS
+ return;
}
if (isset($this->headers['content-encoding']))
{
@@ -283,7 +292,7 @@ class SimplePie_File
else
{
$this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
- if (!$this->body = file_get_contents($url))
+ if (empty($url) || !($this->body = file_get_contents($url)))
{
$this->error = 'file_get_contents could not read the file';
$this->success = false;
diff --git a/lib/SimplePie/SimplePie/HTTP/Parser.php b/lib/SimplePie/SimplePie/HTTP/Parser.php
index bff2222b2..2fc3a6779 100644
--- a/lib/SimplePie/SimplePie/HTTP/Parser.php
+++ b/lib/SimplePie/SimplePie/HTTP/Parser.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/IRI.php b/lib/SimplePie/SimplePie/IRI.php
index d3198c04f..ed0574701 100644
--- a/lib/SimplePie/SimplePie/IRI.php
+++ b/lib/SimplePie/SimplePie/IRI.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Item.php b/lib/SimplePie/SimplePie/Item.php
index a77574b37..7bd96c15f 100644
--- a/lib/SimplePie/SimplePie/Item.php
+++ b/lib/SimplePie/SimplePie/Item.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
@@ -821,7 +821,7 @@ class SimplePie_Item
if (!empty($this->data['updated']['raw']))
{
$parser = $this->registry->call('Parse_Date', 'get');
- $this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']);
+ $this->data['updated']['parsed'] = $parser->parse($this->data['updated']['raw']);
}
else
{
@@ -1080,7 +1080,7 @@ class SimplePie_Item
*
* @since Beta 2
* @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
- * @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists).
+ * @todo If an element exists at a level, but its value is empty, we should fall back to the value from the parent (if it exists).
* @return array|null List of SimplePie_Enclosure items
*/
public function get_enclosures()
diff --git a/lib/SimplePie/SimplePie/Locator.php b/lib/SimplePie/SimplePie/Locator.php
index 57e910c22..90ee7a302 100644
--- a/lib/SimplePie/SimplePie/Locator.php
+++ b/lib/SimplePie/SimplePie/Locator.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
@@ -277,7 +277,7 @@ class SimplePie_Locator
$parsed = $this->registry->call('Misc', 'parse_url', array($href));
if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
{
- if ($this->base_location < $link->getLineNo())
+ if (method_exists($link, 'getLineNo') && $this->base_location < $link->getLineNo())
{
$href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
}
diff --git a/lib/SimplePie/SimplePie/Misc.php b/lib/SimplePie/SimplePie/Misc.php
index 621f2c062..5a263a2e5 100644
--- a/lib/SimplePie/SimplePie/Misc.php
+++ b/lib/SimplePie/SimplePie/Misc.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
@@ -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)
{
@@ -124,7 +128,7 @@ class SimplePie_Misc
{
$attribs[$j][2] = $attribs[$j][1];
}
- $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
+ $return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8'); //FreshRSS
}
}
}
@@ -138,7 +142,7 @@ class SimplePie_Misc
foreach ($element['attribs'] as $key => $value)
{
$key = strtolower($key);
- $full .= " $key=\"" . htmlspecialchars($value['data'], ENT_COMPAT, 'UTF-8') . '"';
+ $full .= " $key=\"" . htmlspecialchars($value['data'], ENT_COMPAT, 'UTF-8') . '"'; //FreshRSS
}
if ($element['self_closing'])
{
@@ -224,6 +228,23 @@ class SimplePie_Misc
}
}
+ public static function array_merge_recursive($array1, $array2)
+ {
+ foreach ($array2 as $key => $value)
+ {
+ if (is_array($value))
+ {
+ $array1[$key] = SimplePie_Misc::array_merge_recursive($array1[$key], $value);
+ }
+ else
+ {
+ $array1[$key] = $value;
+ }
+ }
+
+ return $array1;
+ }
+
public static function parse_url($url)
{
$iri = new SimplePie_IRI($url);
@@ -2157,36 +2178,12 @@ function embed_wmedia(width, height, link) {
/**
* Get the SimplePie build timestamp
*
- * Uses the git index if it exists, otherwise uses the modification time
- * of the newest file.
+ * Return SimplePie.php modification time.
*/
public static function get_build()
{
- $root = dirname(dirname(__FILE__));
- if (file_exists($root . '/.git/index'))
- {
- return filemtime($root . '/.git/index');
- }
- elseif (file_exists($root . '/SimplePie'))
- {
- $time = 0;
- foreach (glob($root . '/SimplePie/*.php') as $file)
- {
- if (($mtime = filemtime($file)) > $time)
- {
- $time = $mtime;
- }
- }
- return $time;
- }
- elseif (file_exists(dirname(__FILE__) . '/Core.php'))
- {
- return filemtime(dirname(__FILE__) . '/Core.php');
- }
- else
- {
- return filemtime(__FILE__);
- }
+ $mtime = @filemtime(dirname(dirname(__FILE__)) . '/SimplePie.php'); //FreshRSS
+ return $mtime ? $mtime : filemtime(__FILE__);
}
/**
diff --git a/lib/SimplePie/SimplePie/Net/IPv6.php b/lib/SimplePie/SimplePie/Net/IPv6.php
index da80d8aca..2ff1afc90 100644
--- a/lib/SimplePie/SimplePie/Net/IPv6.php
+++ b/lib/SimplePie/SimplePie/Net/IPv6.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Parse/Date.php b/lib/SimplePie/SimplePie/Parse/Date.php
index d51f500d3..ef800f125 100644
--- a/lib/SimplePie/SimplePie/Parse/Date.php
+++ b/lib/SimplePie/SimplePie/Parse/Date.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Parser.php b/lib/SimplePie/SimplePie/Parser.php
index d698552ca..7fb7bd9be 100644
--- a/lib/SimplePie/SimplePie/Parser.php
+++ b/lib/SimplePie/SimplePie/Parser.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
@@ -77,55 +77,86 @@ class SimplePie_Parser
public function parse(&$data, $encoding)
{
- // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
- if (strtoupper($encoding) === 'US-ASCII')
- {
- $this->encoding = 'UTF-8';
- }
- else
- {
- $this->encoding = $encoding;
- }
+ $xmlEncoding = '';
- // Strip BOM:
- // UTF-32 Big Endian BOM
- if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
- {
- $data = substr($data, 4);
- }
- // UTF-32 Little Endian BOM
- elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
- {
- $data = substr($data, 4);
- }
- // UTF-16 Big Endian BOM
- elseif (substr($data, 0, 2) === "\xFE\xFF")
- {
- $data = substr($data, 2);
- }
- // UTF-16 Little Endian BOM
- elseif (substr($data, 0, 2) === "\xFF\xFE")
+ if (!empty($encoding))
{
- $data = substr($data, 2);
- }
- // UTF-8 BOM
- elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
- {
- $data = substr($data, 3);
+ // Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
+ if (strtoupper($encoding) === 'US-ASCII')
+ {
+ $this->encoding = 'UTF-8';
+ }
+ else
+ {
+ $this->encoding = $encoding;
+ }
+
+ // Strip BOM:
+ // UTF-32 Big Endian BOM
+ if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
+ {
+ $data = substr($data, 4);
+ }
+ // UTF-32 Little Endian BOM
+ elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
+ {
+ $data = substr($data, 4);
+ }
+ // UTF-16 Big Endian BOM
+ elseif (substr($data, 0, 2) === "\xFE\xFF")
+ {
+ $data = substr($data, 2);
+ }
+ // UTF-16 Little Endian BOM
+ elseif (substr($data, 0, 2) === "\xFF\xFE")
+ {
+ $data = substr($data, 2);
+ }
+ // UTF-8 BOM
+ elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
+ {
+ $data = substr($data, 3);
+ }
+
+ if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
+ {
+ $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;
+ }
+ else
+ {
+ $this->error_string = 'SimplePie bug! Please report this!';
+ return false;
+ }
+ }
}
- if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
+ if ($xmlEncoding === '' || $xmlEncoding === 'UTF-8') //FreshRSS: case of no explicit HTTP encoding, and lax UTF-8
{
- $declaration = $this->registry->create('XML_Declaration_Parser', array(substr($data, 5, $pos - 5)));
- if ($declaration->parse())
+ try
{
- $data = substr($data, $pos + 2);
- $data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
+ $dom = new DOMDocument();
+ $dom->recover = true;
+ $dom->strictErrorChecking = false;
+ @$dom->loadXML($data);
+ $this->encoding = $encoding = $dom->encoding = 'UTF-8';
+ $data2 = $dom->saveXML();
+ if (function_exists('mb_convert_encoding'))
+ {
+ $data2 = mb_convert_encoding($data2, 'UTF-8', 'UTF-8');
+ }
+ if (strlen($data2) > (strlen($data) / 2.0))
+ {
+ $data = $data2;
+ }
+ unset($data2);
}
- else
+ catch (Exception $e)
{
- $this->error_string = 'SimplePie bug! Please report this!';
- return false;
}
}
diff --git a/lib/SimplePie/SimplePie/Rating.php b/lib/SimplePie/SimplePie/Rating.php
index 8689e5dfb..b5fe80516 100644
--- a/lib/SimplePie/SimplePie/Rating.php
+++ b/lib/SimplePie/SimplePie/Rating.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Registry.php b/lib/SimplePie/SimplePie/Registry.php
index 1072cdebb..bd9c1f535 100755
--- a/lib/SimplePie/SimplePie/Registry.php
+++ b/lib/SimplePie/SimplePie/Registry.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Restriction.php b/lib/SimplePie/SimplePie/Restriction.php
index 4ba371bfb..a1d59916d 100644
--- a/lib/SimplePie/SimplePie/Restriction.php
+++ b/lib/SimplePie/SimplePie/Restriction.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/Sanitize.php b/lib/SimplePie/SimplePie/Sanitize.php
index 83a274ced..168a5e2e8 100644
--- a/lib/SimplePie/SimplePie/Sanitize.php
+++ b/lib/SimplePie/SimplePie/Sanitize.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
@@ -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;
@@ -247,6 +267,10 @@ class SimplePie_Sanitize
if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
{
+ if (!class_exists('DOMDocument'))
+ {
+ throw new SimplePie_Exception('DOMDocument not found, unable to use sanitizer');
+ }
$document = new DOMDocument();
$document->encoding = 'UTF-8';
$data = $this->preprocess($data, $type);
@@ -255,10 +279,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 +299,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 +307,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);
}
}
@@ -310,7 +343,7 @@ class SimplePie_Sanitize
}
else
{
- $file = $this->registry->create('File', array($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
+ $file = $this->registry->create('File', array($img->getAttribute('src'), $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
$headers = $file->headers;
if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
@@ -452,9 +485,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 +569,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 +578,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/SimplePie/Source.php b/lib/SimplePie/SimplePie/Source.php
index 51d8e6c25..2613798fd 100644
--- a/lib/SimplePie/SimplePie/Source.php
+++ b/lib/SimplePie/SimplePie/Source.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/XML/Declaration/Parser.php b/lib/SimplePie/SimplePie/XML/Declaration/Parser.php
index aec19f10a..589e452a2 100644
--- a/lib/SimplePie/SimplePie/XML/Declaration/Parser.php
+++ b/lib/SimplePie/SimplePie/XML/Declaration/Parser.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
diff --git a/lib/SimplePie/SimplePie/gzdecode.php b/lib/SimplePie/SimplePie/gzdecode.php
index 52e024ea9..6e65f0811 100644
--- a/lib/SimplePie/SimplePie/gzdecode.php
+++ b/lib/SimplePie/SimplePie/gzdecode.php
@@ -33,7 +33,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*
* @package SimplePie
- * @version 1.3.1
+ * @version 1.4-dev
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
* @author Ryan Parman
* @author Geoffrey Sneddon
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
new file mode 100644
index 000000000..59fbef41f
--- /dev/null
+++ b/lib/http-conditional.php
@@ -0,0 +1,212 @@
+<?php
+/*
+ Enable support for HTTP/1.x conditional requests in PHP.
+ Goal: Optimisation
+ - If the client sends a HEAD request, avoid transferring data and return the correct headers.
+ - If the client already has the same version in its cache, avoid transferring data again (304 Not Modified).
+ - Possibility to control cache for client and proxies (public or private policy, life time).
+ - When $feedMode is set to true, in the case of a RSS/ATOM feed,
+ it puts a timestamp in the global variable $clientCacheDate to allow the sending of only the articles newer than the client's cache.
+ - When $compression is set to true, compress the data before sending it to the client and persitent connections are allowed.
+ - When $session is set to true, automatically checks if $_SESSION has been modified during the last generation the document.
+
+ Interface:
+ - function httpConditional($UnixTimeStamp,$cacheSeconds=0,$cachePrivacy=0,$feedMode=false,$compression=false)
+ [Required] $UnixTimeStamp: Date of the last modification of the data to send to the client (Unix Timestamp format).
+ [Implied] $cacheSeconds=0: Lifetime in seconds of the document. If $cacheSeconds<0, cache is disabled. If $cacheSeconds==0, the document will be revalidated each time it is accessed. If $cacheSeconds>0, the document will be cashed and not revalidated against the server for this delay.
+ [Implied] $cachePrivacy=0: 0=private, 1=normal (public), 2=forced public. When public, it allows a cashed document ($cacheSeconds>0) to be shared by several users.
+ [Implied] $feedMode=false: Special RSS/ATOM feeds. When true, it sets $cachePrivacy to 0 (private), does not use the modification time of the script itself, and puts the date of the client's cache (or a old date from 1980) in the global variable $clientCacheDate.
+ [implied] $compression=false: Enable the compression and allows persistant connections (automatic detection of the capacities of the client).
+ [implied] $session=false: To be turned on when sessions are used. Checks if the data contained in $_SESSION has been modified during the last generation the document.
+ Returns: True if the connection can be closed (e.g.: the client has already the lastest version), false if the new content has to be send to the client.
+
+ Typical use:
+ <?php
+ require_once('http-conditional.php');
+ //Date of the last modification of the content (Unix Timestamp format).
+ //Examples: query the database, or last modification of a static file.
+ $dateLastModification=...;
+ if (httpConditional($dateLastModification))
+ {
+ ... //Close database connections, and other cleaning.
+ exit(); //No need to send anything
+ }
+ //Do not send any text to the client before this line.
+ ... //Rest of the script, just as you would do normally.
+ ?>
+
+ 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/
+
+ Copyright 2004-2013, Licence: Creative Commons "Attribution-ShareAlike 2.0 France" BY-SA (FR),
+ http://creativecommons.org/licenses/by-sa/2.0/fr/
+ http://alexandre.alapetite.fr/divers/apropos/#by-sa
+ - Attribution. You must give the original author credit
+ - Share Alike. If you alter, transform, or build upon this work,
+ you may distribute the resulting work only under a license identical to this one
+ (Can be included in GPL/LGPL projects)
+ - The French law is authoritative
+ - Any of these conditions can be waived if you get permission from Alexandre Alapetite
+ - Please send to Alexandre Alapetite the modifications you make,
+ in order to improve this file for the benefit of everybody
+
+ If you want to distribute this code, please do it as a link to:
+ http://alexandre.alapetite.fr/doc-alex/php-http-304/
+*/
+
+//In RSS/ATOM feedMode, contains the date of the clients last update.
+$clientCacheDate=0; //Global public variable because PHP4 does not allow conditional arguments by reference
+$_sessionMode=false; //Global private variable
+
+function httpConditional($UnixTimeStamp,$cacheSeconds=0,$cachePrivacy=0,$feedMode=false,$compression=false,$session=false)
+{//Credits: http://alexandre.alapetite.fr/doc-alex/php-http-304/
+ //RFC2616 HTTP/1.1: http://www.w3.org/Protocols/rfc2616/rfc2616.html
+ //RFC1945 HTTP/1.0: http://www.w3.org/Protocols/rfc1945/rfc1945.txt
+
+ if (headers_sent()) return false;
+
+ if (isset($_SERVER['SCRIPT_FILENAME'])) $scriptName=$_SERVER['SCRIPT_FILENAME'];
+ elseif (isset($_SERVER['PATH_TRANSLATED'])) $scriptName=$_SERVER['PATH_TRANSLATED'];
+ else return false;
+
+ if ((!$feedMode)&&(($modifScript=filemtime($scriptName))>$UnixTimeStamp))
+ $UnixTimeStamp=$modifScript;
+ $UnixTimeStamp=min($UnixTimeStamp,time());
+ $is304=true;
+ $is412=false;
+ $nbCond=0;
+
+ //rfc2616-sec3.html#sec3.3.1
+ $dateLastModif=gmdate('D, d M Y H:i:s \G\M\T',$UnixTimeStamp);
+ $dateCacheClient='Thu, 10 Jan 1980 20:30:40 GMT';
+
+ //rfc2616-sec14.html#sec14.19 //='"0123456789abcdef0123456789abcdef"'
+ if (isset($_SERVER['QUERY_STRING'])) $myQuery='?'.$_SERVER['QUERY_STRING'];
+ else $myQuery='';
+ if ($session&&isset($_SESSION))
+ {
+ global $_sessionMode;
+ $_sessionMode=$session;
+ $myQuery.=print_r($_SESSION,true).session_name().'='.session_id();
+ }
+ $etagServer='"'.md5($scriptName.$myQuery.'#'.$dateLastModif).'"';
+
+ if ((!$is412)&&isset($_SERVER['HTTP_IF_MATCH']))
+ {//rfc2616-sec14.html#sec14.24
+ $etagsClient=stripslashes($_SERVER['HTTP_IF_MATCH']);
+ $is412=(($etagClient!=='*')&&(strpos($etagsClient,$etagServer)===false));
+ }
+ if ($is304&&isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))
+ {//rfc2616-sec14.html#sec14.25 //rfc1945.txt
+ $nbCond++;
+ $dateCacheClient=$_SERVER['HTTP_IF_MODIFIED_SINCE'];
+ $p=strpos($dateCacheClient,';');
+ if ($p!==false)
+ $dateCacheClient=substr($dateCacheClient,0,$p);
+ $is304=($dateCacheClient==$dateLastModif);
+ }
+ if ($is304&&isset($_SERVER['HTTP_IF_NONE_MATCH']))
+ {//rfc2616-sec14.html#sec14.26
+ $nbCond++;
+ $etagClient=stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
+ $is304=(($etagClient===$etagServer)||($etagClient==='*'));
+ }
+ if ((!$is412)&&isset($_SERVER['HTTP_IF_UNMODIFIED_SINCE']))
+ {//rfc2616-sec14.html#sec14.28
+ $dateCacheClient=$_SERVER['HTTP_IF_UNMODIFIED_SINCE'];
+ $p=strpos($dateCacheClient,';');
+ if ($p!==false)
+ $dateCacheClient=substr($dateCacheClient,0,$p);
+ $is412=($dateCacheClient!==$dateLastModif);
+ }
+ if ($feedMode)
+ {//Special RSS/ATOM
+ global $clientCacheDate;
+ $clientCacheDate=@strtotime($dateCacheClient);
+ $cachePrivacy=0;
+ }
+
+ if ($is412)
+ {//rfc2616-sec10.html#sec10.4.13
+ header('HTTP/1.1 412 Precondition Failed');
+ header('Cache-Control: private, max-age=0, must-revalidate');
+ header('Content-Type: text/plain');
+ echo "HTTP/1.1 Error 412 Precondition Failed: Precondition request failed positive evaluation\n";
+ return true;
+ }
+ elseif ($is304&&($nbCond>0))
+ {//rfc2616-sec10.html#sec10.3.5
+ header('HTTP/1.0 304 Not Modified');
+ header('Etag: '.$etagServer);
+ if ($feedMode) header('Connection: close'); //Comment this line under IIS
+ return true;
+ }
+ else
+ {//rfc2616-sec10.html#sec10.2.1
+ //rfc2616-sec14.html#sec14.3
+ if ($compression) ob_start('_httpConditionalCallBack'); //Will check HTTP_ACCEPT_ENCODING
+ //header('HTTP/1.0 200 OK');
+ if ($cacheSeconds<0)
+ {
+ $cache='private, no-cache, no-store, must-revalidate';
+ //header('Expires: 0');
+ header('Pragma: no-cache');
+ }
+ else
+ {
+ if ($cacheSeconds===0)
+ {
+ $cache='private, must-revalidate, ';
+ //header('Expires: 0');
+ }
+ elseif ($cachePrivacy===0) $cache='private, ';
+ elseif ($cachePrivacy===2) $cache='public, ';
+ else $cache='';
+ $cache.='max-age='.floor($cacheSeconds);
+ }
+ //header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T',time()+$cacheSeconds)); //HTTP/1.0 //rfc2616-sec14.html#sec14.21
+ header('Cache-Control: '.$cache); //rfc2616-sec14.html#sec14.9
+ header('Last-Modified: '.$dateLastModif);
+ header('Etag: '.$etagServer);
+ if ($feedMode) header('Connection: close'); //rfc2616-sec14.html#sec14.10 //Comment this line under IIS
+ return $_SERVER['REQUEST_METHOD']==='HEAD'; //rfc2616-sec9.html#sec9.4
+ }
+}
+
+function _httpConditionalCallBack($buffer,$mode=5)
+{//Private function automatically called at the end of the script when compression is enabled
+ //rfc2616-sec14.html#sec14.11
+ //You can adjust the level of compression with zlib.output_compression_level in php.ini
+ if (extension_loaded('zlib')&&(!ini_get('zlib.output_compression')))
+ {
+ $buffer2=ob_gzhandler($buffer,$mode); //Will check HTTP_ACCEPT_ENCODING and put correct headers such as Vary //rfc2616-sec14.html#sec14.44
+ if (strlen($buffer2)>1) //When ob_gzhandler succeeded
+ $buffer=$buffer2;
+ }
+ header('Content-Length: '.strlen($buffer)); //Allows persistant connections //rfc2616-sec14.html#sec14.13
+ return $buffer;
+}
+
+function httpConditionalRefresh($UnixTimeStamp)
+{//Update HTTP headers if the content has just been modified by the client's request
+ //See an example on http://alexandre.alapetite.fr/doc-alex/compteur/
+ if (headers_sent()) return false;
+
+ if (isset($_SERVER['SCRIPT_FILENAME'])) $scriptName=$_SERVER['SCRIPT_FILENAME'];
+ elseif (isset($_SERVER['PATH_TRANSLATED'])) $scriptName=$_SERVER['PATH_TRANSLATED'];
+ else return false;
+
+ $dateLastModif=gmdate('D, d M Y H:i:s \G\M\T',$UnixTimeStamp);
+
+ if (isset($_SERVER['QUERY_STRING'])) $myQuery='?'.$_SERVER['QUERY_STRING'];
+ else $myQuery='';
+ global $_sessionMode;
+ if ($_sessionMode&&isset($_SESSION))
+ $myQuery.=print_r($_SESSION,true).session_name().'='.session_id();
+ $etagServer='"'.md5($scriptName.$myQuery.'#'.$dateLastModif).'"';
+
+ header('Last-Modified: '.$dateLastModif);
+ header('Etag: '.$etagServer);
+}
diff --git a/lib/lib_date.php b/lib/lib_date.php
new file mode 100644
index 000000000..9533711e3
--- /dev/null
+++ b/lib/lib_date.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * Author: Alexandre Alapetite http://alexandre.alapetite.fr
+ * 2014-06-01
+ * License: GNU AGPLv3 http://www.gnu.org/licenses/agpl-3.0.html
+ *
+ * Parser of ISO 8601 time intervals http://en.wikipedia.org/wiki/ISO_8601#Time_intervals
+ * Examples: "2014-02/2014-04", "2014-02/04", "2014-06", "P1M"
+ */
+
+/*
+example('2014-03');
+example('201403');
+example('2014-03-30');
+example('2014-05-30T13');
+example('2014-05-30T13:30');
+example('2014-02/2014-04');
+example('2014-02--2014-04');
+example('2014-02/04');
+example('2014-02-03/05');
+example('2014-02-03T22:00/22:15');
+example('2014-02-03T22:00/15');
+example('2014-03/');
+example('/2014-03');
+example('2014-03/P1W');
+example('P1W/2014-05-25T23:59:59');
+example('P1Y/');
+example('P1Y');
+example('P2M/');
+example('P3W/');
+example('P4D/');
+example('PT5H/');
+example('PT6M/');
+example('PT7S/');
+example('P1DT1H/');
+
+function example($dateInterval) {
+ $dateIntervalArray = parseDateInterval($dateInterval);
+ echo $dateInterval, "\t=>\t",
+ $dateIntervalArray[0] == null ? 'null' : @date('c', $dateIntervalArray[0]), '/',
+ $dateIntervalArray[1] == null ? 'null' : @date('c', $dateIntervalArray[1]), "\n";
+}
+*/
+
+function _dateFloor($isoDate) {
+ $x = explode('T', $isoDate, 2);
+ $t = isset($x[1]) ? str_pad($x[1], 6, '0') : '000000';
+ return str_pad($x[0], 8, '01') . 'T' . $t;
+}
+
+function _dateCeiling($isoDate) {
+ $x = explode('T', $isoDate, 2);
+ $t = isset($x[1]) && strlen($x[1]) > 1 ? str_pad($x[1], 6, '59') : '235959';
+ switch (strlen($x[0])) {
+ case 4:
+ return $x[0] . '1231T' . $t;
+ case 6:
+ $d = @strtotime($x[0] . '01');
+ return $x[0] . date('t', $d) . 'T' . $t;
+ default:
+ return $x[0] . 'T' . $t;
+ }
+}
+
+function _noDelimit($isoDate) {
+ return $isoDate === null || $isoDate === '' ? null :
+ str_replace(array('-', ':'), '', $isoDate); //FIXME: Bug with negative time zone
+}
+
+function _dateRelative($d1, $d2) {
+ if ($d2 === null) {
+ return $d1 !== null && $d1[0] !== 'P' ? $d1 : null;
+ } elseif ($d2 !== '' && $d2[0] != 'P' && $d1 !== null && $d1[0] !== 'P') {
+ $y2 = substr($d2, 0, 4);
+ if (strlen($y2) < 4 || !ctype_digit($y2)) { //Does not start by a year
+ $d2 = _noDelimit($d2);
+ return substr($d1, 0, -strlen($d2)) . $d2; //Add prefix from $d1
+ }
+ }
+ return _noDelimit($d2);
+}
+
+/**
+ * Parameter $dateInterval is a string containing an ISO 8601 time interval.
+ * Returns an array with the minimum and maximum Unix timestamp of this interval,
+ * or null if open interval, or false if error.
+ */
+function parseDateInterval($dateInterval) {
+ $dateInterval = trim($dateInterval);
+ $dateInterval = str_replace('--', '/', $dateInterval);
+ $dateInterval = strtoupper($dateInterval);
+ $min = null;
+ $max = null;
+ $x = explode('/', $dateInterval, 2);
+ $d1 = _noDelimit($x[0]);
+ $d2 = _dateRelative($d1, count($x) > 1 ? $x[1] : null);
+ if ($d1 !== null && $d1[0] !== 'P') {
+ $min = @strtotime(_dateFloor($d1));
+ }
+ if ($d2 !== null) {
+ if ($d2[0] === 'P') {
+ try {
+ $di2 = new DateInterval($d2);
+ $dt1 = @date_create(); //new DateTime() would create an Exception if the default time zone is not defined
+ if ($min !== null && $min !== false) {
+ $dt1->setTimestamp($min);
+ }
+ $max = $dt1->add($di2)->getTimestamp() - 1;
+ } catch (Exception $e) {
+ $max = false;
+ }
+ } elseif ($d1 === null || $d1[0] !== 'P') {
+ $max = @strtotime(_dateCeiling($d2));
+ } else {
+ $max = @strtotime($d2);
+ }
+ }
+ if ($d1 !== null && $d1[0] === 'P') {
+ try {
+ $di1 = new DateInterval($d1);
+ $dt2 = @date_create();
+ if ($max !== null && $max !== false) {
+ $dt2->setTimestamp($max);
+ }
+ $min = $dt2->sub($di1)->getTimestamp() + 1;
+ } catch (Exception $e) {
+ $min = false;
+ }
+ }
+ return array($min, $max);
+}
diff --git a/lib/lib_opml.php b/lib/lib_opml.php
new file mode 100644
index 000000000..16a9921ea
--- /dev/null
+++ b/lib/lib_opml.php
@@ -0,0 +1,231 @@
+<?php
+
+/* *
+ * lib_opml is a free library to manage OPML format in PHP.
+ * It takes in consideration only version 2.0 (http://dev.opml.org/spec2.html).
+ * Basically it means "text" attribute for outline elements is required.
+ *
+ * lib_opml requires SimpleXML (http://php.net/manual/en/book.simplexml.php)
+ *
+ * Usages:
+ * > include('lib_opml.php');
+ * > $filename = 'my_opml_file.xml';
+ * > $opml_array = libopml_parse_file($filename);
+ * > print_r($opml_array);
+ *
+ * > $opml_string = [...];
+ * > $opml_array = libopml_parse_string($opml_string);
+ * > print_r($opml_array);
+ *
+ * > $opml_array = [...];
+ * > $opml_string = libopml_render($opml_array);
+ * > $opml_object = libopml_render($opml_array, true);
+ * > echo $opml_string;
+ * > print_r($opml_object);
+ *
+ * If parsing fails for any reason (e.g. not an XML string, does not match with
+ * the specifications), a LibOPML_Exception is raised.
+ *
+ * Author: Marien Fressinaud <dev@marienfressinaud.fr>
+ * Url: https://github.com/marienfressinaud/lib_opml
+ * Version: 0.1
+ * Date: 2014-03-29
+ * License: public domain
+ *
+ * */
+
+class LibOPML_Exception extends Exception {}
+
+
+// These elements are optional
+define('HEAD_ELEMENTS', serialize(array(
+ 'title', 'dateCreated', 'dateModified', 'ownerName', 'ownerEmail',
+ 'ownerId', 'docs', 'expansionState', 'vertScrollState', 'windowTop',
+ 'windowLeft', 'windowBottom', 'windowRight'
+)));
+
+
+function libopml_parse_outline($outline_xml) {
+ $outline = array();
+
+ // An outline may contain any kind of attributes but "text" attribute is
+ // required !
+ $text_is_present = false;
+ foreach ($outline_xml->attributes() as $key => $value) {
+ $outline[$key] = (string)$value;
+
+ if ($key === 'text') {
+ $text_is_present = true;
+ }
+ }
+
+ if (!$text_is_present) {
+ throw new LibOPML_Exception(
+ 'Outline does not contain any text attribute'
+ );
+ }
+
+ foreach ($outline_xml->children() as $key => $value) {
+ // An outline may contain any number of outline children
+ if ($key === 'outline') {
+ $outline['@outlines'][] = libopml_parse_outline($value);
+ } else {
+ throw new LibOPML_Exception(
+ 'Body can contain only outline elements'
+ );
+ }
+ }
+
+ return $outline;
+}
+
+
+function libopml_parse_string($xml) {
+ $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 LibOPML_Exception();
+ }
+
+ $array = array(
+ 'version' => (string)$opml['version'],
+ 'head' => array(),
+ 'body' => array()
+ );
+
+ // First, we get all "head" elements. Head is required but its sub-elements
+ // are optional.
+ foreach ($opml->head->children() as $key => $value) {
+ if (in_array($key, unserialize(HEAD_ELEMENTS), true)) {
+ $array['head'][$key] = (string)$value;
+ } else {
+ throw new LibOPML_Exception(
+ $key . 'is not part of OPML format'
+ );
+ }
+ }
+
+ // Then, we get body oulines. Body must contain at least one outline
+ // element.
+ $at_least_one_outline = false;
+ foreach ($opml->body->children() as $key => $value) {
+ if ($key === 'outline') {
+ $at_least_one_outline = true;
+ $array['body'][] = libopml_parse_outline($value);
+ } else {
+ throw new LibOPML_Exception(
+ 'Body can contain only outline elements'
+ );
+ }
+ }
+
+ if (!$at_least_one_outline) {
+ throw new LibOPML_Exception(
+ 'Body must contain at least one outline element'
+ );
+ }
+
+ return $array;
+}
+
+
+function libopml_parse_file($filename) {
+ $file_content = file_get_contents($filename);
+
+ if ($file_content === false) {
+ throw new LibOPML_Exception(
+ $filename . ' cannot be found'
+ );
+ }
+
+ return libopml_parse_string($file_content);
+}
+
+
+function libopml_render_outline($parent_elt, $outline) {
+ // Outline MUST be an array!
+ if (!is_array($outline)) {
+ throw new LibOPML_Exception(
+ 'Outline element must be defined as array'
+ );
+ }
+
+ $outline_elt = $parent_elt->addChild('outline');
+ $text_is_present = false;
+ foreach ($outline as $key => $value) {
+ // Only outlines can be an array and so we consider children are also
+ // outline elements.
+ if ($key === '@outlines' && is_array($value)) {
+ foreach ($value as $outline_child) {
+ libopml_render_outline($outline_elt, $outline_child);
+ }
+ } elseif (is_array($value)) {
+ throw new LibOPML_Exception(
+ 'Type of outline elements cannot be array: ' . $key
+ );
+ } else {
+ // Detect text attribute is present, that's good :)
+ if ($key === 'text') {
+ $text_is_present = true;
+ }
+
+ $outline_elt->addAttribute($key, $value);
+ }
+ }
+
+ if (!$text_is_present) {
+ throw new LibOPML_Exception(
+ 'You must define at least a text element for all outlines'
+ );
+ }
+}
+
+
+function libopml_render($array, $as_xml_object = false) {
+ $opml = new SimpleXMLElement('<opml version="2.0"></opml>');
+
+ // Create head element. $array['head'] is optional but head element will
+ // exist in the final XML object.
+ $head = $opml->addChild('head');
+ if (isset($array['head'])) {
+ foreach ($array['head'] as $key => $value) {
+ if (in_array($key, unserialize(HEAD_ELEMENTS), true)) {
+ $head->addChild($key, $value);
+ }
+ }
+ }
+
+ // Check body is set and contains at least one element
+ if (!isset($array['body'])) {
+ throw new LibOPML_Exception(
+ '$array must contain a body element'
+ );
+ }
+ if (count($array['body']) <= 0) {
+ throw new LibOPML_Exception(
+ 'Body element must contain at least one element (array)'
+ );
+ }
+
+ // Create outline elements
+ $body = $opml->addChild('body');
+ foreach ($array['body'] as $outline) {
+ libopml_render_outline($body, $outline);
+ }
+
+ // And return the final result
+ if ($as_xml_object) {
+ return $opml;
+ } else {
+ $dom = dom_import_simplexml($opml)->ownerDocument;
+ $dom->formatOutput = true;
+ $dom->encoding = 'UTF-8';
+ return $dom->saveXML();
+ }
+}
diff --git a/lib/lib_phpQuery.php b/lib/lib_phpQuery.php
index 4aefb70fe..194efa0c6 100644
--- a/lib/lib_phpQuery.php
+++ b/lib/lib_phpQuery.php
@@ -280,7 +280,7 @@ class DOMDocumentWrapper {
// @see http://www.w3.org/International/O-HTTP-charset
if (! $documentCharset) {
$documentCharset = 'ISO-8859-1';
- $addDocumentCharset = true;
+ $addDocumentCharset = true;
}
// Should be careful here, still need 'magic encoding detection' since lots of pages have other 'default encoding'
// Worse, some pages can have mixed encodings... we'll try not to worry about that
@@ -567,7 +567,7 @@ class DOMDocumentWrapper {
// if ($fake === false)
// throw new Exception("Error loading documentFragment markup");
// else
-// $return = array_merge($return,
+// $return = array_merge($return,
// $this->import($fake->root->childNodes)
// );
// } else {
@@ -969,24 +969,24 @@ interface ICallbackNamed {
}
/**
* Callback class introduces currying-like pattern.
- *
+ *
* Example:
* function foo($param1, $param2, $param3) {
* var_dump($param1, $param2, $param3);
* }
- * $fooCurried = new Callback('foo',
- * 'param1 is now statically set',
+ * $fooCurried = new Callback('foo',
+ * 'param1 is now statically set',
* new CallbackParam, new CallbackParam
* );
* phpQuery::callbackRun($fooCurried,
* array('param2 value', 'param3 value'
* );
- *
- * Callback class is supported in all phpQuery methods which accepts callbacks.
+ *
+ * Callback class is supported in all phpQuery methods which accepts callbacks.
*
* @link http://code.google.com/p/phpquery/wiki/Callbacks#Param_Structures
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
- *
+ *
* @TODO??? return fake forwarding function created via create_function
* @TODO honor paramStructure
*/
@@ -995,7 +995,7 @@ class Callback
public $callback = null;
public $params = null;
protected $name;
- public function __construct($callback, $param1 = null, $param2 = null,
+ public function __construct($callback, $param1 = null, $param2 = null,
$param3 = null) {
$params = func_get_args();
$params = array_slice($params, 1);
@@ -1024,11 +1024,11 @@ class Callback
}
/**
* Shorthand for new Callback(create_function(...), ...);
- *
+ *
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
*/
class CallbackBody extends Callback {
- public function __construct($paramList, $code, $param1 = null, $param2 = null,
+ public function __construct($paramList, $code, $param1 = null, $param2 = null,
$param3 = null) {
$params = func_get_args();
$params = array_slice($params, 2);
@@ -1038,7 +1038,7 @@ class CallbackBody extends Callback {
}
/**
* Callback type which on execution returns reference passed during creation.
- *
+ *
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
*/
class CallbackReturnReference extends Callback
@@ -1060,7 +1060,7 @@ class CallbackReturnReference extends Callback
}
/**
* Callback type which on execution returns value passed during creation.
- *
+ *
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
*/
class CallbackReturnValue extends Callback
@@ -1087,7 +1087,7 @@ class CallbackReturnValue extends Callback
}
/**
* CallbackParameterToReference can be used when we don't really want a callback,
- * only parameter passed to it. CallbackParameterToReference takes first
+ * only parameter passed to it. CallbackParameterToReference takes first
* parameter's value and passes it to reference.
*
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com>
@@ -1095,7 +1095,7 @@ class CallbackReturnValue extends Callback
class CallbackParameterToReference extends Callback {
/**
* @param $reference
- * @TODO implement $paramIndex;
+ * @TODO implement $paramIndex;
* param index choose which callback param will be passed to reference
*/
public function __construct(&$reference){
@@ -2994,7 +2994,7 @@ class phpQueryObject
}
/**
* Enter description here...
- *
+ *
* @param $code
* @return unknown_type
*/
@@ -3005,7 +3005,7 @@ class phpQueryObject
}
/**
* Enter description here...
- *
+ *
* @param $code
* @return unknown_type
*/
@@ -4034,7 +4034,7 @@ class phpQueryObject
}
/**
* Enter description here...
- *
+ *
* @param <type> $key
* @param <type> $value
*/
@@ -4051,7 +4051,7 @@ class phpQueryObject
}
/**
* Enter description here...
- *
+ *
* @param <type> $key
*/
public function removeData($key) {
@@ -4392,8 +4392,8 @@ if (!function_exists('mb_substr_count'))
*/
abstract class phpQuery {
/**
- * XXX: Workaround for mbstring problems
- *
+ * XXX: Workaround for mbstring problems
+ *
* @var bool
*/
public static $mbstringSupport = true;
diff --git a/lib/lib_rss.php b/lib/lib_rss.php
index 41e95fc90..31c9cdbc1 100644
--- a/lib/lib_rss.php
+++ b/lib/lib_rss.php
@@ -1,208 +1,246 @@
<?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);
+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 get_domain ($url) {
- return parse_url($url, PHP_URL_HOST);
+function formatBytes($bytes, $precision = 2, $system = 'IEC') {
+ if ($system === 'IEC') {
+ $base = 1024;
+ $units = array('B', 'KiB', 'MiB', 'GiB', 'TiB');
+ } elseif ($system === 'SI') {
+ $base = 1000;
+ $units = array('B', 'KB', 'MB', 'GB', 'TB');
+ }
+ $bytes = max(intval($bytes), 0);
+ $pow = $bytes === 0 ? 0 : floor(log($bytes) / log($base));
+ $pow = min($pow, count($units) - 1);
+ $bytes /= pow($base, $pow);
+ return formatNumber($bytes, $precision) . ' ' . $units[$pow];
}
-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 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 $txt;
-}
-function cleanText ($text) {
- return preg_replace ('/&[\w]+;/', '', $text);
+ return @date ($date, $t);
}
-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 ()));
- }
+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 {
- // Flux rss sans catégorie, on récupère l'ajoute dans la catégorie par défaut
- $feeds[] = getFeed ($outline, $defCat->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 array ($categories, $feeds);
+ return strtr($text, $htmlEntitiesOnly);
}
-/**
- * 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 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(800);
+ $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' => '', 'postpone' => ''), //http://www.w3.org/TR/resource-priorities/
+ 'audio' => array('lazyload' => '', 'postpone' => '', 'preload' => 'none'),
+ 'iframe' => array('lazyload' => '', 'postpone' => '', 'sandbox' => 'allow-scripts allow-same-origin'),
+ 'video' => array('lazyload' => '', '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';
+/**
+ * Add support of image lazy loading
+ * Move content from src attribute to data-original
+ * @param content is the text we want to parse
+ */
+function lazyimg($content) {
+ return preg_replace(
+ '/<((?:img|iframe)[^>]+?)src=[\'"]([^"\']+)[\'"]([^>]*)>/i',
+ '<$1src="' . Minz_Url::display('/themes/icons/grey.gif') . '" data-original="$2"$3>',
+ $content
+ );
+}
- if (!is_dir ($favicons_dir)) {
- if (!mkdir ($favicons_dir, 0755, true)) {
- return $url;
- }
+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() {
+ Minz_Session::_param('touch', uTimeString());
+ return touch(LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log');
+}
+
+function usernameFromPath($userPath) {
+ if (preg_match('%/([A-Za-z0-9]{1,16})_user\.php$%', $userPath, $matches)) {
+ return $matches[1];
+ } else {
+ return '';
}
+}
- 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;
- }
+function listUsers() {
+ return array_map('usernameFromPath', glob(DATA_PATH . '/*_user.php'));
+}
- curl_close ($c);
+function httpAuthUser() {
+ return isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : '';
+}
+
+function cryptAvailable() {
+ if (version_compare(PHP_VERSION, '5.3.3', '>=')) {
+ try {
+ $hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
+ return $hash === @crypt('password', $hash);
+ } catch (Exception $e) {
+ }
}
+ return false;
+}
- return $favicon_url;
+function is_referer_from_same_domain() {
+ if (empty($_SERVER['HTTP_REFERER'])) {
+ return false;
+ }
+ $host = parse_url(((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? 'https://' : 'http://') .
+ (empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST']));
+ $referer = parse_url($_SERVER['HTTP_REFERER']);
+ if (empty($host['scheme']) || empty($referer['scheme']) || $host['scheme'] !== $referer['scheme'] ||
+ empty($host['host']) || empty($referer['host']) || $host['host'] !== $referer['host']) {
+ return false;
+ }
+ return (isset($host['port']) ? $host['port'] : 0) === (isset($referer['port']) ? $referer['port'] : 0);
}
diff --git a/lib/lib_text.php b/lib/lib_text.php
deleted file mode 100644
index 9792e191e..000000000
--- a/lib/lib_text.php
+++ /dev/null
@@ -1,96 +0,0 @@
-<?php
-
-function bbDecode($string) {
-
- $find = array(
- "'\[b\](.*?)\[/b\]'is",
- "'\[u\](.*?)\[/u\]'is",
- "'\[i\](.*?)\[/i\]'is",
- "'\[s\](.*?)\[/s\]'is",
- "'\[code\](.*?)\[/code\]'is",
- "'\[quote\](.*?)\[/quote\]'is",
- "'\[quote=(.*?)\](.*?)\[/quote\]'is",
- "'\[span=(.*?)\](.*?)\[/span\]'i",
- "'\[div=(.*?)\](.*?)\[/div\]'is",
- "'\[h\](.*?)\[/h\]'i",
- "'\[url\](.*?)\[/url\]'i",
- "'\[url=(.*?)\](.*?)\[/url\]'i",
- "'\[video\](.*?)\[/video\]'i",
- "'\[video width=(.*?) height=(.*?)\](.*?)\[/video\]'i",
- "'\[img\](.*?)\[/img\]'i",
- "'\[img title=(.*?) rel=(.*?)\](.*?)\[/img\]'i",
- "'\[img title=(.*?)\](.*?)\[/img\]'i",
- );
-
- $replace = array(
- "<strong>\\1</strong>",
- "<u>\\1</u>",
- "<i>\\1</i>",
- "<del>\\1</del>",
- "<pre>\\1</pre>",
- "<q>\\1</q>",
- "<q><span class=\"cite\">\\1 a écrit</span><br />\\2</q>",
- "<span class=\"\\1\">\\2</span>",
- "<div class=\"\\1\">\\2</div>",
- "<b>\\1</b><br />",
- "<a href=\"\\1\">\\1</a>",
- "<a href=\"\\1\">\\2</a>",
- "<object width=\"480\" height=\"387\" class=\"center\"><param name=\"movie\" value=\"\\1\"></param><embed src=\"\\1\" type=\"application/x-shockwave-flash\" width=\"480\" height=\"387\"></embed></object>",
- "<object width=\"\\1\" height=\"\\2\" class=\"center\"><param name=\"movie\" value=\"\\3\"></param><embed src=\"\\3\" type=\"application/x-shockwave-flash\" width=\"\\1\" height=\"\\2\"></embed></object>",
- "<a href=\"\\1\" rel=\"prettyPhoto\"><img src=\"\\1\" alt=\"\" /></a>",
- "<img class=\"illustration\" src=\"\\3\" alt=\"\\1\" />",
- "<img src=\"\\2\" alt=\"\\1\" />",
- );
-
- $string = makeLinks(preg_replace ($find, $replace, $string));
- $string = nl2brPlus ($string);
-
- return $string;
-}
-
-// do nl2br except when in a <pre> tag
-function nl2brPlus($string) {
- $string = str_replace("\n", "<br />", $string);
- if(preg_match_all('/\<pre\>(.*?)\<\/pre\>/', $string, $match)){
- foreach($match as $a){
- foreach($a as $b){
- $string = str_replace('<pre>'.$b.'</pre>', "<pre>".str_replace("<br />", "", $b)."</pre>", $string);
- }
- }
- }
- return $string;
-}
-
-# Transform URL and e-mails into links
-function makeLinks($string) {
- $string = preg_replace_callback('/\s(http|https|ftp):(\/\/){0,1}([^\"\s]*)/i','splitUri',$string);
- return $string;
-}
-
-# Split links, require for makeLinks
-function splitUri($matches) {
- $uri = $matches[1].':'.$matches[2].$matches[3];
- $t = parse_url($uri);
- $link = $matches[3];
-
- if (!empty($t['scheme'])) {
- return ' <a href="'.$uri.'">'.$link.'</a>';
- } else {
- return $uri;
- }
-}
-
-// parse la description pour ajouter les liens sur les tags
-function parse_tags ($desc) {
- $desc_parse = preg_replace ('/#([\w\dÀÇÈÉÊËÎÏÔÙÚÛÜàáâçèéêëîïóùúûü]+)/i', '<a class="linktag" href="?addtag=\\1">\\1</a>', $desc);
-
- return $desc_parse;
-}
-
-function lazyimg($content) {
- return preg_replace(
- '/<img([^<]+)src=([\'"])([^"\']*)([\'"])([^<]*)>/i',
- '<img$1src="' . Url::display('/data/grey.gif') . '" data-original="$3"$5>',
- $content
- );
-} \ No newline at end of file
diff --git a/lib/minz/Cache.php b/lib/minz/Cache.php
deleted file mode 100644
index 6848e3350..000000000
--- a/lib/minz/Cache.php
+++ /dev/null
@@ -1,116 +0,0 @@
-<?php
-/**
- * MINZ - Copyright 2011 Marien Fressinaud
- * Sous licence AGPL3 <http://www.gnu.org/licenses/>
-*/
-
-/**
- * La classe Cache permet de gérer facilement les pages en cache
- */
-class Minz_Cache {
- /**
- * $expire timestamp auquel expire le cache de $url
- */
- private $expire = 0;
-
- /**
- * $file est le nom du fichier de cache
- */
- private $file = '';
-
- /**
- * $enabled permet de déterminer si le cache est activé
- */
- private static $enabled = true;
-
- /**
- * Constructeur
- */
- public function __construct () {
- $this->_fileName ();
- $this->_expire ();
- }
-
- /**
- * Setteurs
- */
- public function _fileName () {
- $file = md5 (Request::getURI ());
-
- $this->file = CACHE_PATH . '/'.$file;
- }
-
- public function _expire () {
- if ($this->exist ()) {
- $this->expire = filemtime ($this->file)
- + Configuration::delayCache ();
- }
- }
-
- /**
- * Permet de savoir si le cache est activé
- * @return true si activé, false sinon
- */
- public static function isEnabled () {
- return Configuration::cacheEnabled () && self::$enabled;
- }
-
- /**
- * Active / désactive le cache
- */
- public static function switchOn () {
- self::$enabled = true;
- }
- public static function switchOff () {
- self::$enabled = false;
- }
-
- /**
- * Détermine si le cache de $url a expiré ou non
- * @return true si il a expiré, false sinon
- */
- public function expired () {
- return time () > $this->expire;
- }
-
- /**
- * Affiche le contenu du cache
- * @print le code html du cache
- */
- public function render () {
- if ($this->exist ()) {
- include ($this->file);
- }
- }
-
- /**
- * Enregistre $html en cache
- * @param $html le html à mettre en cache
- */
- public function cache ($html) {
- file_put_contents ($this->file, $html);
- }
-
- /**
- * Permet de savoir si le cache existe
- * @return true si il existe, false sinon
- */
- public function exist () {
- return file_exists ($this->file);
- }
-
- /**
- * Nettoie le cache en supprimant tous les fichiers
- */
- public static function clean () {
- $files = opendir (CACHE_PATH);
-
- while ($fic = readdir ($files)) {
- if ($fic != '.' && $fic != '..') {
- unlink (CACHE_PATH.'/'.$fic);
- }
- }
-
- closedir ($files);
- }
-}
diff --git a/lib/minz/Configuration.php b/lib/minz/Configuration.php
deleted file mode 100755
index ad6df1bcf..000000000
--- a/lib/minz/Configuration.php
+++ /dev/null
@@ -1,242 +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';
-
- /**
- * 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 (BadConfigurationException $e) {
- throw $e;
- } catch (FileNotExistException $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
- );
-
- // [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/Dispatcher.php b/lib/minz/Dispatcher.php
deleted file mode 100644
index 0cfdd8e75..000000000
--- a/lib/minz/Dispatcher.php
+++ /dev/null
@@ -1,152 +0,0 @@
-<?php
-/**
- * MINZ - Copyright 2011 Marien Fressinaud
- * Sous licence AGPL3 <http://www.gnu.org/licenses/>
-*/
-
-/**
- * Le Dispatcher s'occupe d'initialiser le Controller et d'executer l'action
- * déterminée dans la Request
- * C'est un singleton
- */
-class Dispatcher {
- const CONTROLLERS_PATH_NAME = '/controllers';
-
- /* singleton */
- private static $instance = null;
-
- private $router;
- private $controller;
-
- /**
- * Récupère l'instance du Dispatcher
- */
- public static function getInstance ($router) {
- if (is_null (self::$instance)) {
- self::$instance = new Dispatcher ($router);
- }
- return self::$instance;
- }
-
- /**
- * Constructeur
- */
- private function __construct ($router) {
- $this->router = $router;
- }
-
- /**
- * Lance le controller indiqué dans Request
- * Remplit le body de Response à partir de la Vue
- * @exception MinzException
- */
- public function run () {
- $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 (Minz_Cache::isEnabled () && !$cache->expired ()) {
- ob_start ();
- $cache->render ();
- $text = ob_get_clean();
- } else {
- while (Request::$reseted) {
- Request::$reseted = false;
-
- try {
- $this->createController (
- Request::controllerName ()
- . 'Controller'
- );
-
- $this->controller->init ();
- $this->controller->firstAction ();
- $this->launchAction (
- Request::actionName ()
- . 'Action'
- );
- $this->controller->lastAction ();
-
- if (!Request::$reseted) {
- ob_start ();
- $this->controller->view ()->build ();
- $text = ob_get_clean();
- }
- } catch (MinzException $e) {
- throw $e;
- }
- }
-
- if (Minz_Cache::isEnabled ()) {
- $cache->cache ($text);
- }
- }
-
- 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
- */
- private function createController ($controller_name) {
- $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 (
- $controller_name,
- MinzException::ERROR
- );
- }
- $this->controller = new $controller_name ($this->router);
-
- if (! ($this->controller instanceof ActionController)) {
- throw new ControllerNotActionControllerException (
- $controller_name,
- MinzException::ERROR
- );
- }
- }
-
- /**
- * 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
- */
- private function launchAction ($action_name) {
- if (!Request::$reseted) {
- if (!is_callable (array (
- $this->controller,
- $action_name
- ))) {
- throw new ActionException (
- get_class ($this->controller),
- $action_name,
- MinzException::ERROR
- );
- }
- call_user_func (array (
- $this->controller,
- $action_name
- ));
- }
- }
-}
diff --git a/lib/minz/FrontController.php b/lib/minz/FrontController.php
deleted file mode 100755
index 84e7a07e1..000000000
--- a/lib/minz/FrontController.php
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-# ***** 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
- * Elle est appelée en général dans le fichier index.php à la racine du serveur
- */
-class FrontController {
- protected $dispatcher;
- protected $router;
-
- /**
- * Constructeur
- * Initialise le router et le dispatcher
- */
- public function __construct () {
- $this->loadLib ();
-
- if (LOG_PATH === false) {
- $this->killApp ('Path doesn\'t exist : LOG_PATH');
- }
-
- try {
- Configuration::init ();
-
- Request::init ();
-
- $this->router = new Router ();
- $this->router->init ();
- } catch (RouteNotFoundException $e) {
- Minz_Log::record ($e->getMessage (), Minz_Log::ERROR);
- Error::error (
- 404,
- array ('error' => array ($e->getMessage ()))
- );
- } catch (MinzException $e) {
- Minz_Log::record ($e->getMessage (), Minz_Log::ERROR);
- $this->killApp ();
- }
-
- $this->dispatcher = Dispatcher::getInstance ($this->router);
- }
-
- /**
- * Inclue les fichiers de la librairie
- */
- private function loadLib () {
- require ('ActionController.php');
- require ('Cache.php');
- require ('Configuration.php');
- require ('Dispatcher.php');
- require ('Error.php');
- require ('Helper.php');
- require ('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');
- }
-
- /**
- * Démarre l'application (lance le dispatcher et renvoie la réponse
- */
- public function run () {
- try {
- $this->dispatcher->run ();
- Response::send ();
- } catch (MinzException $e) {
- Minz_Log::record ($e->getMessage (), Minz_Log::ERROR);
-
- if ($e instanceof FileNotExistException ||
- $e instanceof ControllerNotExistException ||
- $e instanceof ControllerNotActionControllerException ||
- $e instanceof ActionException) {
- Error::error (
- 404,
- array ('error' => array ($e->getMessage ())),
- true
- );
- } else {
- $this->killApp ();
- }
- }
- }
-
- /**
- * Permet d'arrêter le programme en urgence
- */
- private function killApp ($txt = '') {
- if ($txt == '') {
- $txt = 'See logs files';
- }
- exit ('### Application problem ###'."\n".$txt);
- }
-}
diff --git a/lib/minz/Helper.php b/lib/minz/Helper.php
deleted file mode 100755
index 4f64ba218..000000000
--- a/lib/minz/Helper.php
+++ /dev/null
@@ -1,22 +0,0 @@
-<?php
-/**
- * MINZ - Copyright 2011 Marien Fressinaud
- * Sous licence AGPL3 <http://www.gnu.org/licenses/>
-*/
-
-/**
- * La classe Helper représente une aide pour des tâches récurrentes
- */
-class Helper {
- /**
- * Annule les effets des magic_quotes pour une variable donnée
- * @param $var variable à traiter (tableau ou simple variable)
- */
- public static function stripslashes_r ($var) {
- if (is_array ($var)){
- return array_map (array ('Helper', 'stripslashes_r'), $var);
- } else {
- return stripslashes($var);
- }
- }
-}
diff --git a/lib/minz/Request.php b/lib/minz/Request.php
deleted file mode 100644
index bde17f988..000000000
--- a/lib/minz/Request.php
+++ /dev/null
@@ -1,196 +0,0 @@
-<?php
-/**
- * MINZ - Copyright 2011 Marien Fressinaud
- * Sous licence AGPL3 <http://www.gnu.org/licenses/>
-*/
-
-/**
- * Request représente la requête http
- */
-class Request {
- private static $controller_name = '';
- private static $action_name = '';
- private static $params = array ();
-
- private static $default_controller_name = 'index';
- private static $default_action_name = 'index';
-
- public static $reseted = true;
-
- /**
- * Getteurs
- */
- public static function controllerName () {
- return self::$controller_name;
- }
- public static function actionName () {
- return self::$action_name;
- }
- public static function params () {
- return self::$params;
- }
- 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
- } else {
- return htmlspecialchars($p, ENT_NOQUOTES, 'UTF-8');
- }
- } else {
- return $default;
- }
- }
- public static function defaultControllerName () {
- return self::$default_controller_name;
- }
- public static function defaultActionName () {
- return self::$default_action_name;
- }
-
- /**
- * Setteurs
- */
- public static function _controllerName ($controller_name) {
- self::$controller_name = $controller_name;
- }
- public static function _actionName ($action_name) {
- self::$action_name = $action_name;
- }
- public static function _params ($params) {
- if (!is_array($params)) {
- $params = array ($params);
- }
-
- self::$params = $params;
- }
- public static function _param ($key, $value = false) {
- if ($value === false) {
- unset (self::$params[$key]);
- } else {
- self::$params[$key] = $value;
- }
- }
-
- /**
- * Initialise la Request
- */
- public static function init () {
- self::magicQuotesOff ();
- }
-
- /**
- * Retourn le nom de domaine du site
- */
- public static function getDomainName () {
- return $_SERVER['HTTP_HOST'];
- }
-
- /**
- * Détermine la base de l'url
- * @return la base de l'url
- */
- public static function getBaseUrl () {
- return Configuration::baseUrl ();
- }
-
- /**
- * Récupère l'URI de la requête
- * @return l'URI
- */
- public static function getURI () {
- if (isset ($_SERVER['REQUEST_URI'])) {
- $base_url = self::getBaseUrl ();
- $uri = $_SERVER['REQUEST_URI'];
-
- $len_base_url = strlen ($base_url);
- $real_uri = substr ($uri, $len_base_url);
- } else {
- $real_uri = '';
- }
-
- return $real_uri;
- }
-
- /**
- * Relance une requête
- * @param $url l'url vers laquelle est relancée la requête
- * @param $redirect si vrai, force la redirection http
- * > sinon, le dispatcher recharge en interne
- */
- public static function forward ($url = array (), $redirect = false) {
- $url = Url::checkUrl ($url);
-
- if ($redirect) {
- header ('Location: ' . Url::display ($url, 'php'));
- exit ();
- } else {
- self::$reseted = true;
-
- self::_controllerName ($url['c']);
- self::_actionName ($url['a']);
- self::_params (array_merge (
- self::$params,
- $url['params']
- ));
- }
- }
-
- /**
- * Permet de récupérer une variable de type $_GET
- * @param $param nom de la variable
- * @param $default valeur par défaut à attribuer à la variable
- * @return $_GET[$param]
- * $_GET si $param = false
- * $default si $_GET[$param] n'existe pas
- */
- public static function fetchGET ($param = false, $default = false) {
- if ($param === false) {
- return $_GET;
- } elseif (isset ($_GET[$param])) {
- return $_GET[$param];
- } else {
- return $default;
- }
- }
-
- /**
- * Permet de récupérer une variable de type $_POST
- * @param $param nom de la variable
- * @param $default valeur par défaut à attribuer à la variable
- * @return $_POST[$param]
- * $_POST si $param = false
- * $default si $_POST[$param] n'existe pas
- */
- public static function fetchPOST ($param = false, $default = false) {
- if ($param === false) {
- return $_POST;
- } elseif (isset ($_POST[$param])) {
- return $_POST[$param];
- } else {
- return $default;
- }
- }
-
- /**
- * Méthode désactivant les magic_quotes pour les variables
- * $_GET
- * $_POST
- * $_COOKIE
- */
- private static function magicQuotesOff () {
- if (get_magic_quotes_gpc ()) {
- $_GET = Helper::stripslashes_r ($_GET);
- $_POST = Helper::stripslashes_r ($_POST);
- $_COOKIE = Helper::stripslashes_r ($_COOKIE);
- }
- }
-
- public static function isPost () {
- return !empty ($_POST) || !empty ($_FILES);
- }
-}
-
-
diff --git a/lib/minz/Response.php b/lib/minz/Response.php
deleted file mode 100644
index fcf53c5b1..000000000
--- a/lib/minz/Response.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-/**
- * MINZ - Copyright 2011 Marien Fressinaud
- * Sous licence AGPL3 <http://www.gnu.org/licenses/>
-*/
-
-/**
- * Response représente la requête http renvoyée à l'utilisateur
- */
-class Response {
- private static $header = 'HTTP/1.0 200 OK';
- private static $body = '';
-
- /**
- * Mets à jour le body de la Response
- * @param $text le texte à incorporer dans le body
- */
- public static function setBody ($text) {
- self::$body = $text;
- }
-
- /**
- * Mets à jour le header de la Response
- * @param $code le code HTTP, valeurs possibles
- * - 200 (OK)
- * - 403 (Forbidden)
- * - 404 (Forbidden)
- * - 500 (Forbidden) -> par défaut si $code erroné
- * - 503 (Forbidden)
- */
- public static function setHeader ($code) {
- switch ($code) {
- case 200 :
- self::$header = 'HTTP/1.0 200 OK';
- break;
- case 403 :
- self::$header = 'HTTP/1.0 403 Forbidden';
- break;
- case 404 :
- self::$header = 'HTTP/1.0 404 Not Found';
- break;
- case 500 :
- self::$header = 'HTTP/1.0 500 Internal Server Error';
- break;
- case 503 :
- self::$header = 'HTTP/1.0 503 Service Unavailable';
- break;
- default :
- self::$header = 'HTTP/1.0 500 Internal Server Error';
- }
- }
-
- /**
- * Envoie la Response à l'utilisateur
- */
- public static function send () {
- header (self::$header);
- echo self::$body;
- }
-}
diff --git a/lib/minz/Router.php b/lib/minz/Router.php
deleted file mode 100755
index c5d6f5baa..000000000
--- a/lib/minz/Router.php
+++ /dev/null
@@ -1,209 +0,0 @@
-<?php
-/**
- * MINZ - Copyright 2011 Marien Fressinaud
- * Sous licence AGPL3 <http://www.gnu.org/licenses/>
-*/
-
-/**
- * La classe Router gère le routage de l'application
- * Les routes sont définies dans APP_PATH.'/configuration/routes.php'
- */
-class Router {
- const ROUTES_PATH_NAME = '/configuration/routes.php';
-
- private $routes = array ();
-
- /**
- * Constructeur
- * @exception FileNotExistException si ROUTES_PATH_NAME n'existe pas
- * et que l'on utilise l'url rewriting
- */
- public function __construct () {
- if (Configuration::useUrlRewriting ()) {
- if (file_exists (APP_PATH . self::ROUTES_PATH_NAME)) {
- $routes = include (
- APP_PATH . self::ROUTES_PATH_NAME
- );
-
- if (!is_array ($routes)) {
- $routes = array ();
- }
-
- $this->routes = array_map (
- array ('Url', 'checkUrl'),
- $routes
- );
- } else {
- throw new FileNotExistException (
- self::ROUTES_PATH_NAME,
- MinzException::ERROR
- );
- }
- }
- }
-
- /**
- * Initialise le Router en déterminant le couple Controller / Action
- * Mets à jour la Request
- * @exception RouteNotFoundException si l'uri n'est pas présente dans
- * > la table de routage
- */
- public function init () {
- $url = array ();
-
- if (Configuration::useUrlRewriting ()) {
- try {
- $url = $this->buildWithRewriting ();
- } catch (RouteNotFoundException $e) {
- throw $e;
- }
- } else {
- $url = $this->buildWithoutRewriting ();
- }
-
- $url['params'] = array_merge (
- $url['params'],
- Request::fetchPOST ()
- );
-
- Request::forward ($url);
- }
-
- /**
- * Retourne un tableau représentant l'url passée par la barre d'adresses
- * Ne se base PAS sur la table de routage
- * @return tableau représentant l'url
- */
- public function buildWithoutRewriting () {
- $url = array ();
-
- $url['c'] = Request::fetchGET (
- 'c',
- Request::defaultControllerName ()
- );
- $url['a'] = Request::fetchGET (
- 'a',
- Request::defaultActionName ()
- );
- $url['params'] = Request::fetchGET ();
-
- // post-traitement
- unset ($url['params']['c']);
- unset ($url['params']['a']);
-
- return $url;
- }
-
- /**
- * Retourne un tableau représentant l'url passée par la barre d'adresses
- * Se base sur la table de routage
- * @return tableau représentant l'url
- * @exception RouteNotFoundException si l'uri n'est pas présente dans
- * > la table de routage
- */
- public function buildWithRewriting () {
- $url = array ();
- $uri = Request::getURI ();
- $find = false;
-
- foreach ($this->routes as $route) {
- $regex = '*^' . $route['route'] . '$*';
- if (preg_match ($regex, $uri, $matches)) {
- $url['c'] = $route['controller'];
- $url['a'] = $route['action'];
- $url['params'] = $this->getParams (
- $route['params'],
- $matches
- );
- $find = true;
- break;
- }
- }
-
- if (!$find && $uri != '/') {
- throw new RouteNotFoundException (
- $uri,
- MinzException::ERROR
- );
- }
-
- // post-traitement
- $url = Url::checkUrl ($url);
-
- return $url;
- }
-
- /**
- * Retourne l'uri d'une url en se basant sur la table de routage
- * @param l'url sous forme de tableau
- * @return l'uri formatée (string) selon une route trouvée
- */
- public function printUriRewrited ($url) {
- $route = $this->searchRoute ($url);
-
- if ($route !== false) {
- return $this->replaceParams ($route, $url['params']);
- }
-
- return '';
- }
-
- /**
- * Recherche la route correspondante à une url
- * @param l'url sous forme de tableau
- * @return la route telle que spécifiée dans la table de routage,
- * false si pas trouvée
- */
- public function searchRoute ($url) {
- foreach ($this->routes as $route) {
- if ($route['controller'] == $url['c']
- && $route['action'] == $url['a']) {
- // calcule la différence des tableaux de params
- $params = array_flip ($route['params']);
- $difference_params = array_diff_key (
- $params,
- $url['params']
- );
-
- // vérifie que pas de différence
- // et le cas où $params est vide et pas $url['params']
- if (empty ($difference_params)
- && (!empty ($params) || empty ($url['params']))) {
- return $route;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Récupère un tableau dont
- * - les clés sont définies dans $params_route
- * - les valeurs sont situées dans $matches
- * Le tableau $matches est décalé de +1 par rapport à $params_route
- */
- private function getParams($params_route, $matches) {
- $params = array ();
-
- for ($i = 0; $i < count ($params_route); $i++) {
- $param = $params_route[$i];
- $params[$param] = $matches[$i + 1];
- }
-
- return $params;
- }
-
- /**
- * Remplace les éléments de la route par les valeurs contenues dans $params
- */
- private function replaceParams ($route, $params_replace) {
- $uri = $route['route'];
- $params = array();
- foreach($route['params'] as $param) {
- $uri = preg_replace('#\((.+)\)#U', $params_replace[$param], $uri, 1);
- }
-
- return stripslashes($uri);
- }
-}
diff --git a/lib/minz/Session.php b/lib/minz/Session.php
deleted file mode 100755
index f9c9c6754..000000000
--- a/lib/minz/Session.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-
-/**
- * La classe Session gère la session utilisateur
- * C'est un singleton
- */
-class Session {
- /**
- * $session stocke les variables de session
- */
- private static $session = array ();
-
- /**
- * Initialise la session
- */
- public static function init () {
- // démarre la session
- session_name (md5 (Configuration::selApplication ()));
- 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;
- }
-
-
- /**
- * Permet de créer ou mettre à jour une variable de session
- * @param $p le paramètre à créer ou modifier
- * @param $v la valeur à attribuer, false pour supprimer
- */
- public static function _param ($p, $v = false) {
- if ($v === false) {
- unset ($_SESSION[$p]);
- unset (self::$session[$p]);
- } 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 ();
- self::$session = array ();
-
- if (!$force) {
- self::_param ('language', $language);
- }
- }
-}
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_pdo.php b/lib/minz/dao/Model_pdo.php
deleted file mode 100755
index fa44038db..000000000
--- a/lib/minz/dao/Model_pdo.php
+++ /dev/null
@@ -1,58 +0,0 @@
-<?php
-/**
- * MINZ - Copyright 2011 Marien Fressinaud
- * Sous licence AGPL3 <http://www.gnu.org/licenses/>
-*/
-
-/**
- * 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 {
- /**
- * $bd variable représentant la base de données
- */
- 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
- */
- public function __construct () {
- $db = Configuration::dataBase ();
- $driver_options = null;
-
- try {
- $type = $db['type'];
- if($type == 'mysql') {
- $string = $type
- . ':host=' . $db['host']
- . ';dbname=' . $db['base']
- . ';charset=utf8';
- $driver_options = array(
- 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
- }
-
- $this->bd = new PDO (
- $string,
- $db['user'],
- $db['password'],
- $driver_options
- );
-
- $this->prefix = $db['prefix'];
- } catch (Exception $e) {
- throw new PDOConnectionException (
- $string,
- $db['user'], MinzException::WARNING
- );
- }
- }
-}
diff --git a/lib/minz/dao/Model_txt.php b/lib/minz/dao/Model_txt.php
deleted file mode 100755
index c9d5cfe77..000000000
--- a/lib/minz/dao/Model_txt.php
+++ /dev/null
@@ -1,77 +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;
- $this->file = @fopen ($this->filename, $mode);
-
- if (!$this->file) {
- throw new FileNotExistException (
- $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 8fca5ec16..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';
-
- 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);
+ }
+
+}