aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2019-08-20 14:55:43 +0200
committerGravatar GitHub <noreply@github.com> 2019-08-20 14:55:43 +0200
commitfd33d92d413acb5ee48e04d8a78f251e35ef06c5 (patch)
tree494f54d132e9b305ec91f5c8736b633bdedfb298 /lib
parent38a4b22f7bb2eb51c5224d2a340e199d6a280797 (diff)
Require PHP 5.5+ (#2495)
* Require PHP 5.5+ https://github.com/FreshRSS/FreshRSS/issues/2469#issuecomment-522255093 I think it would be reasonable to require PHP 5.5+ for the core of FreshRSS after all. As Frenzie said, WordPress currently requires PHP 5.6.20+, and it is the most popular PHP application. We would loose about 20% of the PHP servers according to https://w3techs.com/technologies/details/pl-php/5/all but I expect this number to drop fast after the release of CentOS 8 (CentOS accounts for 17% of Linux servers https://w3techs.com/technologies/details/os-linux/all/all ). Distributions: * no impact on Ubuntu, Fedora, Alpine, OpenWRT, FreeBSD, OpenSuze, Mageia, as all active versions have PHP > 7 * no impact on OpenSuze, Synology, as all active versions have PHP > 5.5 * we drop Debian 8 Jessie (-2020) - we keep supporting Debian 9 Stretch (2017-06) - current is Debian 10 Buster * we drop Red Hat 7 (-2024) - we keep supporting RHEL 8 (2019-05) * we drop CentOS 7 (-2024) - we will support CentOS 8 (to be released soonish) When dropping older versions, I can better like when it is for a good reason, and there is actually one with PHP 5.5, namely generators (yield) https://php.net/language.generators.overview which I consider using. * Version note for JSON.php * hex2bin * Update .travis.yml Co-Authored-By: Frans de Jonge <fransdejonge@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/Minz/Configuration.php2
-rw-r--r--lib/Minz/ModelArray.php2
-rw-r--r--lib/Minz/ModelPdo.php2
-rw-r--r--lib/lib_install.php2
-rw-r--r--lib/lib_rss.php32
-rw-r--r--lib/password_compat.php279
6 files changed, 13 insertions, 306 deletions
diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php
index aae3accc6..93f6b494c 100644
--- a/lib/Minz/Configuration.php
+++ b/lib/Minz/Configuration.php
@@ -198,7 +198,7 @@ class Minz_Configuration {
return false;
}
- // Clear PHP 5.5+ cache for include
+ // Clear PHP cache for include
if (function_exists('opcache_invalidate')) {
opcache_invalidate($this->config_filename);
}
diff --git a/lib/Minz/ModelArray.php b/lib/Minz/ModelArray.php
index 1ac2b313d..4938f4b1d 100644
--- a/lib/Minz/ModelArray.php
+++ b/lib/Minz/ModelArray.php
@@ -48,7 +48,7 @@ class Minz_ModelArray {
throw new Minz_PermissionDeniedException($this->filename);
}
if (function_exists('opcache_invalidate')) {
- opcache_invalidate($this->filename); //Clear PHP 5.5+ cache for include
+ opcache_invalidate($this->filename); //Clear PHP cache for include
}
return true;
}
diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php
index 733982c14..14510c983 100644
--- a/lib/Minz/ModelPdo.php
+++ b/lib/Minz/ModelPdo.php
@@ -103,7 +103,7 @@ class Minz_ModelPdo {
$this->bd->beginTransaction();
}
public function inTransaction() {
- return $this->bd->inTransaction(); //requires PHP >= 5.3.3
+ return $this->bd->inTransaction();
}
public function commit() {
$this->bd->commit();
diff --git a/lib/lib_install.php b/lib/lib_install.php
index 6e4df4e9c..6b9b33240 100644
--- a/lib/lib_install.php
+++ b/lib/lib_install.php
@@ -6,7 +6,7 @@ Minz_Configuration::register('default_system', join_path(FRESHRSS_PATH, 'config.
Minz_Configuration::register('default_user', join_path(FRESHRSS_PATH, 'config-user.default.php'));
function checkRequirements($dbType = '') {
- $php = version_compare(PHP_VERSION, '5.3.8') >= 0;
+ $php = version_compare(PHP_VERSION, '5.5.0') >= 0;
$minz = file_exists(join_path(LIB_PATH, 'Minz'));
$curl = extension_loaded('curl');
$pdo_mysql = extension_loaded('pdo_mysql');
diff --git a/lib/lib_rss.php b/lib/lib_rss.php
index c0ea23989..2706ff606 100644
--- a/lib/lib_rss.php
+++ b/lib/lib_rss.php
@@ -1,9 +1,9 @@
<?php
-if (version_compare(PHP_VERSION, '5.3.8', '<')) {
- die('FreshRSS error: FreshRSS requires PHP 5.3.8+!');
+if (version_compare(PHP_VERSION, '5.5.0', '<')) {
+ die('FreshRSS error: FreshRSS requires PHP 5.5.0+!');
}
-if (!function_exists('json_decode')) {
+if (!function_exists('json_decode')) { //PHP bug #63520 < PHP 7
require_once(__DIR__ . '/JSON.php');
function json_decode($var, $assoc = false) {
$JSON = new Services_JSON($assoc ? SERVICES_JSON_LOOSE_TYPE : 0);
@@ -19,8 +19,6 @@ if (!function_exists('json_encode')) {
}
}
-defined('JSON_UNESCAPED_UNICODE') or define('JSON_UNESCAPED_UNICODE', 256); //PHP 5.3
-
if (!function_exists('mb_strcut')) {
function mb_strcut($str, $start, $length = null, $encoding = 'UTF-8') {
return substr($str, $start, $length);
@@ -68,12 +66,7 @@ function idn_to_puny($url) {
$parts = parse_url($url);
if (!empty($parts['host'])) {
$idn = $parts['host'];
- // INTL_IDNA_VARIANT_UTS46 is defined starting in PHP 5.4
- if (defined('INTL_IDNA_VARIANT_UTS46')) {
- $puny = idn_to_ascii($idn, 0, INTL_IDNA_VARIANT_UTS46);
- } else {
- $puny = idn_to_ascii($idn);
- }
+ $puny = idn_to_ascii($idn, 0, INTL_IDNA_VARIANT_UTS46);
$pos = strpos($url, $idn);
if ($pos !== false) {
return substr_replace($url, $puny, $pos, strlen($idn));
@@ -187,17 +180,10 @@ function timestamptodate ($t, $hour = true) {
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 {
- $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
- )));
- }
+ $htmlEntitiesOnly = array_flip(array_diff(
+ get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES, 'UTF-8'), //Decode HTML entities
+ get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES, 'UTF-8') //Preserve XML entities
+ ));
}
return strtr($text, $htmlEntitiesOnly);
}
@@ -428,7 +414,7 @@ function check_install_php() {
$pdo_pgsql = extension_loaded('pdo_pgsql');
$pdo_sqlite = extension_loaded('pdo_sqlite');
return array(
- 'php' => version_compare(PHP_VERSION, '5.3.8') >= 0,
+ 'php' => version_compare(PHP_VERSION, '5.5.0') >= 0,
'minz' => file_exists(LIB_PATH . '/Minz'),
'curl' => extension_loaded('curl'),
'pdo' => $pdo_mysql || $pdo_sqlite || $pdo_pgsql,
diff --git a/lib/password_compat.php b/lib/password_compat.php
deleted file mode 100644
index e8ec02885..000000000
--- a/lib/password_compat.php
+++ /dev/null
@@ -1,279 +0,0 @@
-<?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);
- }
-
-}