]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
PHP: ensure 5.3 compatibility, refactor timezone utilities 271/head
authorVirtualTam <virtualtam@flibidi.net>
Fri, 10 Jul 2015 23:29:12 +0000 (01:29 +0200)
committerVirtualTam <virtualtam@flibidi.net>
Mon, 13 Jul 2015 11:06:06 +0000 (13:06 +0200)
Relates to #250

Modifications
 - supported version
   - bump required version from 5.1.0 to 5.3.x
   - update README
   - add PHP 5.3 to Travis environments
 - rewrite array declarations: explicitely use array() instead of []
 - move checkPHPVersion to application/Utils.php
 - move timezone functions to application/TimeZone.php
   - cleanup code
   - improve test coverage

Signed-off-by: VirtualTam <virtualtam@flibidi.net>
.travis.yml
README.md
application/Config.php
application/TimeZone.php [new file with mode: 0644]
application/Utils.php
index.php
tests/ConfigTest.php
tests/LinkDBTest.php
tests/TimeZoneTest.php [new file with mode: 0644]
tests/UtilsTest.php

index bcaf682ce45847484077161351d540a0182864f3..d1c7017291d5a1f1ee5a18196acf46c0106160aa 100644 (file)
@@ -3,6 +3,7 @@ php:
   - 5.6
   - 5.5
   - 5.4
+  - 5.3
 install:
   - composer self-update
   - composer install
index 15d4379af82aca848f22ace13028b2f345cfd2e3..b3dbaf5facb5c6c8e8cc3f9deb1eb0b6e8352903 100644 (file)
--- a/README.md
+++ b/README.md
@@ -57,7 +57,7 @@ Password: `demo`
 
 ## Installing
 
-Shaarli requires php 5.4. `php-gd` is optional and provides thumbnail resizing.
+Shaarli requires PHP 5.3. `php-gd` is optional and provides thumbnail resizing.
 
  * Download the latest stable release from https://github.com/shaarli/Shaarli/releases
  * Unpack the archive in a directory on your web server
