Ver Fonte

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>
Alexandre Alapetite há 6 anos atrás
pai
commit
fd33d92d41

+ 1 - 6
.travis.yml

@@ -30,12 +30,7 @@ env:
 matrix:
   fast_finish: true
   include:
-    # PHP 5.3 only runs on Ubuntu 12.04 (precise), not 14.04 (trusty)
-    - php: "5.3"
-      dist: precise
-    # PHP 5.4 & 5.5 only run on Travis in 14.04 (trusty), not 16.04 (xenial)
-    - php: "5.4"
-      dist: trusty
+    # PHP 5.5 only runs on Travis in 14.04 (trusty), not 16.04 (xenial)
     - php: "5.5"
       dist: trusty
     - php: "7.2"

+ 1 - 2
README.fr.md

@@ -43,7 +43,7 @@ FreshRSS n’est fourni avec aucune garantie.
 * Serveur modeste, par exemple sous Linux ou Windows
 	* Fonctionne même sur un Raspberry Pi 1 avec des temps de réponse < 1s (testé sur 150 flux, 22k articles)
 * Serveur Web Apache2 (recommandé), ou nginx, lighttpd (non testé sur les autres)
-* PHP 5.3.8+ (PHP 5.4+ recommandé, et PHP 5.5+ pour les performances, ou PHP 7+ pour d’encore meilleures performances)
+* PHP 5.5+ (PHP 7+ recommandé pour de meilleures performances)
 	* Requis : [cURL](https://secure.php.net/curl), [DOM](https://secure.php.net/dom), [XML](https://secure.php.net/xml), [session](https://secure.php.net/session), [ctype](https://secure.php.net/ctype), et [PDO_MySQL](https://secure.php.net/pdo-mysql) ou [PDO_SQLite](https://secure.php.net/pdo-sqlite) ou [PDO_PGSQL](https://secure.php.net/pdo-pgsql)
 	* Recommandés : [JSON](https://secure.php.net/json), [GMP](https://secure.php.net/gmp) (pour accès API sur plateformes < 64 bits), [IDN](https://secure.php.net/intl.idn) (pour les noms de domaines internationalisés), [mbstring](https://secure.php.net/mbstring) (pour le texte Unicode), [iconv](https://secure.php.net/iconv) (pour conversion d’encodages), [ZIP](https://secure.php.net/zip) (pour import/export), [zlib](https://secure.php.net/zlib) (pour les flux compressés)
 * MySQL 5.5.3+ (recommandé) ou équivalent MariaDB, ou SQLite 3.7.4+, ou PostgreSQL 9.2+
@@ -219,7 +219,6 @@ Tout client supportant une API de type Fever ; Sélection :
 * [bcrypt.js](https://github.com/dcodeIO/bcrypt.js)
 * [phpQuery](https://github.com/phpquery/phpquery)
 * [Services_JSON](https://pear.php.net/pepr/pepr-proposal-show.php?id=198)
-* [password_compat](https://github.com/ircmaxell/password_compat)
 
 
 

+ 1 - 2
README.md

@@ -43,7 +43,7 @@ FreshRSS comes with absolutely no warranty.
 * Light server running Linux or Windows
 	* It even works on Raspberry Pi 1 with response time under a second (tested with 150 feeds, 22k articles)
 * A web server: Apache2 (recommended), nginx, lighttpd (not tested on others)
-* PHP 5.3.8+ (PHP 5.4+ recommended, and PHP 5.5+ for performance, or PHP 7 for even higher performance)
+* PHP 5.5+ (PHP 7+ recommended for higher performance)
 	* Required extensions: [cURL](https://secure.php.net/curl), [DOM](https://secure.php.net/dom), [XML](https://secure.php.net/xml), [session](https://secure.php.net/session), [ctype](https://secure.php.net/ctype), and [PDO_MySQL](https://secure.php.net/pdo-mysql) or [PDO_SQLite](https://secure.php.net/pdo-sqlite) or [PDO_PGSQL](https://secure.php.net/pdo-pgsql)
 	* Recommended extensions: [JSON](https://secure.php.net/json), [GMP](https://secure.php.net/gmp) (for API access on 32-bit platforms), [IDN](https://secure.php.net/intl.idn) (for Internationalized Domain Names), [mbstring](https://secure.php.net/mbstring) (for Unicode strings), [iconv](https://secure.php.net/iconv) (for charset conversion), [ZIP](https://secure.php.net/zip) (for import/export), [zlib](https://secure.php.net/zlib) (for compressed feeds)
 * MySQL 5.5.3+ (recommended) or MariaDB equivalent, or SQLite 3.7.4+, or PostgreSQL 9.2+
@@ -219,7 +219,6 @@ Supported clients are:
 * [bcrypt.js](https://github.com/dcodeIO/bcrypt.js)
 * [phpQuery](https://github.com/phpquery/phpquery)
 * [Services_JSON](https://pear.php.net/pepr/pepr-proposal-show.php?id=198)
-* [password_compat](https://github.com/ircmaxell/password_compat)
 
 [travis-badge]:https://travis-ci.org/FreshRSS/FreshRSS.svg?branch=master
 [travis-link]:https://travis-ci.org/FreshRSS/FreshRSS

+ 0 - 4
app/Controllers/authController.php

@@ -169,10 +169,6 @@ class FreshRSS_auth_Controller extends Minz_ActionController {
 				return;
 			}
 
-			if (!function_exists('password_verify')) {
-				include_once(LIB_PATH . '/password_compat.php');
-			}
-
 			$s = $conf->passwordHash;
 			$ok = password_verify($password, $s);
 			unset($password);

+ 0 - 3
app/Controllers/userController.php

@@ -9,9 +9,6 @@ class FreshRSS_user_Controller extends Minz_ActionController {
 	const BCRYPT_COST = 9;
 
 	public static function hashPassword($passwordPlain) {
-		if (!function_exists('password_hash')) {
-			include_once(LIB_PATH . '/password_compat.php');
-		}
 		$passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST));
 		$passwordPlain = '';
 		$passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash);	//Compatibility with bcrypt.js

+ 1 - 6
app/Models/Auth.php

@@ -219,10 +219,6 @@ class FreshRSS_FormAuth {
 			return false;
 		}
 
-		if (!function_exists('password_verify')) {
-			include_once(LIB_PATH . '/password_compat.php');
-		}
-
 		return password_verify($nonce . $hash, $challenge);
 	}
 
@@ -283,8 +279,7 @@ class FreshRSS_FormAuth {
 		$cookie_duration = empty($limits['cookie_duration']) ? 2592000 : $limits['cookie_duration'];
 		$oldest = time() - $cookie_duration;
 		foreach (new DirectoryIterator(DATA_PATH . '/tokens/') as $file_info) {
-			// $extension = $file_info->getExtension(); doesn't work in PHP < 5.3.7
-			$extension = pathinfo($file_info->getFilename(), PATHINFO_EXTENSION);
+			$extension = $file_info->getExtension();
 			if ($extension === 'txt' && $file_info->getMTime() < $oldest) {
 				@unlink($file_info->getPathname());
 			}

+ 2 - 2
app/Models/EntryDAO.php

@@ -191,7 +191,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
 			if ($this->hasNativeHex()) {
 				$this->addEntryPrepared->bindParam(':hash', $valuesTmp['hash']);
 			} else {
-				$valuesTmp['hashBin'] = pack('H*', $valuesTmp['hash']);	//hex2bin() is PHP5.4+
+				$valuesTmp['hashBin'] = hex2bin($valuesTmp['hash']);
 				$this->addEntryPrepared->bindParam(':hash', $valuesTmp['hashBin']);
 			}
 		}
@@ -273,7 +273,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
 		if ($this->hasNativeHex()) {
 			$this->updateEntryPrepared->bindParam(':hash', $valuesTmp['hash']);
 		} else {
-			$valuesTmp['hashBin'] = pack('H*', $valuesTmp['hash']);	//hex2bin() is PHP5.4+
+			$valuesTmp['hashBin'] = hex2bin($valuesTmp['hash']);
 			$this->updateEntryPrepared->bindParam(':hash', $valuesTmp['hashBin']);
 		}
 

+ 1 - 1
app/install.php

@@ -413,7 +413,7 @@ function printStep1() {
 	<?php if ($res['php'] == 'ok') { ?>
 	<p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.php.ok', PHP_VERSION); ?></p>
 	<?php } else { ?>
-	<p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.php.nok', PHP_VERSION, '5.3.8'); ?></p>
+	<p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.php.nok', PHP_VERSION, '5.5.0'); ?></p>
 	<?php } ?>
 
 	<?php if ($res['minz'] == 'ok') { ?>

+ 1 - 4
app/views/helpers/export/articles.phtml

@@ -1,10 +1,7 @@
 <?php
 $username = Minz_Session::param('currentUser', '_');
 
-$options = 0;
-if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
-	$options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
-}
+$options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
 
 $articles = array(
 	'id' => 'user/' . str_replace('/', '', $username) . '/state/org.freshrss/' . $this->type,

+ 1 - 1
app/views/update/checkInstall.phtml

@@ -9,7 +9,7 @@
 	<p class="alert <?php echo $status ? 'alert-success' : 'alert-error'; ?>">
 		<?php
 			if ($key === 'php') {
-				echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok'), PHP_VERSION, '5.3.8');
+				echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok'), PHP_VERSION, '5.5.0');
 			} else {
 				echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok'));
 			}

+ 1 - 5
docs/en/admins/02_Installation.md

@@ -7,15 +7,11 @@ You need to verify that your server can run FreshRSS before installing it. If yo
 | Software    | Recommended      | Works also with               |
 | ----------- | ---------------- | ----------------------------- |
 | Web server  | **Apache 2**     | Nginx                         |
-| PHP         | **PHP 5.5+**     | PHP 5.3.8+                    |
+| PHP         | **PHP 7+**       | PHP 5.5+                      |
 | PHP modules | Required: libxml, cURL, PDO_MySQL, PCRE and ctype. <br>Required (32-bit only): GMP <br> Recommanded: JSON, Zlib, mbstring, iconv, ZipArchive <br> *For the whole modules list see [Dockerfile](https://github.com/FreshRSS/FreshRSS/blob/744a9e8cf00aef7dec0acfa5f90f0dcfa2ef8837/Docker/Dockerfile-Alpine#L7-L9)* | |
 | Database    | **MySQL 5.5.3+** | SQLite 3.7.4+                 |
 | Browser     | **Firefox**      | Chrome, Opera, Safari, or IE11+ |
 
-## Important notice
-
-FreshRSS **CAN** work with PHP 5.3.8+. To do so, we are using specific functions available in the [''password_compat'' library](https://github.com/ircmaxell/password_compat#requirements) for the form authentication.
-
 
 # Getting the appropriate version of FreshRSS
 

+ 2 - 19
docs/en/developers/01_First_steps.md

@@ -148,26 +148,9 @@ abstract class ClassName {}
 
 Files must be encoded with UTF-8 character set.
 
-## PHP 5.3 compatibility
+## PHP compatibility
 
-Do not get an array item directly from a function or a method. Use a variable.
-
-```php
-// code with PHP 5.3 compatibility
-$my_variable = function_returning_an_array();
-echo $my_variable[0];
-// code without PHP 5.3 compatibility
-echo function_returning_an_array()[0];
-```
-
-Do not use short array declaration.
-
-```php
-// code with PHP 5.3 compatibility
-$variable = array();
-// code without PHP 5.3 compatibility
-$variable = [];
-```
+Ensure that your code is working with a PHP version as old as what FreshRSS officially supports.
 
 ## Miscellaneous
 

+ 1 - 1
docs/en/users/06_Mobile_access.md

@@ -29,7 +29,7 @@ See the [page about the Fever compatible API](06_Fever_API.md) for another possi
 	* If you get *Service Unavailable!*, then check from step 1 again.
 	* With __Apache__:
 		* If you get *FAIL getallheaders!*, the combination of your PHP version and your Web server does not provide access to [`getallheaders`](http://php.net/getallheaders)
-			* Update to PHP 5.4+, or use PHP as module instead of CGI. Otherwise turn on Apache `mod_setenvif` (often enabled by default), or `mod_rewrite` with the following procedure:
+			* Turn on Apache `mod_setenvif` (often enabled by default), or `mod_rewrite` with the following procedure:
 				* Allow [`FileInfo` in `.htaccess`](http://httpd.apache.org/docs/trunk/mod/core.html#allowoverride): see the [server setup](../admins/02_Installation.md) again.
 				* Enable [`mod_rewrite`](http://httpd.apache.org/docs/trunk/mod/mod_rewrite.html):
 					* With Debian / Ubuntu: `sudo a2enmod rewrite`

+ 2 - 19
docs/fr/developers/01_First_steps.md

@@ -148,26 +148,9 @@ abstract class NomDeLaClasse {}
 
 Les fichiers doivent être encodés en UTF-8.
 
-## Compatibilité avec PHP 5.3
+## Compatibilité PHP
 
-Il ne faut pas demander l'indice d'un tableau qui est retourné par une fonction ou une méthode. Il faut passer par une variable intermédiaire.
-
-```php
-// code compatible avec PHP 5.3
-$ma_variable = fonction_qui_retourne_un_tableau();
-echo $ma_variable[0];
-// code incompatible avec PHP 5.3
-echo fonction_qui_retourne_un_tableau()[0];
-```
-
-Il ne faut pas utiliser la déclaration raccourcie des tableaux.
-
-```php
-// code compatible avec PHP 5.3
-$variable = array();
-// code incompatible avec PHP 5.3
-$variable = [];
-```
+Assurez-vous que votre code fonctionne avec une version de PHP aussi ancienne que celle que FreshRSS supporte officiellement.
 
 ## Divers
 

+ 1 - 5
docs/fr/users/01_Installation.md

@@ -7,15 +7,11 @@ Il est toutefois de votre responsabilité de vérifier que votre hébergement pe
  | Logiciel         | Recommandé                                                                                                     | Fonctionne aussi avec          |
  | --------         | -----------                                                                                                    | ---------------------          |
  | Serveur web      | **Apache 2**                                                                                                   | Nginx                          |
- | PHP              | **PHP 5.5+**                                                                                                   | PHP 5.3.8+                     |
+ | PHP              | **PHP 7+**                                                                                                     | PHP 5.5+                       |
  | Modules PHP      | Requis : libxml, cURL, PDO_MySQL, PCRE et ctype<br>Requis (32 bits seulement) : GMP<br>Recommandé : JSON, Zlib, mbstring et iconv, ZipArchive<br>*Pour une liste complète des modules nécessaires voir le [Dockerfile](https://github.com/FreshRSS/FreshRSS/blob/744a9e8cf00aef7dec0acfa5f90f0dcfa2ef8837/Docker/Dockerfile-Alpine#L7-L9)* |                                |
  | Base de données  | **MySQL 5.5.3+**                                                                                               | SQLite 3.7.4+                  |
  | Navigateur       | **Firefox**                                                                                                    | Chrome, Opera, Safari, or IE 11+ |
 
-## Note importante
-
-FreshRSS **PEUT** fonctionner sur la version de PHP 5.3.8+. En effet, nous utilisons des fonctions spécifiques pour la connexion par formulaire et notamment la [bibliothèque ''password_compat''](https://github.com/ircmaxell/password_compat#requirements).
-
 # Choisir la bonne version de FreshRSS
 
 FreshRSS possède trois versions différentes (nous parlons de branches) qui sortent à des fréquences plus ou moins rapides. Aussi prenez le temps de comprendre à quoi correspond chacune de ces versions.

+ 1 - 1
docs/fr/users/06_Mobile_access.md

@@ -29,7 +29,7 @@ Voir la [page sur l’API compatible Fever](06_Fever_API.md) pour une autre poss
 	* Si vous obtenez *Service Unavailable!*, retourner à l’étape 6.
 	* Avec __Apache__:
 		* Si vous obtenez *FAIL getallheaders!*, alors la combinaison de votre version de PHP et de votre serveur Web ne permet pas l’accès à [`getallheaders`](http://php.net/getallheaders)
-			* Utilisez au moins PHP 5.4+, ou utilisez PHP en tant que module plutôt que CGI. Sinon, activer Apache `mod_setenvif` (souvent activé par défault), ou `mod_rewrite` avec la procédure suivante :
+			* Activer Apache `mod_setenvif` (souvent activé par défault), ou `mod_rewrite` avec la procédure suivante :
 				* Autoriser [`FileInfo` dans `.htaccess`](http://httpd.apache.org/docs/trunk/mod/core.html#allowoverride) : revoir [l’installation du serveur](01_Installation.md).
 				* Activer [`mod_rewrite`](http://httpd.apache.org/docs/trunk/mod/mod_rewrite.html) :
 					* Sur Debian / Ubuntu : `sudo a2enmod rewrite`

+ 1 - 1
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);
 		}

+ 1 - 1
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;
 	}

+ 1 - 1
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();

+ 1 - 1
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');

+ 9 - 23
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,

+ 0 - 279
lib/password_compat.php

@@ -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);
-   }
-
-}

+ 1 - 9
p/api/greader.php

@@ -43,11 +43,7 @@ if (PHP_INT_SIZE < 8) {	//32-bit
 	}
 }
 
-if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
-	define('JSON_OPTIONS', JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
-} else {
-	define('JSON_OPTIONS', 0);
-}
+define('JSON_OPTIONS', JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
 
 function headerVariable($headerName, $varName) {
 	$header = '';
@@ -182,10 +178,6 @@ function authorizationToUser() {
 
 function clientLogin($email, $pass) {	//http://web.archive.org/web/20130604091042/http://undoc.in/clientLogin.html
 	if (FreshRSS_user_Controller::checkUsername($email)) {
-		if (!function_exists('password_verify')) {
-			include_once(LIB_PATH . '/password_compat.php');
-		}
-
 		FreshRSS_Context::$user_conf = get_user_configuration($email);
 		if (FreshRSS_Context::$user_conf == null) {
 			Minz_Log::warning('Invalid API user ' . $email . ': configuration cannot be found.');

+ 0 - 1
phpcs.xml

@@ -10,7 +10,6 @@
 	<exclude-pattern>./lib/http-conditional.php</exclude-pattern>
 	<exclude-pattern>./lib/JSON.php</exclude-pattern>
 	<exclude-pattern>./lib/lib_phpQuery.php</exclude-pattern>
-	<exclude-pattern>./lib/password_compat.php</exclude-pattern>
 	<!-- Duplicate class names are not allowed -->
 	<rule ref="Generic.Classes.DuplicateClassName"/>
 	<!-- Statements must not be empty -->