diff options
author | ArthurHoaro <arthur@hoa.ro> | 2015-06-29 12:23:00 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2015-07-09 20:46:03 +0200 |
commit | dd484b90b1c15989210d7379e51256d545856d95 (patch) | |
tree | c7300dc1c54388699ca45055cae58b2740525c80 | |
parent | eee711c0a8583e1c2ea2186544795d59fa41d9f6 (diff) | |
download | Shaarli-dd484b90b1c15989210d7379e51256d545856d95.tar.gz Shaarli-dd484b90b1c15989210d7379e51256d545856d95.tar.zst Shaarli-dd484b90b1c15989210d7379e51256d545856d95.zip |
All settings are now stored in config.php
Isolate functions related to config in Config.php + add unit tests + code_sniffer.
options.php is not supported anymore, but its content will be automatically saved into config.php
Fixes #shaarli/Shaarli#41
*TODO*: update [documentation](https://github.com/shaarli/Shaarli/wiki#configuration).
-rwxr-xr-x | application/Config.php | 129 | ||||
-rw-r--r-- | index.php | 94 | ||||
-rwxr-xr-x | tests/ConfigTest.php | 177 |
3 files changed, 362 insertions, 38 deletions
diff --git a/application/Config.php b/application/Config.php new file mode 100755 index 00000000..0b01b524 --- /dev/null +++ b/application/Config.php | |||
@@ -0,0 +1,129 @@ | |||
1 | <?php | ||
2 | /** | ||
3 | * Functions related to configuration management. | ||
4 | */ | ||
5 | |||
6 | /** | ||
7 | * Re-write configuration file according to given array. | ||
8 | * Requires mandatory fields listed in $MANDATORY_FIELDS. | ||
9 | * | ||
10 | * @param array $config contains all configuration fields. | ||
11 | * @param bool $isLoggedIn true if user is logged in. | ||
12 | * | ||
13 | * @return void | ||
14 | * | ||
15 | * @throws MissingFieldConfigException: a mandatory field has not been provided in $config. | ||
16 | * @throws UnauthorizedConfigException: user is not authorize to change configuration. | ||
17 | * @throws Exception: an error occured while writing the new config file. | ||
18 | */ | ||
19 | function writeConfig($config, $isLoggedIn) | ||
20 | { | ||
21 | // These fields are required in configuration. | ||
22 | $MANDATORY_FIELDS = [ | ||
23 | 'login', 'hash', 'salt', 'timezone', 'title', 'titleLink', | ||
24 | 'redirector', 'disablesessionprotection', 'privateLinkByDefault' | ||
25 | ]; | ||
26 | |||
27 | if (!isset($config['config']['CONFIG_FILE'])) { | ||
28 | throw new MissingFieldConfigException('CONFIG_FILE'); | ||
29 | } | ||
30 | |||
31 | // Only logged in user can alter config. | ||
32 | if (is_file($config['config']['CONFIG_FILE']) && !$isLoggedIn) { | ||
33 | throw new UnauthorizedConfigException(); | ||
34 | } | ||
35 | |||
36 | // Check that all mandatory fields are provided in $config. | ||
37 | foreach ($MANDATORY_FIELDS as $field) { | ||
38 | if (!isset($config[$field])) { | ||
39 | throw new MissingFieldConfigException($field); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | $configStr = '<?php '. PHP_EOL; | ||
44 | $configStr .= '$GLOBALS[\'login\'] = '.var_export($config['login'], true).';'. PHP_EOL; | ||
45 | $configStr .= '$GLOBALS[\'hash\'] = '.var_export($config['hash'], true).';'. PHP_EOL; | ||
46 | $configStr .= '$GLOBALS[\'salt\'] = '.var_export($config['salt'], true).'; '. PHP_EOL; | ||
47 | $configStr .= '$GLOBALS[\'timezone\'] = '.var_export($config['timezone'], true).';'. PHP_EOL; | ||
48 | $configStr .= 'date_default_timezone_set('.var_export($config['timezone'], true).');'. PHP_EOL; | ||
49 | $configStr .= '$GLOBALS[\'title\'] = '.var_export($config['title'], true).';'. PHP_EOL; | ||
50 | $configStr .= '$GLOBALS[\'titleLink\'] = '.var_export($config['titleLink'], true).'; '. PHP_EOL; | ||
51 | $configStr .= '$GLOBALS[\'redirector\'] = '.var_export($config['redirector'], true).'; '. PHP_EOL; | ||
52 | $configStr .= '$GLOBALS[\'disablesessionprotection\'] = '.var_export($config['disablesessionprotection'], true).'; '. PHP_EOL; | ||
53 | $configStr .= '$GLOBALS[\'privateLinkByDefault\'] = '.var_export($config['privateLinkByDefault'], true).'; '. PHP_EOL; | ||
54 | |||
55 | // Store all $config['config'] | ||
56 | foreach ($config['config'] as $key => $value) { | ||
57 | $configStr .= '$GLOBALS[\'config\'][\''. $key .'\'] = '.var_export($config['config'][$key], true).';'. PHP_EOL; | ||
58 | } | ||
59 | $configStr .= '?>'; | ||
60 | |||
61 | if (!file_put_contents($config['config']['CONFIG_FILE'], $configStr) | ||
62 | || strcmp(file_get_contents($config['config']['CONFIG_FILE']), $configStr) != 0 | ||
63 | ) { | ||
64 | throw new Exception( | ||
65 | 'Shaarli could not create the config file. | ||
66 | Please make sure Shaarli has the right to write in the folder is it installed in.' | ||
67 | ); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * Milestone 0.9 - shaarli/Shaarli#41: options.php is not supported anymore. | ||
73 | * ==> if user is loggedIn, merge its content with config.php, then delete options.php. | ||
74 | * | ||
75 | * @param array $config contains all configuration fields. | ||
76 | * @param bool $isLoggedIn true if user is logged in. | ||
77 | * | ||
78 | * @return void | ||
79 | */ | ||
80 | function mergeDeprecatedConfig($config, $isLoggedIn) | ||
81 | { | ||
82 | $config_file = $config['config']['CONFIG_FILE']; | ||
83 | |||
84 | if (is_file($config['config']['DATADIR'].'/options.php') && $isLoggedIn) { | ||
85 | include $config['config']['DATADIR'].'/options.php'; | ||
86 | |||
87 | // Load GLOBALS into config | ||
88 | foreach ($GLOBALS as $key => $value) { | ||
89 | $config[$key] = $value; | ||
90 | } | ||
91 | $config['config']['CONFIG_FILE'] = $config_file; | ||
92 | writeConfig($config, $isLoggedIn); | ||
93 | |||
94 | unlink($config['config']['DATADIR'].'/options.php'); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * Exception used if a mandatory field is missing in given configuration. | ||
100 | */ | ||
101 | class MissingFieldConfigException extends Exception | ||
102 | { | ||
103 | public $field; | ||
104 | |||
105 | /** | ||
106 | * Construct exception. | ||
107 | * | ||
108 | * @param string $field field name missing. | ||
109 | */ | ||
110 | public function __construct($field) | ||
111 | { | ||
112 | $this->field = $field; | ||
113 | $this->message = 'Configuration value is required for '. $this->field; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * Exception used if an unauthorized attempt to edit configuration has been made. | ||
119 | */ | ||
120 | class UnauthorizedConfigException extends Exception | ||
121 | { | ||
122 | /** | ||
123 | * Construct exception. | ||
124 | */ | ||
125 | public function __construct() | ||
126 | { | ||
127 | $this->message = 'You are not authorized to alter config.'; | ||
128 | } | ||
129 | } \ No newline at end of file | ||
@@ -11,7 +11,8 @@ | |||
11 | date_default_timezone_set('UTC'); | 11 | date_default_timezone_set('UTC'); |
12 | 12 | ||
13 | // ----------------------------------------------------------------------------------------------- | 13 | // ----------------------------------------------------------------------------------------------- |
14 | // Hardcoded parameter (These parameters can be overwritten by creating the file /data/options.php) | 14 | // Hardcoded parameter (These parameters can be overwritten by editing the file /data/config.php) |
15 | // You should not touch any code below (or at your own risks!) | ||
15 | $GLOBALS['config']['DATADIR'] = 'data'; // Data subdirectory | 16 | $GLOBALS['config']['DATADIR'] = 'data'; // Data subdirectory |
16 | $GLOBALS['config']['CONFIG_FILE'] = $GLOBALS['config']['DATADIR'].'/config.php'; // Configuration file (user login/password) | 17 | $GLOBALS['config']['CONFIG_FILE'] = $GLOBALS['config']['DATADIR'].'/config.php'; // Configuration file (user login/password) |
17 | $GLOBALS['config']['DATASTORE'] = $GLOBALS['config']['DATADIR'].'/datastore.php'; // Data storage file. | 18 | $GLOBALS['config']['DATASTORE'] = $GLOBALS['config']['DATADIR'].'/datastore.php'; // Data storage file. |
@@ -36,10 +37,6 @@ $GLOBALS['config']['ARCHIVE_ORG'] = false; // For each link, add a link to an ar | |||
36 | $GLOBALS['config']['ENABLE_RSS_PERMALINKS'] = true; // Enable RSS permalinks by default. This corresponds to the default behavior of shaarli before this was added as an option. | 37 | $GLOBALS['config']['ENABLE_RSS_PERMALINKS'] = true; // Enable RSS permalinks by default. This corresponds to the default behavior of shaarli before this was added as an option. |
37 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] = false; | 38 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] = false; |
38 | // ----------------------------------------------------------------------------------------------- | 39 | // ----------------------------------------------------------------------------------------------- |
39 | // You should not touch below (or at your own risks!) | ||
40 | // Optional config file. | ||
41 | if (is_file($GLOBALS['config']['DATADIR'].'/options.php')) require($GLOBALS['config']['DATADIR'].'/options.php'); | ||
42 | |||
43 | define('shaarli_version','0.0.45beta'); | 40 | define('shaarli_version','0.0.45beta'); |
44 | // http://server.com/x/shaarli --> /shaarli/ | 41 | // http://server.com/x/shaarli --> /shaarli/ |
45 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); | 42 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); |
@@ -69,6 +66,7 @@ error_reporting(E_ALL^E_WARNING); // See all error except warnings. | |||
69 | // Shaarli library | 66 | // Shaarli library |
70 | require_once 'application/LinkDB.php'; | 67 | require_once 'application/LinkDB.php'; |
71 | require_once 'application/Utils.php'; | 68 | require_once 'application/Utils.php'; |
69 | require_once 'application/Config.php'; | ||
72 | 70 | ||
73 | include "inc/rain.tpl.class.php"; //include Rain TPL | 71 | include "inc/rain.tpl.class.php"; //include Rain TPL |
74 | raintpl::$tpl_dir = $GLOBALS['config']['RAINTPL_TPL']; // template directory | 72 | raintpl::$tpl_dir = $GLOBALS['config']['RAINTPL_TPL']; // template directory |
@@ -100,7 +98,6 @@ if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.escape(indexU | |||
100 | if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); | 98 | if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); |
101 | if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']=''; | 99 | if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']=''; |
102 | if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false; | 100 | if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false; |
103 | if (empty($GLOBALS['disablejquery'])) $GLOBALS['disablejquery']=false; | ||
104 | if (empty($GLOBALS['privateLinkByDefault'])) $GLOBALS['privateLinkByDefault']=false; | 101 | if (empty($GLOBALS['privateLinkByDefault'])) $GLOBALS['privateLinkByDefault']=false; |
105 | if (empty($GLOBALS['titleLink'])) $GLOBALS['titleLink']='?'; | 102 | if (empty($GLOBALS['titleLink'])) $GLOBALS['titleLink']='?'; |
106 | // I really need to rewrite Shaarli with a proper configuation manager. | 103 | // I really need to rewrite Shaarli with a proper configuation manager. |
@@ -709,7 +706,7 @@ function showRSS() | |||
709 | if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); | 706 | if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); |
710 | else if (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); | 707 | else if (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); |
711 | else $linksToDisplay = $LINKSDB; | 708 | else $linksToDisplay = $LINKSDB; |
712 | 709 | ||
713 | $nblinksToDisplay = 50; // Number of links to display. | 710 | $nblinksToDisplay = 50; // Number of links to display. |
714 | if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. | 711 | if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. |
715 | { | 712 | { |
@@ -789,7 +786,7 @@ function showATOM() | |||
789 | if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); | 786 | if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); |
790 | else if (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); | 787 | else if (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); |
791 | else $linksToDisplay = $LINKSDB; | 788 | else $linksToDisplay = $LINKSDB; |
792 | 789 | ||
793 | $nblinksToDisplay = 50; // Number of links to display. | 790 | $nblinksToDisplay = 50; // Number of links to display. |
794 | if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. | 791 | if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. |
795 | { | 792 | { |
@@ -1041,7 +1038,7 @@ function renderPage() | |||
1041 | if (!empty($_GET['searchterm'])) $links = $LINKSDB->filterFulltext($_GET['searchterm']); | 1038 | if (!empty($_GET['searchterm'])) $links = $LINKSDB->filterFulltext($_GET['searchterm']); |
1042 | elseif (!empty($_GET['searchtags'])) $links = $LINKSDB->filterTags(trim($_GET['searchtags'])); | 1039 | elseif (!empty($_GET['searchtags'])) $links = $LINKSDB->filterTags(trim($_GET['searchtags'])); |
1043 | else $links = $LINKSDB; | 1040 | else $links = $LINKSDB; |
1044 | 1041 | ||
1045 | $body=''; | 1042 | $body=''; |
1046 | $linksToDisplay=array(); | 1043 | $linksToDisplay=array(); |
1047 | 1044 | ||
@@ -1056,7 +1053,7 @@ function renderPage() | |||
1056 | $linksToDisplay[]=$link; // Add to array. | 1053 | $linksToDisplay[]=$link; // Add to array. |
1057 | } | 1054 | } |
1058 | } | 1055 | } |
1059 | 1056 | ||
1060 | $PAGE = new pageBuilder; | 1057 | $PAGE = new pageBuilder; |
1061 | $PAGE->assign('linkcount',count($LINKSDB)); | 1058 | $PAGE->assign('linkcount',count($LINKSDB)); |
1062 | $PAGE->assign('linksToDisplay',$linksToDisplay); | 1059 | $PAGE->assign('linksToDisplay',$linksToDisplay); |
@@ -1214,7 +1211,19 @@ function renderPage() | |||
1214 | // Save new password | 1211 | // Save new password |
1215 | $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. | 1212 | $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. |
1216 | $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); | 1213 | $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); |
1217 | writeConfig(); | 1214 | try { |
1215 | writeConfig($GLOBALS, isLoggedIn()); | ||
1216 | } | ||
1217 | catch(Exception $e) { | ||
1218 | error_log( | ||
1219 | 'ERROR while writing config file after changing password.' . PHP_EOL . | ||
1220 | $e->getMessage() | ||
1221 | ); | ||
1222 | |||
1223 | // TODO: do not handle exceptions/errors in JS. | ||
1224 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=tools\';</script>'; | ||
1225 | exit; | ||
1226 | } | ||
1218 | echo '<script>alert("Your password has been changed.");document.location=\'?do=tools\';</script>'; | 1227 | echo '<script>alert("Your password has been changed.");document.location=\'?do=tools\';</script>'; |
1219 | exit; | 1228 | exit; |
1220 | } | 1229 | } |
@@ -1243,12 +1252,23 @@ function renderPage() | |||
1243 | $GLOBALS['titleLink']=$_POST['titleLink']; | 1252 | $GLOBALS['titleLink']=$_POST['titleLink']; |
1244 | $GLOBALS['redirector']=$_POST['redirector']; | 1253 | $GLOBALS['redirector']=$_POST['redirector']; |
1245 | $GLOBALS['disablesessionprotection']=!empty($_POST['disablesessionprotection']); | 1254 | $GLOBALS['disablesessionprotection']=!empty($_POST['disablesessionprotection']); |
1246 | $GLOBALS['disablejquery']=!empty($_POST['disablejquery']); | ||
1247 | $GLOBALS['privateLinkByDefault']=!empty($_POST['privateLinkByDefault']); | 1255 | $GLOBALS['privateLinkByDefault']=!empty($_POST['privateLinkByDefault']); |
1248 | $GLOBALS['config']['ENABLE_RSS_PERMALINKS']= !empty($_POST['enableRssPermalinks']); | 1256 | $GLOBALS['config']['ENABLE_RSS_PERMALINKS']= !empty($_POST['enableRssPermalinks']); |
1249 | $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); | 1257 | $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); |
1250 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] = !empty($_POST['hidePublicLinks']); | 1258 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] = !empty($_POST['hidePublicLinks']); |
1251 | writeConfig(); | 1259 | try { |
1260 | writeConfig($GLOBALS, isLoggedIn()); | ||
1261 | } | ||
1262 | catch(Exception $e) { | ||
1263 | error_log( | ||
1264 | 'ERROR while writing config file after configuration update.' . PHP_EOL . | ||
1265 | $e->getMessage() | ||
1266 | ); | ||
1267 | |||
1268 | // TODO: do not handle exceptions/errors in JS. | ||
1269 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=tools\';</script>'; | ||
1270 | exit; | ||
1271 | } | ||
1252 | echo '<script>alert("Configuration was saved.");document.location=\'?do=tools\';</script>'; | 1272 | echo '<script>alert("Configuration was saved.");document.location=\'?do=tools\';</script>'; |
1253 | exit; | 1273 | exit; |
1254 | } | 1274 | } |
@@ -2007,7 +2027,19 @@ function install() | |||
2007 | $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); | 2027 | $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); |
2008 | $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.escape(indexUrl()) : $_POST['title'] ); | 2028 | $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.escape(indexUrl()) : $_POST['title'] ); |
2009 | $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); | 2029 | $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); |
2010 | writeConfig(); | 2030 | try { |
2031 | writeConfig($GLOBALS, isLoggedIn()); | ||
2032 | } | ||
2033 | catch(Exception $e) { | ||
2034 | error_log( | ||
2035 | 'ERROR while writing config file after installation.' . PHP_EOL . | ||
2036 | $e->getMessage() | ||
2037 | ); | ||
2038 | |||
2039 | // TODO: do not handle exceptions/errors in JS. | ||
2040 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?\';</script>'; | ||
2041 | exit; | ||
2042 | } | ||
2011 | echo '<script>alert("Shaarli is now configured. Please enter your login/password and start shaaring your links!");document.location=\'?do=login\';</script>'; | 2043 | echo '<script>alert("Shaarli is now configured. Please enter your login/password and start shaaring your links!");document.location=\'?do=login\';</script>'; |
2012 | exit; | 2044 | exit; |
2013 | } | 2045 | } |
@@ -2121,30 +2153,7 @@ if (!function_exists('json_encode')) { | |||
2121 | } | 2153 | } |
2122 | } | 2154 | } |
2123 | 2155 | ||
2124 | // Re-write configuration file according to globals. | 2156 | |
2125 | // Requires some $GLOBALS to be set (login,hash,salt,title). | ||
2126 | // If the config file cannot be saved, an error message is displayed and the user is redirected to "Tools" menu. | ||
2127 | // (otherwise, the function simply returns.) | ||
2128 | function writeConfig() | ||
2129 | { | ||
2130 | if (is_file($GLOBALS['config']['CONFIG_FILE']) && !isLoggedIn()) die('You are not authorized to alter config.'); // Only logged in user can alter config. | ||
2131 | $config='<?php $GLOBALS[\'login\']='.var_export($GLOBALS['login'],true).'; $GLOBALS[\'hash\']='.var_export($GLOBALS['hash'],true).'; $GLOBALS[\'salt\']='.var_export($GLOBALS['salt'],true).'; '; | ||
2132 | $config .='$GLOBALS[\'timezone\']='.var_export($GLOBALS['timezone'],true).'; date_default_timezone_set('.var_export($GLOBALS['timezone'],true).'); $GLOBALS[\'title\']='.var_export($GLOBALS['title'],true).';'; | ||
2133 | $config .= '$GLOBALS[\'titleLink\']='.var_export($GLOBALS['titleLink'],true).'; '; | ||
2134 | $config .= '$GLOBALS[\'redirector\']='.var_export($GLOBALS['redirector'],true).'; '; | ||
2135 | $config .= '$GLOBALS[\'disablesessionprotection\']='.var_export($GLOBALS['disablesessionprotection'],true).'; '; | ||
2136 | $config .= '$GLOBALS[\'disablejquery\']='.var_export($GLOBALS['disablejquery'],true).'; '; | ||
2137 | $config .= '$GLOBALS[\'privateLinkByDefault\']='.var_export($GLOBALS['privateLinkByDefault'],true).'; '; | ||
2138 | $config .= '$GLOBALS[\'config\'][\'ENABLE_RSS_PERMALINKS\']='.var_export($GLOBALS['config']['ENABLE_RSS_PERMALINKS'], true).'; '; | ||
2139 | $config .= '$GLOBALS[\'config\'][\'ENABLE_UPDATECHECK\']='.var_export($GLOBALS['config']['ENABLE_UPDATECHECK'], true).'; '; | ||
2140 | $config .= '$GLOBALS[\'config\'][\'HIDE_PUBLIC_LINKS\']='.var_export($GLOBALS['config']['HIDE_PUBLIC_LINKS'], true).'; '; | ||
2141 | $config .= ' ?>'; | ||
2142 | if (!file_put_contents($GLOBALS['config']['CONFIG_FILE'],$config) || strcmp(file_get_contents($GLOBALS['config']['CONFIG_FILE']),$config)!=0) | ||
2143 | { | ||
2144 | echo '<script>alert("Shaarli could not create the config file. Please make sure Shaarli has the right to write in the folder is it installed in.");document.location=\'?\';</script>'; | ||
2145 | exit; | ||
2146 | } | ||
2147 | } | ||
2148 | 2157 | ||
2149 | /* Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL, | 2158 | /* Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL, |
2150 | I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. | 2159 | I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. |
@@ -2373,6 +2382,15 @@ function invalidateCaches() | |||
2373 | pageCache::purgeCache(); // Purge page cache shared by sessions. | 2382 | pageCache::purgeCache(); // Purge page cache shared by sessions. |
2374 | } | 2383 | } |
2375 | 2384 | ||
2385 | try { | ||
2386 | mergeDeprecatedConfig($GLOBALS, isLoggedIn()); | ||
2387 | } catch(Exception $e) { | ||
2388 | error_log( | ||
2389 | 'ERROR while merging deprecated options.php file.' . PHP_EOL . | ||
2390 | $e->getMessage() | ||
2391 | ); | ||
2392 | } | ||
2393 | |||
2376 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=genthumbnail')) { genThumbnail(); exit; } // Thumbnail generation/cache does not need the link database. | 2394 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=genthumbnail')) { genThumbnail(); exit; } // Thumbnail generation/cache does not need the link database. |
2377 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; } | 2395 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; } |
2378 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; } | 2396 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; } |
diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php new file mode 100755 index 00000000..4279c57e --- /dev/null +++ b/tests/ConfigTest.php | |||
@@ -0,0 +1,177 @@ | |||
1 | <?php | ||
2 | /** | ||
3 | * Config' tests | ||
4 | */ | ||
5 | |||
6 | require_once 'application/Config.php'; | ||
7 | |||
8 | /** | ||
9 | * Unitary tests for Shaarli config related functions | ||
10 | */ | ||
11 | class ConfigTest extends PHPUnit_Framework_TestCase | ||
12 | { | ||
13 | // Configuration input set. | ||
14 | private static $_configFields; | ||
15 | |||
16 | /** | ||
17 | * Executed before each test. | ||
18 | */ | ||
19 | public function setUp() | ||
20 | { | ||
21 | self::$_configFields = [ | ||
22 | 'login' => 'login', | ||
23 | 'hash' => 'hash', | ||
24 | 'salt' => 'salt', | ||
25 | 'timezone' => 'Europe/Paris', | ||
26 | 'title' => 'title', | ||
27 | 'titleLink' => 'titleLink', | ||
28 | 'redirector' => '', | ||
29 | 'disablesessionprotection' => false, | ||
30 | 'privateLinkByDefault' => false, | ||
31 | 'config' => [ | ||
32 | 'CONFIG_FILE' => 'tests/config.php', | ||
33 | 'DATADIR' => 'tests', | ||
34 | 'config1' => 'config1data', | ||
35 | 'config2' => 'config2data', | ||
36 | ] | ||
37 | ]; | ||
38 | } | ||
39 | |||
40 | /** | ||
41 | * Executed after each test. | ||
42 | * | ||
43 | * @return void | ||
44 | */ | ||
45 | public function tearDown() | ||
46 | { | ||
47 | if (is_file(self::$_configFields['config']['CONFIG_FILE'])) { | ||
48 | unlink(self::$_configFields['config']['CONFIG_FILE']); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | /** | ||
53 | * Test writeConfig function, valid use case, while being logged in. | ||
54 | */ | ||
55 | public function testWriteConfig() | ||
56 | { | ||
57 | writeConfig(self::$_configFields, true); | ||
58 | |||
59 | include self::$_configFields['config']['CONFIG_FILE']; | ||
60 | $this->assertEquals(self::$_configFields['login'], $GLOBALS['login']); | ||
61 | $this->assertEquals(self::$_configFields['hash'], $GLOBALS['hash']); | ||
62 | $this->assertEquals(self::$_configFields['salt'], $GLOBALS['salt']); | ||
63 | $this->assertEquals(self::$_configFields['timezone'], $GLOBALS['timezone']); | ||
64 | $this->assertEquals(self::$_configFields['title'], $GLOBALS['title']); | ||
65 | $this->assertEquals(self::$_configFields['titleLink'], $GLOBALS['titleLink']); | ||
66 | $this->assertEquals(self::$_configFields['redirector'], $GLOBALS['redirector']); | ||
67 | $this->assertEquals(self::$_configFields['disablesessionprotection'], $GLOBALS['disablesessionprotection']); | ||
68 | $this->assertEquals(self::$_configFields['privateLinkByDefault'], $GLOBALS['privateLinkByDefault']); | ||
69 | $this->assertEquals(self::$_configFields['config']['config1'], $GLOBALS['config']['config1']); | ||
70 | $this->assertEquals(self::$_configFields['config']['config2'], $GLOBALS['config']['config2']); | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * Test writeConfig option while logged in: | ||
75 | * 1. init fields. | ||
76 | * 2. update fields, add new sub config, add new root config. | ||
77 | * 3. rewrite config. | ||
78 | * 4. check result. | ||
79 | */ | ||
80 | public function testWriteConfigFieldUpdate() | ||
81 | { | ||
82 | writeConfig(self::$_configFields, true); | ||
83 | self::$_configFields['title'] = 'ok'; | ||
84 | self::$_configFields['config']['config1'] = 'ok'; | ||
85 | self::$_configFields['config']['config_new'] = 'ok'; | ||
86 | self::$_configFields['new'] = 'should not be saved'; | ||
87 | writeConfig(self::$_configFields, true); | ||
88 | |||
89 | include self::$_configFields['config']['CONFIG_FILE']; | ||
90 | $this->assertEquals('ok', $GLOBALS['title']); | ||
91 | $this->assertEquals('ok', $GLOBALS['config']['config1']); | ||
92 | $this->assertEquals('ok', $GLOBALS['config']['config_new']); | ||
93 | $this->assertFalse(isset($GLOBALS['new'])); | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * Test writeConfig function with an empty array. | ||
98 | * | ||
99 | * @expectedException MissingFieldConfigException | ||
100 | */ | ||
101 | public function testWriteConfigEmpty() | ||
102 | { | ||
103 | writeConfig(array(), true); | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * Test writeConfig function with a missing mandatory field. | ||
108 | * | ||
109 | * @expectedException MissingFieldConfigException | ||
110 | */ | ||
111 | public function testWriteConfigMissingField() | ||
112 | { | ||
113 | unset(self::$_configFields['login']); | ||
114 | writeConfig(self::$_configFields, true); | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * Test writeConfig function while being logged out, and there is no config file existing. | ||
119 | */ | ||
120 | public function testWriteConfigLoggedOutNoFile() | ||
121 | { | ||
122 | writeConfig(self::$_configFields, false); | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * Test writeConfig function while being logged out, and a config file already exists. | ||
127 | * | ||
128 | * @expectedException UnauthorizedConfigException | ||
129 | */ | ||
130 | public function testWriteConfigLoggedOutWithFile() | ||
131 | { | ||
132 | file_put_contents(self::$_configFields['config']['CONFIG_FILE'], ''); | ||
133 | writeConfig(self::$_configFields, false); | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * Test mergeDeprecatedConfig while being logged in: | ||
138 | * 1. init a config file. | ||
139 | * 2. init a options.php file with update value. | ||
140 | * 3. merge. | ||
141 | * 4. check updated value in config file. | ||
142 | */ | ||
143 | public function testMergeDeprecatedConfig() | ||
144 | { | ||
145 | // init | ||
146 | writeConfig(self::$_configFields, true); | ||
147 | $configCopy = self::$_configFields; | ||
148 | $invert = !$configCopy['privateLinkByDefault']; | ||
149 | $configCopy['privateLinkByDefault'] = $invert; | ||
150 | |||
151 | // Use writeConfig to create a options.php | ||
152 | $configCopy['config']['CONFIG_FILE'] = 'tests/options.php'; | ||
153 | writeConfig($configCopy, true); | ||
154 | |||
155 | $this->assertTrue(is_file($configCopy['config']['CONFIG_FILE'])); | ||
156 | |||
157 | // merge configs | ||
158 | mergeDeprecatedConfig(self::$_configFields, true); | ||
159 | |||
160 | // make sure updated field is changed | ||
161 | include self::$_configFields['config']['CONFIG_FILE']; | ||
162 | $this->assertEquals($invert, $GLOBALS['privateLinkByDefault']); | ||
163 | $this->assertFalse(is_file($configCopy['config']['CONFIG_FILE'])); | ||
164 | } | ||
165 | |||
166 | /** | ||
167 | * Test mergeDeprecatedConfig while being logged in without options file. | ||
168 | */ | ||
169 | public function testMergeDeprecatedConfigNoFile() | ||
170 | { | ||
171 | writeConfig(self::$_configFields, true); | ||
172 | mergeDeprecatedConfig(self::$_configFields, true); | ||
173 | |||
174 | include self::$_configFields['config']['CONFIG_FILE']; | ||
175 | $this->assertEquals(self::$_configFields['login'], $GLOBALS['login']); | ||
176 | } | ||
177 | } \ No newline at end of file | ||