index 0b01b524686a0523e429d3da3199c95fe788ff98..ec799d7f75cda61bfe33bf4e3d228b5e4952cf85 100755 (executable)
 function writeConfig($config, $isLoggedIn)\r
 {\r
     // These fields are required in configuration.\r
-    $MANDATORY_FIELDS = [\r
+    $MANDATORY_FIELDS = array(\r
         'login', 'hash', 'salt', 'timezone', 'title', 'titleLink',\r
         'redirector', 'disablesessionprotection', 'privateLinkByDefault'\r
-    ];\r
+    );\r
 \r
     if (!isset($config['config']['CONFIG_FILE'])) {\r
         throw new MissingFieldConfigException('CONFIG_FILE');\r
@@ -126,4 +126,4 @@ class UnauthorizedConfigException extends Exception
     {\r
         $this->message = 'You are not authorized to alter config.';\r
     }\r
-}
\ No newline at end of file
+}\r
diff --git a/application/TimeZone.php b/application/TimeZone.php
new file mode 100644 (file)
index 0000000..ccbef91
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+/**
+ * Generates the timezone selection form and JavaScript.
+ *
+ * Note: 'UTC/UTC' is mapped to 'UTC' to form a valid option
+ *
+ * Example: preselect Europe/Paris
+ *  list($htmlform, $js) = templateTZform('Europe/Paris');
+ *
+ * @param string $preselected_timezone preselected timezone (optional)
+ *
+ * @return an array containing the generated HTML form and Javascript code
+ **/
+function generateTimeZoneForm($preselected_timezone='')
+{
+    // Select the first available timezone if no preselected value is passed
+    if ($preselected_timezone == '') {
+        $l = timezone_identifiers_list();
+        $preselected_timezone = $l[0];
+    }
+
+    // Try to split the provided timezone
+    $spos = strpos($preselected_timezone, '/');
+    $pcontinent = substr($preselected_timezone, 0, $spos);
+    $pcity = substr($preselected_timezone, $spos+1);
+
+    // Display config form:
+    $timezone_form = '';
+    $timezone_js = '';
+
+    // The list is in the form 'Europe/Paris', 'America/Argentina/Buenos_Aires'...
+    // We split the list in continents/cities.
+    $continents = array();
+    $cities = array();
+
+    // TODO: use a template to generate the HTML/Javascript form
+
+    foreach (timezone_identifiers_list() as $tz) {
+        if ($tz == 'UTC') {
+            $tz = 'UTC/UTC';
+        }
+        $spos = strpos($tz, '/');
+
+        if ($spos !== false) {
+            $continent = substr($tz, 0, $spos);
+            $city = substr($tz, $spos+1);
+            $continents[$continent] = 1;
+
+            if (!isset($cities[$continent])) {
+                $cities[$continent] = '';
+            }
+            $cities[$continent] .= '<option value="'.$city.'"';
+            if ($pcity == $city) {
+                $cities[$continent] .= ' selected="selected"';
+            }
+            $cities[$continent] .= '>'.$city.'</option>';
+        }
+    }
+
+    $continents_html = '';
+    $continents = array_keys($continents);
+
+    foreach ($continents as $continent) {
+        $continents_html .= '<option  value="'.$continent.'"';
+        if ($pcontinent == $continent) {
+            $continents_html .= ' selected="selected"';
+        }
+        $continents_html .= '>'.$continent.'</option>';
+    }
+
+    // Timezone selection form
+    $timezone_form = 'Continent:';
+    $timezone_form .= '<select name="continent" id="continent" onChange="onChangecontinent();">';
+    $timezone_form .= $continents_html.'</select>';
+    $timezone_form .= '&nbsp;&nbsp;&nbsp;&nbsp;City:';
+    $timezone_form .= '<select name="city" id="city">'.$cities[$pcontinent].'</select><br />';
+
+    // Javascript handler - updates the city list when the user selects a continent
+    $timezone_js = '<script>';
+    $timezone_js .= 'function onChangecontinent() {';
+    $timezone_js .= 'document.getElementById("city").innerHTML =';
+    $timezone_js .= ' citiescontinent[document.getElementById("continent").value]; }';
+    $timezone_js .= 'var citiescontinent = '.json_encode($cities).';';
+    $timezone_js .= '</script>';
+
+    return array($timezone_form, $timezone_js);
+}
+
+/**
+ * Tells if a continent/city pair form a valid timezone
+ *
+ * Note: 'UTC/UTC' is mapped to 'UTC'
+ *
+ * @param string $continent the timezone continent
+ * @param string $city      the timezone city
+ *
+ * @return whether continent/city is a valid timezone
+ */
+function isTimeZoneValid($continent, $city)
+{
+    if ($continent == 'UTC' && $city == 'UTC') {
+        return true;
+    }
+
+    return in_array(
+        $continent.'/'.$city,
+        timezone_identifiers_list()
+    );
+}
+?>
index 658b97bc2f03fff6d2f5580fa912165d1a422cdb..cd4724fa388fe7de20eaa12bc97189cea993f119 100644 (file)
@@ -48,7 +48,7 @@ function endsWith($haystack, $needle, $case=true)
  */
 function nl2br_escaped($html)
 {
-    return str_replace('>','&gt;',str_replace('<','&lt;',nl2br($html)));
+    return str_replace('>', '&gt;', str_replace('<', '&lt;', nl2br($html)));
 }
 
 /**
@@ -117,3 +117,24 @@ function generateLocation($referer, $host, $loopTerms = array())
 
     return $final_referer;
 }
+
+/**
+ * Checks the PHP version to ensure Shaarli can run
+ *
+ * @param string $minVersion minimum PHP required version
+ * @param string $curVersion current PHP version (use PHP_VERSION)
+ *
+ * @throws Exception    the PHP version is not supported
+ */
+function checkPHPVersion($minVersion, $curVersion)
+{
+    if (version_compare($curVersion, $minVersion) < 0) {
+        throw new Exception(
+            'Your PHP version is obsolete!'
+            .' Shaarli requires at least PHP '.$minVersion.', and thus cannot run.'
+            .' Your PHP version has known security vulnerabilities and should be'
+            .' updated as soon as possible.'
+        );
+    }
+}
+?>
index bf0b99e043b7492f8402cd2c62aa8b5b29b13f66..6d3fbd39616926a7c9a48659399ff3ce908d67f9 100644 (file)
--- a/index.php
+++ b/index.php
@@ -3,7 +3,7 @@
 // The personal, minimalist, super-fast, no-database Delicious clone. By sebsauvage.net
 // http://sebsauvage.net/wiki/doku.php?id=php:shaarli
 // Licence: http://www.opensource.org/licenses/zlib-license.php
-// Requires: PHP 5.1.x  (but autocomplete fields will only work if you have PHP 5.2.x)
+// Requires: PHP 5.3.x
 // -----------------------------------------------------------------------------------------------
 // NEVER TRUST IN PHP.INI
 // Some hosts do not define a default timezone in php.ini,
@@ -59,7 +59,6 @@ ini_set('max_input_time','60');  // High execution time in case of problematic i
 ini_set('memory_limit', '128M');  // Try to set max upload file size and read (May not work on some hosts).
 ini_set('post_max_size', '16M');
 ini_set('upload_max_filesize', '16M');
-checkphpversion();
 error_reporting(E_ALL^E_WARNING);  // See all error except warnings.
 //error_reporting(-1); // See all errors (for debugging only)
 
@@ -70,9 +69,19 @@ if (is_file($GLOBALS['config']['CONFIG_FILE'])) {
 
 // Shaarli library
 require_once 'application/LinkDB.php';
+require_once 'application/TimeZone.php';
 require_once 'application/Utils.php';
 require_once 'application/Config.php';
 
+// Ensure the PHP version is supported
+try {
+    checkPHPVersion('5.3', PHP_VERSION);
+} catch(Exception $e) {
+    header('Content-Type: text/plain; charset=utf-8');
+    echo $e->getMessage();
+    exit;
+}
+
 include "inc/rain.tpl.class.php"; //include Rain TPL
 raintpl::$tpl_dir = $GLOBALS['config']['RAINTPL_TPL']; // template directory
 raintpl::$cache_dir = $GLOBALS['config']['RAINTPL_TMP']; // cache directory
@@ -164,21 +173,7 @@ function setup_login_state() {
 
        return $userIsLoggedIn;
 }
-//==================================================================================================
 $userIsLoggedIn = setup_login_state();
-//==================================================================================================
-//==================================================================================================
-
-// Check PHP version
-function checkphpversion()
-{
-    if (version_compare(PHP_VERSION, '5.1.0') < 0)
-    {
-        header('Content-Type: text/plain; charset=utf-8');
-        echo 'Your PHP version is obsolete! Shaarli requires at least php 5.1.0, and thus cannot run. Sorry. Your PHP version has known security vulnerabilities and should be updated as soon as possible.';
-        exit;
-    }
-}
 
 // Checks if an update is available for Shaarli.
 // (at most once a day, and only for registered user.)
@@ -982,7 +977,7 @@ function showDaily()
         $linksToDisplay = $LINKSDB->filterDay($day);
     } catch (Exception $exc) {
         error_log($exc);
-        $linksToDisplay = [];
+        $linksToDisplay = array();
     }
 
     // We pre-format some fields for proper output.
@@ -1288,7 +1283,7 @@ function renderPage()
             if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away!
             $tz = 'UTC';
             if (!empty($_POST['continent']) && !empty($_POST['city']))
-                if (isTZvalid($_POST['continent'],$_POST['city']))
+                if (isTimeZoneValid($_POST['continent'],$_POST['city']))
                     $tz = $_POST['continent'].'/'.$_POST['city'];
             $GLOBALS['timezone'] = $tz;
             $GLOBALS['title']=$_POST['title'];
@@ -1322,8 +1317,8 @@ function renderPage()
             $PAGE->assign('token',getToken());
             $PAGE->assign('title', empty($GLOBALS['title']) ? '' : $GLOBALS['title'] );
             $PAGE->assign('redirector', empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] );
-            list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']);
-            $PAGE->assign('timezone_form',$timezone_form); // FIXME: Put entire tz form generation in template?
+            list($timezone_form, $timezone_js) = generateTimeZoneForm($GLOBALS['timezone']);
+            $PAGE->assign('timezone_form', $timezone_form);
             $PAGE->assign('timezone_js',$timezone_js);
             $PAGE->renderPage('configure');
             exit;
@@ -2059,9 +2054,11 @@ function install()
     if (!empty($_POST['setlogin']) && !empty($_POST['setpassword']))
     {
         $tz = 'UTC';
-        if (!empty($_POST['continent']) && !empty($_POST['city']))
-            if (isTZvalid($_POST['continent'],$_POST['city']))
+        if (!empty($_POST['continent']) && !empty($_POST['city'])) {
+            if (isTimeZoneValid($_POST['continent'], $_POST['city'])) {
                 $tz = $_POST['continent'].'/'.$_POST['city'];
+            }
+        }
         $GLOBALS['timezone'] = $tz;
         // Everything is ok, let's create config file.
         $GLOBALS['login'] = $_POST['setlogin'];
@@ -2087,8 +2084,11 @@ function install()
     }
 
     // Display config form:
-    list($timezone_form,$timezone_js) = templateTZform();
-    $timezone_html=''; if ($timezone_form!='') $timezone_html='<tr><td><b>Timezone:</b></td><td>'.$timezone_form.'</td></tr>';
+    list($timezone_form, $timezone_js) = generateTimeZoneForm();
+    $timezone_html = '';
+    if ($timezone_form != '') {
+        $timezone_html = '<tr><td><b>Timezone:</b></td><td>'.$timezone_form.'</td></tr>';
+    }
 
     $PAGE = new pageBuilder;
     $PAGE->assign('timezone_html',$timezone_html);
@@ -2097,67 +2097,6 @@ function install()
     exit;
 }
 
-// Generates the timezone selection form and JavaScript.
-// Input: (optional) current timezone (can be 'UTC/UTC'). It will be pre-selected.
-// Output: array(html,js)
-// Example: list($htmlform,$js) = templateTZform('Europe/Paris');  // Europe/Paris pre-selected.
-// Returns array('','') if server does not support timezones list. (e.g. PHP 5.1 on free.fr)
-function templateTZform($ptz=false)
-{
-    if (function_exists('timezone_identifiers_list')) // because of old PHP version (5.1) which can be found on free.fr
-    {
-        // Try to split the provided timezone.
-        if ($ptz==false) { $l=timezone_identifiers_list(); $ptz=$l[0]; }
-        $spos=strpos($ptz,'/'); $pcontinent=substr($ptz,0,$spos); $pcity=substr($ptz,$spos+1);
-
-        // Display config form:
-        $timezone_form = '';
-        $timezone_js = '';
-        // The list is in the form "Europe/Paris", "America/Argentina/Buenos_Aires"...
-        // We split the list in continents/cities.
-        $continents = array();
-        $cities = array();
-        foreach(timezone_identifiers_list() as $tz)
-        {
-            if ($tz=='UTC') $tz='UTC/UTC';
-            $spos = strpos($tz,'/');
-            if ($spos!==false)
-            {
-                $continent=substr($tz,0,$spos); $city=substr($tz,$spos+1);
-                $continents[$continent]=1;
-                if (!isset($cities[$continent])) $cities[$continent]='';
-                $cities[$continent].='<option value="'.$city.'"'.($pcity==$city?' selected':'').'>'.$city.'</option>';
-            }
-        }
-        $continents_html = '';
-        $continents = array_keys($continents);
-        foreach($continents as $continent)
-            $continents_html.='<option  value="'.$continent.'"'.($pcontinent==$continent?' selected':'').'>'.$continent.'</option>';
-        $cities_html = $cities[$pcontinent];
-        $timezone_form = "Continent: <select name=\"continent\" id=\"continent\" onChange=\"onChangecontinent();\">${continents_html}</select>";
-        $timezone_form .= "&nbsp;&nbsp;&nbsp;&nbsp;City: <select name=\"city\" id=\"city\">${cities[$pcontinent]}</select><br />";
-        $timezone_js = "<script>";
-        $timezone_js .= "function onChangecontinent(){document.getElementById(\"city\").innerHTML = citiescontinent[document.getElementById(\"continent\").value];}";
-        $timezone_js .= "var citiescontinent = ".json_encode($cities).";" ;
-        $timezone_js .= "</script>" ;
-        return array($timezone_form,$timezone_js);
-    }
-    return array('','');
-}
-
-// Tells if a timezone is valid or not.
-// If not valid, returns false.
-// If system does not support timezone list, returns false.
-function isTZvalid($continent,$city)
-{
-    $tz = $continent.'/'.$city;
-    if (function_exists('timezone_identifiers_list')) // because of old PHP version (5.1) which can be found on free.fr
-    {
-        if (in_array($tz, timezone_identifiers_list())) // it's a valid timezone?
-                    return true;
-    }
-    return false;
-}
 if (!function_exists('json_encode')) {
     function json_encode($data) {
         switch ($type = gettype($data)) {
index 4279c57e54c1d5734844b72940b06a5fd61b7b3a..a239d8b7d3a2004e57ba03fde078bc8f7b5bfb99 100755 (executable)
@@ -18,7 +18,7 @@ class ConfigTest extends PHPUnit_Framework_TestCase
      */\r
     public function setUp()\r
     {\r
-        self::$_configFields = [\r
+        self::$_configFields = array(\r
             'login' => 'login',\r
             'hash' => 'hash',\r
             'salt' => 'salt',\r
@@ -28,13 +28,13 @@ class ConfigTest extends PHPUnit_Framework_TestCase
             'redirector' => '',\r
             'disablesessionprotection' => false,\r
             'privateLinkByDefault' => false,\r
-            'config' => [\r
+            'config' => array(\r
                 'CONFIG_FILE' => 'tests/config.php',\r
                 'DATADIR' => 'tests',\r
                 'config1' => 'config1data',\r
                 'config2' => 'config2data',\r
-            ]\r
-        ];\r
+            )\r
+        );\r
     }\r
 \r
     /**\r
@@ -174,4 +174,4 @@ class ConfigTest extends PHPUnit_Framework_TestCase
         include self::$_configFields['config']['CONFIG_FILE'];\r
         $this->assertEquals(self::$_configFields['login'], $GLOBALS['login']);\r
     }\r
-}
\ No newline at end of file
+}\r
index d34ea4f568bf4dcef51456615bfd9e00cb8dd602..504c81901a8fc402278e66eb50689d51e5fe0b92 100644 (file)
@@ -228,12 +228,12 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
     public function testDays()
     {
         $this->assertEquals(
-            ['20121206', '20130614', '20150310'],
+            array('20121206', '20130614', '20150310'),
             self::$publicLinkDB->days()
         );
 
         $this->assertEquals(
-            ['20121206', '20130614', '20141125', '20150310'],
+            array('20121206', '20130614', '20141125', '20150310'),
             self::$privateLinkDB->days()
         );
     }
@@ -269,7 +269,7 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
     public function testAllTags()
     {
         $this->assertEquals(
-            [
+            array(
                 'web' => 3,
                 'cartoon' => 2,
                 'gnu' => 2,
@@ -279,12 +279,12 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
                 'software' => 1,
                 'stallman' => 1,
                 'free' => 1
-            ],
+            ),
             self::$publicLinkDB->allTags()
         );
 
         $this->assertEquals(
-            [
+            array(
                 'web' => 4,
                 'cartoon' => 3,
                 'gnu' => 2,
@@ -298,7 +298,7 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
                 'w3c' => 1,
                 'css' => 1,
                 'Mercurial' => 1
-            ],
+            ),
             self::$privateLinkDB->allTags()
         );
     }
diff --git a/tests/TimeZoneTest.php b/tests/TimeZoneTest.php
new file mode 100644 (file)
index 0000000..f3de391
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+/**
+ * TimeZone's tests
+ */
+
+require_once 'application/TimeZone.php';
+
+/**
+ * Unitary tests for timezone utilities
+ */
+class TimeZoneTest extends PHPUnit_Framework_TestCase
+{
+    /**
+     * Generate a timezone selection form
+     */
+    public function testGenerateTimeZoneForm()
+    {
+        $generated = generateTimeZoneForm();
+
+        // HTML form
+        $this->assertStringStartsWith('Continent:<select', $generated[0]);
+        $this->assertContains('selected="selected"', $generated[0]);
+        $this->assertStringEndsWith('</select><br />', $generated[0]);
+
+        // Javascript handler
+        $this->assertStringStartsWith('<script>', $generated[1]);
+        $this->assertContains(
+            '<option value=\"Bermuda\">Bermuda<\/option>',
+            $generated[1]
+        );
+        $this->assertStringEndsWith('</script>', $generated[1]);
+    }
+
+    /**
+     * Generate a timezone selection form, with a preselected timezone
+     */
+    public function testGenerateTimeZoneFormPreselected()
+    {
+        $generated = generateTimeZoneForm('Antarctica/Syowa');
+
+        // HTML form
+        $this->assertStringStartsWith('Continent:<select', $generated[0]);
+        $this->assertContains(
+            'value="Antarctica" selected="selected"',
+            $generated[0]
+        );
+        $this->assertContains(
+            'value="Syowa" selected="selected"',
+            $generated[0]
+        );
+        $this->assertStringEndsWith('</select><br />', $generated[0]);
+
+
+        // Javascript handler
+        $this->assertStringStartsWith('<script>', $generated[1]);
+        $this->assertContains(
+            '<option value=\"Bermuda\">Bermuda<\/option>',
+            $generated[1]
+        );
+        $this->assertStringEndsWith('</script>', $generated[1]);
+    }
+
+    /**
+     * Check valid timezones
+     */
+    public function testValidTimeZone()
+    {
+        $this->assertTrue(isTimeZoneValid('America', 'Argentina/Ushuaia'));
+        $this->assertTrue(isTimeZoneValid('Europe', 'Oslo'));
+        $this->assertTrue(isTimeZoneValid('UTC', 'UTC'));
+    }
+
+    /**
+     * Check invalid timezones
+     */
+    public function testInvalidTimeZone()
+    {
+        $this->assertFalse(isTimeZoneValid('CEST', 'CEST'));
+        $this->assertFalse(isTimeZoneValid('Europe', 'Atlantis'));
+        $this->assertFalse(isTimeZoneValid('Middle_Earth', 'Moria'));
+    }
+}
+?>
index 8355c7f81f9ba12d2d72ca09c77c76a148d8cd48..28e15f5a651268e24e8de545824821fd9ba9ca6a 100644 (file)
@@ -109,7 +109,7 @@ class UtilsTest extends PHPUnit_Framework_TestCase
      */
     public function testGenerateLocationLoop() {
         $ref = 'http://localhost/?test';
-        $this->assertEquals('?', generateLocation($ref, 'localhost', ['test']));
+        $this->assertEquals('?', generateLocation($ref, 'localhost', array('test')));
     }
 
     /**
@@ -119,4 +119,36 @@ class UtilsTest extends PHPUnit_Framework_TestCase
         $ref = 'http://somewebsite.com/?test';
         $this->assertEquals('?', generateLocation($ref, 'localhost'));
     }
+
+    /**
+     * Check supported PHP versions
+     */
+    public function testCheckSupportedPHPVersion()
+    {
+        $minVersion = '5.3';
+        checkPHPVersion($minVersion, '5.4.32');
+        checkPHPVersion($minVersion, '5.5');
+        checkPHPVersion($minVersion, '5.6.10');
+    }
+
+    /**
+     * Check a unsupported PHP version
+     * @expectedException              Exception
+     * @expectedExceptionMessageRegExp /Your PHP version is obsolete/
+     */
+    public function testCheckSupportedPHPVersion51()
+    {
+        checkPHPVersion('5.3', '5.1.0');
+    }
+
+    /**
+     * Check another unsupported PHP version
+     * @expectedException              Exception
+     * @expectedExceptionMessageRegExp /Your PHP version is obsolete/
+     */
+    public function testCheckSupportedPHPVersion52()
+    {
+        checkPHPVersion('5.3', '5.2');
+    }
 }
+?>