diff options
41 files changed, 2105 insertions, 1133 deletions
diff --git a/application/ApplicationUtils.php b/application/ApplicationUtils.php index 978fc9da..e67b2902 100644 --- a/application/ApplicationUtils.php +++ b/application/ApplicationUtils.php | |||
@@ -132,11 +132,11 @@ class ApplicationUtils | |||
132 | /** | 132 | /** |
133 | * Checks Shaarli has the proper access permissions to its resources | 133 | * Checks Shaarli has the proper access permissions to its resources |
134 | * | 134 | * |
135 | * @param array $globalConfig The $GLOBALS['config'] array | 135 | * @param ConfigManager $conf Configuration Manager instance. |
136 | * | 136 | * |
137 | * @return array A list of the detected configuration issues | 137 | * @return array A list of the detected configuration issues |
138 | */ | 138 | */ |
139 | public static function checkResourcePermissions($globalConfig) | 139 | public static function checkResourcePermissions($conf) |
140 | { | 140 | { |
141 | $errors = array(); | 141 | $errors = array(); |
142 | 142 | ||
@@ -145,7 +145,7 @@ class ApplicationUtils | |||
145 | 'application', | 145 | 'application', |
146 | 'inc', | 146 | 'inc', |
147 | 'plugins', | 147 | 'plugins', |
148 | $globalConfig['RAINTPL_TPL'] | 148 | $conf->get('resource.raintpl_tpl'), |
149 | ) as $path) { | 149 | ) as $path) { |
150 | if (! is_readable(realpath($path))) { | 150 | if (! is_readable(realpath($path))) { |
151 | $errors[] = '"'.$path.'" directory is not readable'; | 151 | $errors[] = '"'.$path.'" directory is not readable'; |
@@ -154,10 +154,10 @@ class ApplicationUtils | |||
154 | 154 | ||
155 | // Check cache and data directories are readable and writeable | 155 | // Check cache and data directories are readable and writeable |
156 | foreach (array( | 156 | foreach (array( |
157 | $globalConfig['CACHEDIR'], | 157 | $conf->get('resource.thumbnails_cache'), |
158 | $globalConfig['DATADIR'], | 158 | $conf->get('resource.data_dir'), |
159 | $globalConfig['PAGECACHE'], | 159 | $conf->get('resource.page_cache'), |
160 | $globalConfig['RAINTPL_TMP'] | 160 | $conf->get('resource.raintpl_tmp'), |
161 | ) as $path) { | 161 | ) as $path) { |
162 | if (! is_readable(realpath($path))) { | 162 | if (! is_readable(realpath($path))) { |
163 | $errors[] = '"'.$path.'" directory is not readable'; | 163 | $errors[] = '"'.$path.'" directory is not readable'; |
@@ -169,11 +169,11 @@ class ApplicationUtils | |||
169 | 169 | ||
170 | // Check configuration files are readable and writeable | 170 | // Check configuration files are readable and writeable |
171 | foreach (array( | 171 | foreach (array( |
172 | $globalConfig['CONFIG_FILE'], | 172 | $conf->getConfigFileExt(), |
173 | $globalConfig['DATASTORE'], | 173 | $conf->get('resource.datastore'), |
174 | $globalConfig['IPBANS_FILENAME'], | 174 | $conf->get('resource.ban_file'), |
175 | $globalConfig['LOG_FILE'], | 175 | $conf->get('resource.log'), |
176 | $globalConfig['UPDATECHECK_FILENAME'] | 176 | $conf->get('resource.update_check'), |
177 | ) as $path) { | 177 | ) as $path) { |
178 | if (! is_file(realpath($path))) { | 178 | if (! is_file(realpath($path))) { |
179 | # the file may not exist yet | 179 | # the file may not exist yet |
diff --git a/application/Config.php b/application/Config.php deleted file mode 100644 index 05a59452..00000000 --- a/application/Config.php +++ /dev/null | |||
@@ -1,221 +0,0 @@ | |||
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 = array( | ||
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 | |||
60 | if (isset($config['plugins'])) { | ||
61 | foreach ($config['plugins'] as $key => $value) { | ||
62 | $configStr .= '$GLOBALS[\'plugins\'][\''. $key .'\'] = '.var_export($config['plugins'][$key], true).';'. PHP_EOL; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | if (!file_put_contents($config['config']['CONFIG_FILE'], $configStr) | ||
67 | || strcmp(file_get_contents($config['config']['CONFIG_FILE']), $configStr) != 0 | ||
68 | ) { | ||
69 | throw new Exception( | ||
70 | 'Shaarli could not create the config file. | ||
71 | Please make sure Shaarli has the right to write in the folder is it installed in.' | ||
72 | ); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * Process plugin administration form data and save it in an array. | ||
78 | * | ||
79 | * @param array $formData Data sent by the plugin admin form. | ||
80 | * | ||
81 | * @return array New list of enabled plugin, ordered. | ||
82 | * | ||
83 | * @throws PluginConfigOrderException Plugins can't be sorted because their order is invalid. | ||
84 | */ | ||
85 | function save_plugin_config($formData) | ||
86 | { | ||
87 | // Make sure there are no duplicates in orders. | ||
88 | if (!validate_plugin_order($formData)) { | ||
89 | throw new PluginConfigOrderException(); | ||
90 | } | ||
91 | |||
92 | $plugins = array(); | ||
93 | $newEnabledPlugins = array(); | ||
94 | foreach ($formData as $key => $data) { | ||
95 | if (startsWith($key, 'order')) { | ||
96 | continue; | ||
97 | } | ||
98 | |||
99 | // If there is no order, it means a disabled plugin has been enabled. | ||
100 | if (isset($formData['order_' . $key])) { | ||
101 | $plugins[(int) $formData['order_' . $key]] = $key; | ||
102 | } | ||
103 | else { | ||
104 | $newEnabledPlugins[] = $key; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | // New enabled plugins will be added at the end of order. | ||
109 | $plugins = array_merge($plugins, $newEnabledPlugins); | ||
110 | |||
111 | // Sort plugins by order. | ||
112 | if (!ksort($plugins)) { | ||
113 | throw new PluginConfigOrderException(); | ||
114 | } | ||
115 | |||
116 | $finalPlugins = array(); | ||
117 | // Make plugins order continuous. | ||
118 | foreach ($plugins as $plugin) { | ||
119 | $finalPlugins[] = $plugin; | ||
120 | } | ||
121 | |||
122 | return $finalPlugins; | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * Validate plugin array submitted. | ||
127 | * Will fail if there is duplicate orders value. | ||
128 | * | ||
129 | * @param array $formData Data from submitted form. | ||
130 | * | ||
131 | * @return bool true if ok, false otherwise. | ||
132 | */ | ||
133 | function validate_plugin_order($formData) | ||
134 | { | ||
135 | $orders = array(); | ||
136 | foreach ($formData as $key => $value) { | ||
137 | // No duplicate order allowed. | ||
138 | if (in_array($value, $orders)) { | ||
139 | return false; | ||
140 | } | ||
141 | |||
142 | if (startsWith($key, 'order')) { | ||
143 | $orders[] = $value; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | return true; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * Affect plugin parameters values into plugins array. | ||
152 | * | ||
153 | * @param mixed $plugins Plugins array ($plugins[<plugin_name>]['parameters']['param_name'] = <value>. | ||
154 | * @param mixed $config Plugins configuration. | ||
155 | * | ||
156 | * @return mixed Updated $plugins array. | ||
157 | */ | ||
158 | function load_plugin_parameter_values($plugins, $config) | ||
159 | { | ||
160 | $out = $plugins; | ||
161 | foreach ($plugins as $name => $plugin) { | ||
162 | if (empty($plugin['parameters'])) { | ||
163 | continue; | ||
164 | } | ||
165 | |||
166 | foreach ($plugin['parameters'] as $key => $param) { | ||
167 | if (!empty($config[$key])) { | ||
168 | $out[$name]['parameters'][$key] = $config[$key]; | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | |||
173 | return $out; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * Exception used if a mandatory field is missing in given configuration. | ||
178 | */ | ||
179 | class MissingFieldConfigException extends Exception | ||
180 | { | ||
181 | public $field; | ||
182 | |||
183 | /** | ||
184 | * Construct exception. | ||
185 | * | ||
186 | * @param string $field field name missing. | ||
187 | */ | ||
188 | public function __construct($field) | ||
189 | { | ||
190 | $this->field = $field; | ||
191 | $this->message = 'Configuration value is required for '. $this->field; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * Exception used if an unauthorized attempt to edit configuration has been made. | ||
197 | */ | ||
198 | class UnauthorizedConfigException extends Exception | ||
199 | { | ||
200 | /** | ||
201 | * Construct exception. | ||
202 | */ | ||
203 | public function __construct() | ||
204 | { | ||
205 | $this->message = 'You are not authorized to alter config.'; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | /** | ||
210 | * Exception used if an error occur while saving plugin configuration. | ||
211 | */ | ||
212 | class PluginConfigOrderException extends Exception | ||
213 | { | ||
214 | /** | ||
215 | * Construct exception. | ||
216 | */ | ||
217 | public function __construct() | ||
218 | { | ||
219 | $this->message = 'An error occurred while trying to save plugins loading order.'; | ||
220 | } | ||
221 | } | ||
diff --git a/application/FileUtils.php b/application/FileUtils.php index 6a12ef0e..6cac9825 100644 --- a/application/FileUtils.php +++ b/application/FileUtils.php | |||
@@ -9,11 +9,13 @@ class IOException extends Exception | |||
9 | /** | 9 | /** |
10 | * Construct a new IOException | 10 | * Construct a new IOException |
11 | * | 11 | * |
12 | * @param string $path path to the ressource that cannot be accessed | 12 | * @param string $path path to the resource that cannot be accessed |
13 | * @param string $message Custom exception message. | ||
13 | */ | 14 | */ |
14 | public function __construct($path) | 15 | public function __construct($path, $message = '') |
15 | { | 16 | { |
16 | $this->path = $path; | 17 | $this->path = $path; |
17 | $this->message = 'Error accessing '.$this->path; | 18 | $this->message = empty($message) ? 'Error accessing' : $message; |
19 | $this->message .= PHP_EOL . $this->path; | ||
18 | } | 20 | } |
19 | } | 21 | } |
diff --git a/application/PageBuilder.php b/application/PageBuilder.php index 82580787..7cd88370 100644 --- a/application/PageBuilder.php +++ b/application/PageBuilder.php | |||
@@ -15,12 +15,20 @@ class PageBuilder | |||
15 | private $tpl; | 15 | private $tpl; |
16 | 16 | ||
17 | /** | 17 | /** |
18 | * @var ConfigManager $conf Configuration Manager instance. | ||
19 | */ | ||
20 | protected $conf; | ||
21 | |||
22 | /** | ||
18 | * PageBuilder constructor. | 23 | * PageBuilder constructor. |
19 | * $tpl is initialized at false for lazy loading. | 24 | * $tpl is initialized at false for lazy loading. |
25 | * | ||
26 | * @param ConfigManager $conf Configuration Manager instance (reference). | ||
20 | */ | 27 | */ |
21 | function __construct() | 28 | function __construct(&$conf) |
22 | { | 29 | { |
23 | $this->tpl = false; | 30 | $this->tpl = false; |
31 | $this->conf = $conf; | ||
24 | } | 32 | } |
25 | 33 | ||
26 | /** | 34 | /** |
@@ -33,17 +41,17 @@ class PageBuilder | |||
33 | try { | 41 | try { |
34 | $version = ApplicationUtils::checkUpdate( | 42 | $version = ApplicationUtils::checkUpdate( |
35 | shaarli_version, | 43 | shaarli_version, |
36 | $GLOBALS['config']['UPDATECHECK_FILENAME'], | 44 | $this->conf->get('resource.update_check'), |
37 | $GLOBALS['config']['UPDATECHECK_INTERVAL'], | 45 | $this->conf->get('updates.check_updates_interval'), |
38 | $GLOBALS['config']['ENABLE_UPDATECHECK'], | 46 | $this->conf->get('updates.check_updates'), |
39 | isLoggedIn(), | 47 | isLoggedIn(), |
40 | $GLOBALS['config']['UPDATECHECK_BRANCH'] | 48 | $this->conf->get('updates.check_updates_branch') |
41 | ); | 49 | ); |
42 | $this->tpl->assign('newVersion', escape($version)); | 50 | $this->tpl->assign('newVersion', escape($version)); |
43 | $this->tpl->assign('versionError', ''); | 51 | $this->tpl->assign('versionError', ''); |
44 | 52 | ||
45 | } catch (Exception $exc) { | 53 | } catch (Exception $exc) { |
46 | logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], $exc->getMessage()); | 54 | logm($this->conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], $exc->getMessage()); |
47 | $this->tpl->assign('newVersion', ''); | 55 | $this->tpl->assign('newVersion', ''); |
48 | $this->tpl->assign('versionError', escape($exc->getMessage())); | 56 | $this->tpl->assign('versionError', escape($exc->getMessage())); |
49 | } | 57 | } |
@@ -62,19 +70,24 @@ class PageBuilder | |||
62 | $this->tpl->assign('scripturl', index_url($_SERVER)); | 70 | $this->tpl->assign('scripturl', index_url($_SERVER)); |
63 | $this->tpl->assign('pagetitle', 'Shaarli'); | 71 | $this->tpl->assign('pagetitle', 'Shaarli'); |
64 | $this->tpl->assign('privateonly', !empty($_SESSION['privateonly'])); // Show only private links? | 72 | $this->tpl->assign('privateonly', !empty($_SESSION['privateonly'])); // Show only private links? |
65 | if (!empty($GLOBALS['title'])) { | 73 | if ($this->conf->exists('general.title')) { |
66 | $this->tpl->assign('pagetitle', $GLOBALS['title']); | 74 | $this->tpl->assign('pagetitle', $this->conf->get('general.title')); |
67 | } | 75 | } |
68 | if (!empty($GLOBALS['titleLink'])) { | 76 | if ($this->conf->exists('general.header_link')) { |
69 | $this->tpl->assign('titleLink', $GLOBALS['titleLink']); | 77 | $this->tpl->assign('titleLink', $this->conf->get('general.header_link')); |
70 | } | 78 | } |
71 | if (!empty($GLOBALS['pagetitle'])) { | 79 | if ($this->conf->exists('pagetitle')) { |
72 | $this->tpl->assign('pagetitle', $GLOBALS['pagetitle']); | 80 | $this->tpl->assign('pagetitle', $this->conf->get('pagetitle')); |
73 | } | 81 | } |
74 | $this->tpl->assign('shaarlititle', empty($GLOBALS['title']) ? 'Shaarli': $GLOBALS['title']); | 82 | $this->tpl->assign('shaarlititle', $this->conf->get('title', 'Shaarli')); |
83 | $this->tpl->assign('openshaarli', $this->conf->get('security.open_shaarli', false)); | ||
84 | $this->tpl->assign('showatom', $this->conf->get('feed.show_atom', false)); | ||
85 | $this->tpl->assign('hide_timestamps', $this->conf->get('privacy.hide_timestamps', false)); | ||
75 | if (!empty($GLOBALS['plugin_errors'])) { | 86 | if (!empty($GLOBALS['plugin_errors'])) { |
76 | $this->tpl->assign('plugin_errors', $GLOBALS['plugin_errors']); | 87 | $this->tpl->assign('plugin_errors', $GLOBALS['plugin_errors']); |
77 | } | 88 | } |
89 | // To be removed with a proper theme configuration. | ||
90 | $this->tpl->assign('conf', $this->conf); | ||
78 | } | 91 | } |
79 | 92 | ||
80 | /** | 93 | /** |
@@ -85,7 +98,6 @@ class PageBuilder | |||
85 | */ | 98 | */ |
86 | public function assign($placeholder, $value) | 99 | public function assign($placeholder, $value) |
87 | { | 100 | { |
88 | // Lazy initialization | ||
89 | if ($this->tpl === false) { | 101 | if ($this->tpl === false) { |
90 | $this->initialize(); | 102 | $this->initialize(); |
91 | } | 103 | } |
@@ -101,7 +113,6 @@ class PageBuilder | |||
101 | */ | 113 | */ |
102 | public function assignAll($data) | 114 | public function assignAll($data) |
103 | { | 115 | { |
104 | // Lazy initialization | ||
105 | if ($this->tpl === false) { | 116 | if ($this->tpl === false) { |
106 | $this->initialize(); | 117 | $this->initialize(); |
107 | } | 118 | } |
@@ -113,6 +124,7 @@ class PageBuilder | |||
113 | foreach ($data as $key => $value) { | 124 | foreach ($data as $key => $value) { |
114 | $this->assign($key, $value); | 125 | $this->assign($key, $value); |
115 | } | 126 | } |
127 | return true; | ||
116 | } | 128 | } |
117 | 129 | ||
118 | /** | 130 | /** |
@@ -123,10 +135,10 @@ class PageBuilder | |||
123 | */ | 135 | */ |
124 | public function renderPage($page) | 136 | public function renderPage($page) |
125 | { | 137 | { |
126 | // Lazy initialization | 138 | if ($this->tpl === false) { |
127 | if ($this->tpl===false) { | ||
128 | $this->initialize(); | 139 | $this->initialize(); |
129 | } | 140 | } |
141 | |||
130 | $this->tpl->draw($page); | 142 | $this->tpl->draw($page); |
131 | } | 143 | } |
132 | 144 | ||
diff --git a/application/PluginManager.php b/application/PluginManager.php index 787ac6a9..dca7e63e 100644 --- a/application/PluginManager.php +++ b/application/PluginManager.php | |||
@@ -4,18 +4,10 @@ | |||
4 | * Class PluginManager | 4 | * Class PluginManager |
5 | * | 5 | * |
6 | * Use to manage, load and execute plugins. | 6 | * Use to manage, load and execute plugins. |
7 | * | ||
8 | * Using Singleton design pattern. | ||
9 | */ | 7 | */ |
10 | class PluginManager | 8 | class PluginManager |
11 | { | 9 | { |
12 | /** | 10 | /** |
13 | * PluginManager singleton instance. | ||
14 | * @var PluginManager $instance | ||
15 | */ | ||
16 | private static $instance; | ||
17 | |||
18 | /** | ||
19 | * List of authorized plugins from configuration file. | 11 | * List of authorized plugins from configuration file. |
20 | * @var array $authorizedPlugins | 12 | * @var array $authorizedPlugins |
21 | */ | 13 | */ |
@@ -28,6 +20,11 @@ class PluginManager | |||
28 | private $loadedPlugins = array(); | 20 | private $loadedPlugins = array(); |
29 | 21 | ||
30 | /** | 22 | /** |
23 | * @var ConfigManager Configuration Manager instance. | ||
24 | */ | ||
25 | protected $conf; | ||
26 | |||
27 | /** | ||
31 | * Plugins subdirectory. | 28 | * Plugins subdirectory. |
32 | * @var string $PLUGINS_PATH | 29 | * @var string $PLUGINS_PATH |
33 | */ | 30 | */ |
@@ -40,33 +37,13 @@ class PluginManager | |||
40 | public static $META_EXT = 'meta'; | 37 | public static $META_EXT = 'meta'; |
41 | 38 | ||
42 | /** | 39 | /** |
43 | * Private constructor: new instances not allowed. | 40 | * Constructor. |
44 | */ | ||
45 | private function __construct() | ||
46 | { | ||
47 | } | ||
48 | |||
49 | /** | ||
50 | * Cloning isn't allowed either. | ||
51 | * | ||
52 | * @return void | ||
53 | */ | ||
54 | private function __clone() | ||
55 | { | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * Return existing instance of PluginManager, or create it. | ||
60 | * | 41 | * |
61 | * @return PluginManager instance. | 42 | * @param ConfigManager $conf Configuration Manager instance. |
62 | */ | 43 | */ |
63 | public static function getInstance() | 44 | public function __construct(&$conf) |
64 | { | 45 | { |
65 | if (!(self::$instance instanceof self)) { | 46 | $this->conf = $conf; |
66 | self::$instance = new self(); | ||
67 | } | ||
68 | |||
69 | return self::$instance; | ||
70 | } | 47 | } |
71 | 48 | ||
72 | /** | 49 | /** |
@@ -102,9 +79,9 @@ class PluginManager | |||
102 | /** | 79 | /** |
103 | * Execute all plugins registered hook. | 80 | * Execute all plugins registered hook. |
104 | * | 81 | * |
105 | * @param string $hook name of the hook to trigger. | 82 | * @param string $hook name of the hook to trigger. |
106 | * @param array $data list of data to manipulate passed by reference. | 83 | * @param array $data list of data to manipulate passed by reference. |
107 | * @param array $params additional parameters such as page target. | 84 | * @param array $params additional parameters such as page target. |
108 | * | 85 | * |
109 | * @return void | 86 | * @return void |
110 | */ | 87 | */ |
@@ -122,7 +99,7 @@ class PluginManager | |||
122 | $hookFunction = $this->buildHookName($hook, $plugin); | 99 | $hookFunction = $this->buildHookName($hook, $plugin); |
123 | 100 | ||
124 | if (function_exists($hookFunction)) { | 101 | if (function_exists($hookFunction)) { |
125 | $data = call_user_func($hookFunction, $data); | 102 | $data = call_user_func($hookFunction, $data, $this->conf); |
126 | } | 103 | } |
127 | } | 104 | } |
128 | } | 105 | } |
@@ -148,6 +125,7 @@ class PluginManager | |||
148 | throw new PluginFileNotFoundException($pluginName); | 125 | throw new PluginFileNotFoundException($pluginName); |
149 | } | 126 | } |
150 | 127 | ||
128 | $conf = $this->conf; | ||
151 | include_once $pluginFilePath; | 129 | include_once $pluginFilePath; |
152 | 130 | ||
153 | $this->loadedPlugins[] = $pluginName; | 131 | $this->loadedPlugins[] = $pluginName; |
diff --git a/application/Updater.php b/application/Updater.php index 58c13c07..fd45d17f 100644 --- a/application/Updater.php +++ b/application/Updater.php | |||
@@ -13,14 +13,14 @@ class Updater | |||
13 | protected $doneUpdates; | 13 | protected $doneUpdates; |
14 | 14 | ||
15 | /** | 15 | /** |
16 | * @var array Shaarli's configuration array. | 16 | * @var LinkDB instance. |
17 | */ | 17 | */ |
18 | protected $config; | 18 | protected $linkDB; |
19 | 19 | ||
20 | /** | 20 | /** |
21 | * @var LinkDB instance. | 21 | * @var ConfigManager $conf Configuration Manager instance. |
22 | */ | 22 | */ |
23 | protected $linkDB; | 23 | protected $conf; |
24 | 24 | ||
25 | /** | 25 | /** |
26 | * @var bool True if the user is logged in, false otherwise. | 26 | * @var bool True if the user is logged in, false otherwise. |
@@ -35,16 +35,16 @@ class Updater | |||
35 | /** | 35 | /** |
36 | * Object constructor. | 36 | * Object constructor. |
37 | * | 37 | * |
38 | * @param array $doneUpdates Updates which are already done. | 38 | * @param array $doneUpdates Updates which are already done. |
39 | * @param array $config Shaarli's configuration array. | 39 | * @param LinkDB $linkDB LinkDB instance. |
40 | * @param LinkDB $linkDB LinkDB instance. | 40 | * @oaram ConfigManager $conf Configuration Manager instance. |
41 | * @param boolean $isLoggedIn True if the user is logged in. | 41 | * @param boolean $isLoggedIn True if the user is logged in. |
42 | */ | 42 | */ |
43 | public function __construct($doneUpdates, $config, $linkDB, $isLoggedIn) | 43 | public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn) |
44 | { | 44 | { |
45 | $this->doneUpdates = $doneUpdates; | 45 | $this->doneUpdates = $doneUpdates; |
46 | $this->config = $config; | ||
47 | $this->linkDB = $linkDB; | 46 | $this->linkDB = $linkDB; |
47 | $this->conf = $conf; | ||
48 | $this->isLoggedIn = $isLoggedIn; | 48 | $this->isLoggedIn = $isLoggedIn; |
49 | 49 | ||
50 | // Retrieve all update methods. | 50 | // Retrieve all update methods. |
@@ -114,19 +114,19 @@ class Updater | |||
114 | */ | 114 | */ |
115 | public function updateMethodMergeDeprecatedConfigFile() | 115 | public function updateMethodMergeDeprecatedConfigFile() |
116 | { | 116 | { |
117 | $config_file = $this->config['config']['CONFIG_FILE']; | 117 | if (is_file($this->conf->get('resource.data_dir') . '/options.php')) { |
118 | 118 | include $this->conf->get('resource.data_dir') . '/options.php'; | |
119 | if (is_file($this->config['config']['DATADIR'].'/options.php')) { | ||
120 | include $this->config['config']['DATADIR'].'/options.php'; | ||
121 | 119 | ||
122 | // Load GLOBALS into config | 120 | // Load GLOBALS into config |
121 | $allowedKeys = array_merge(ConfigPhp::$ROOT_KEYS); | ||
122 | $allowedKeys[] = 'config'; | ||
123 | foreach ($GLOBALS as $key => $value) { | 123 | foreach ($GLOBALS as $key => $value) { |
124 | $this->config[$key] = $value; | 124 | if (in_array($key, $allowedKeys)) { |
125 | $this->conf->set($key, $value); | ||
126 | } | ||
125 | } | 127 | } |
126 | $this->config['config']['CONFIG_FILE'] = $config_file; | 128 | $this->conf->write($this->isLoggedIn); |
127 | writeConfig($this->config, $this->isLoggedIn); | 129 | unlink($this->conf->get('resource.data_dir').'/options.php'); |
128 | |||
129 | unlink($this->config['config']['DATADIR'].'/options.php'); | ||
130 | } | 130 | } |
131 | 131 | ||
132 | return true; | 132 | return true; |
@@ -143,7 +143,76 @@ class Updater | |||
143 | $link['tags'] = implode(' ', array_unique(LinkFilter::tagsStrToArray($link['tags'], true))); | 143 | $link['tags'] = implode(' ', array_unique(LinkFilter::tagsStrToArray($link['tags'], true))); |
144 | $this->linkDB[$link['linkdate']] = $link; | 144 | $this->linkDB[$link['linkdate']] = $link; |
145 | } | 145 | } |
146 | $this->linkDB->savedb($this->config['config']['PAGECACHE']); | 146 | $this->linkDB->savedb($this->conf->get('resource.page_cache')); |
147 | return true; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * Move old configuration in PHP to the new config system in JSON format. | ||
152 | * | ||
153 | * Will rename 'config.php' into 'config.save.php' and create 'config.json.php'. | ||
154 | * It will also convert legacy setting keys to the new ones. | ||
155 | */ | ||
156 | public function updateMethodConfigToJson() | ||
157 | { | ||
158 | // JSON config already exists, nothing to do. | ||
159 | if ($this->conf->getConfigIO() instanceof ConfigJson) { | ||
160 | return true; | ||
161 | } | ||
162 | |||
163 | $configPhp = new ConfigPhp(); | ||
164 | $configJson = new ConfigJson(); | ||
165 | $oldConfig = $configPhp->read($this->conf->getConfigFile() . '.php'); | ||
166 | rename($this->conf->getConfigFileExt(), $this->conf->getConfigFile() . '.save.php'); | ||
167 | $this->conf->setConfigIO($configJson); | ||
168 | $this->conf->reload(); | ||
169 | |||
170 | $legacyMap = array_flip(ConfigPhp::$LEGACY_KEYS_MAPPING); | ||
171 | foreach (ConfigPhp::$ROOT_KEYS as $key) { | ||
172 | $this->conf->set($legacyMap[$key], $oldConfig[$key]); | ||
173 | } | ||
174 | |||
175 | // Set sub config keys (config and plugins) | ||
176 | $subConfig = array('config', 'plugins'); | ||
177 | foreach ($subConfig as $sub) { | ||
178 | foreach ($oldConfig[$sub] as $key => $value) { | ||
179 | if (isset($legacyMap[$sub .'.'. $key])) { | ||
180 | $configKey = $legacyMap[$sub .'.'. $key]; | ||
181 | } else { | ||
182 | $configKey = $sub .'.'. $key; | ||
183 | } | ||
184 | $this->conf->set($configKey, $value); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | try{ | ||
189 | $this->conf->write($this->isLoggedIn); | ||
190 | return true; | ||
191 | } catch (IOException $e) { | ||
192 | error_log($e->getMessage()); | ||
193 | return false; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * Escape settings which have been manually escaped in every request in previous versions: | ||
199 | * - general.title | ||
200 | * - general.header_link | ||
201 | * - extras.redirector | ||
202 | * | ||
203 | * @return bool true if the update is successful, false otherwise. | ||
204 | */ | ||
205 | public function escapeUnescapedConfig() | ||
206 | { | ||
207 | try { | ||
208 | $this->conf->set('general.title', escape($this->conf->get('general.title'))); | ||
209 | $this->conf->set('general.header_link', escape($this->conf->get('general.header_link'))); | ||
210 | $this->conf->set('redirector.url', escape($this->conf->get('redirector.url'))); | ||
211 | $this->conf->write($this->isLoggedIn); | ||
212 | } catch (Exception $e) { | ||
213 | error_log($e->getMessage()); | ||
214 | return false; | ||
215 | } | ||
147 | return true; | 216 | return true; |
148 | } | 217 | } |
149 | } | 218 | } |
@@ -203,7 +272,6 @@ class UpdaterException extends Exception | |||
203 | } | 272 | } |
204 | } | 273 | } |
205 | 274 | ||
206 | |||
207 | /** | 275 | /** |
208 | * Read the updates file, and return already done updates. | 276 | * Read the updates file, and return already done updates. |
209 | * | 277 | * |
diff --git a/application/config/ConfigIO.php b/application/config/ConfigIO.php new file mode 100644 index 00000000..2b68fe6a --- /dev/null +++ b/application/config/ConfigIO.php | |||
@@ -0,0 +1,33 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Interface ConfigIO | ||
5 | * | ||
6 | * This describes how Config types should store their configuration. | ||
7 | */ | ||
8 | interface ConfigIO | ||
9 | { | ||
10 | /** | ||
11 | * Read configuration. | ||
12 | * | ||
13 | * @param string $filepath Config file absolute path. | ||
14 | * | ||
15 | * @return array All configuration in an array. | ||
16 | */ | ||
17 | function read($filepath); | ||
18 | |||
19 | /** | ||
20 | * Write configuration. | ||
21 | * | ||
22 | * @param string $filepath Config file absolute path. | ||
23 | * @param array $conf All configuration in an array. | ||
24 | */ | ||
25 | function write($filepath, $conf); | ||
26 | |||
27 | /** | ||
28 | * Get config file extension according to config type. | ||
29 | * | ||
30 | * @return string Config file extension. | ||
31 | */ | ||
32 | function getExtension(); | ||
33 | } | ||
diff --git a/application/config/ConfigJson.php b/application/config/ConfigJson.php new file mode 100644 index 00000000..d07fefee --- /dev/null +++ b/application/config/ConfigJson.php | |||
@@ -0,0 +1,78 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Class ConfigJson (ConfigIO implementation) | ||
5 | * | ||
6 | * Handle Shaarli's JSON configuration file. | ||
7 | */ | ||
8 | class ConfigJson implements ConfigIO | ||
9 | { | ||
10 | /** | ||
11 | * @inheritdoc | ||
12 | */ | ||
13 | function read($filepath) | ||
14 | { | ||
15 | if (! is_readable($filepath)) { | ||
16 | return array(); | ||
17 | } | ||
18 | $data = file_get_contents($filepath); | ||
19 | $data = str_replace(self::getPhpHeaders(), '', $data); | ||
20 | $data = str_replace(self::getPhpSuffix(), '', $data); | ||
21 | $data = json_decode($data, true); | ||
22 | if ($data === null) { | ||
23 | $error = json_last_error(); | ||
24 | throw new Exception('An error occured while parsing JSON file: error code #'. $error); | ||
25 | } | ||
26 | return $data; | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * @inheritdoc | ||
31 | */ | ||
32 | function write($filepath, $conf) | ||
33 | { | ||
34 | // JSON_PRETTY_PRINT is available from PHP 5.4. | ||
35 | $print = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0; | ||
36 | $data = self::getPhpHeaders() . json_encode($conf, $print) . self::getPhpSuffix(); | ||
37 | if (!file_put_contents($filepath, $data)) { | ||
38 | throw new IOException( | ||
39 | $filepath, | ||
40 | 'Shaarli could not create the config file. | ||
41 | Please make sure Shaarli has the right to write in the folder is it installed in.' | ||
42 | ); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | /** | ||
47 | * @inheritdoc | ||
48 | */ | ||
49 | function getExtension() | ||
50 | { | ||
51 | return '.json.php'; | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * The JSON data is wrapped in a PHP file for security purpose. | ||
56 | * This way, even if the file is accessible, credentials and configuration won't be exposed. | ||
57 | * | ||
58 | * Note: this isn't a static field because concatenation isn't supported in field declaration before PHP 5.6. | ||
59 | * | ||
60 | * @return string PHP start tag and comment tag. | ||
61 | */ | ||
62 | public static function getPhpHeaders() | ||
63 | { | ||
64 | return '<?php /*'. PHP_EOL; | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * Get PHP comment closing tags. | ||
69 | * | ||
70 | * Static method for consistency with getPhpHeaders. | ||
71 | * | ||
72 | * @return string PHP comment closing. | ||
73 | */ | ||
74 | public static function getPhpSuffix() | ||
75 | { | ||
76 | return PHP_EOL . '*/ ?>'; | ||
77 | } | ||
78 | } | ||
diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php new file mode 100644 index 00000000..ff41772a --- /dev/null +++ b/application/config/ConfigManager.php | |||
@@ -0,0 +1,392 @@ | |||
1 | <?php | ||
2 | |||
3 | // FIXME! Namespaces... | ||
4 | require_once 'ConfigIO.php'; | ||
5 | require_once 'ConfigJson.php'; | ||
6 | require_once 'ConfigPhp.php'; | ||
7 | |||
8 | /** | ||
9 | * Class ConfigManager | ||
10 | * | ||
11 | * Manages all Shaarli's settings. | ||
12 | * See the documentation for more information on settings: | ||
13 | * - doc/Shaarli-configuration.html | ||
14 | * - https://github.com/shaarli/Shaarli/wiki/Shaarli-configuration | ||
15 | */ | ||
16 | class ConfigManager | ||
17 | { | ||
18 | /** | ||
19 | * @var string Flag telling a setting is not found. | ||
20 | */ | ||
21 | protected static $NOT_FOUND = 'NOT_FOUND'; | ||
22 | |||
23 | /** | ||
24 | * @var string Config folder. | ||
25 | */ | ||
26 | protected $configFile; | ||
27 | |||
28 | /** | ||
29 | * @var array Loaded config array. | ||
30 | */ | ||
31 | protected $loadedConfig; | ||
32 | |||
33 | /** | ||
34 | * @var ConfigIO implementation instance. | ||
35 | */ | ||
36 | protected $configIO; | ||
37 | |||
38 | /** | ||
39 | * Constructor. | ||
40 | */ | ||
41 | public function __construct($configFile = 'data/config') | ||
42 | { | ||
43 | $this->configFile = $configFile; | ||
44 | $this->initialize(); | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * Reset the ConfigManager instance. | ||
49 | */ | ||
50 | public function reset() | ||
51 | { | ||
52 | $this->initialize(); | ||
53 | } | ||
54 | |||
55 | /** | ||
56 | * Rebuild the loaded config array from config files. | ||
57 | */ | ||
58 | public function reload() | ||
59 | { | ||
60 | $this->load(); | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * Initialize the ConfigIO and loaded the conf. | ||
65 | */ | ||
66 | protected function initialize() | ||
67 | { | ||
68 | if (file_exists($this->configFile . '.php')) { | ||
69 | $this->configIO = new ConfigPhp(); | ||
70 | } else { | ||
71 | $this->configIO = new ConfigJson(); | ||
72 | } | ||
73 | $this->load(); | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * Load configuration in the ConfigurationManager. | ||
78 | */ | ||
79 | protected function load() | ||
80 | { | ||
81 | $this->loadedConfig = $this->configIO->read($this->getConfigFileExt()); | ||
82 | $this->setDefaultValues(); | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * Get a setting. | ||
87 | * | ||
88 | * Supports nested settings with dot separated keys. | ||
89 | * Eg. 'config.stuff.option' will find $conf[config][stuff][option], | ||
90 | * or in JSON: | ||
91 | * { "config": { "stuff": {"option": "mysetting" } } } } | ||
92 | * | ||
93 | * @param string $setting Asked setting, keys separated with dots. | ||
94 | * @param string $default Default value if not found. | ||
95 | * | ||
96 | * @return mixed Found setting, or the default value. | ||
97 | */ | ||
98 | public function get($setting, $default = '') | ||
99 | { | ||
100 | // During the ConfigIO transition, map legacy settings to the new ones. | ||
101 | if ($this->configIO instanceof ConfigPhp && isset(ConfigPhp::$LEGACY_KEYS_MAPPING[$setting])) { | ||
102 | $setting = ConfigPhp::$LEGACY_KEYS_MAPPING[$setting]; | ||
103 | } | ||
104 | |||
105 | $settings = explode('.', $setting); | ||
106 | $value = self::getConfig($settings, $this->loadedConfig); | ||
107 | if ($value === self::$NOT_FOUND) { | ||
108 | return $default; | ||
109 | } | ||
110 | return $value; | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * Set a setting, and eventually write it. | ||
115 | * | ||
116 | * Supports nested settings with dot separated keys. | ||
117 | * | ||
118 | * @param string $setting Asked setting, keys separated with dots. | ||
119 | * @param string $value Value to set. | ||
120 | * @param bool $write Write the new setting in the config file, default false. | ||
121 | * @param bool $isLoggedIn User login state, default false. | ||
122 | * | ||
123 | * @throws Exception Invalid | ||
124 | */ | ||
125 | public function set($setting, $value, $write = false, $isLoggedIn = false) | ||
126 | { | ||
127 | if (empty($setting) || ! is_string($setting)) { | ||
128 | throw new Exception('Invalid setting key parameter. String expected, got: '. gettype($setting)); | ||
129 | } | ||
130 | |||
131 | // During the ConfigIO transition, map legacy settings to the new ones. | ||
132 | if ($this->configIO instanceof ConfigPhp && isset(ConfigPhp::$LEGACY_KEYS_MAPPING[$setting])) { | ||
133 | $setting = ConfigPhp::$LEGACY_KEYS_MAPPING[$setting]; | ||
134 | } | ||
135 | |||
136 | $settings = explode('.', $setting); | ||
137 | self::setConfig($settings, $value, $this->loadedConfig); | ||
138 | if ($write) { | ||
139 | $this->write($isLoggedIn); | ||
140 | } | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * Check if a settings exists. | ||
145 | * | ||
146 | * Supports nested settings with dot separated keys. | ||
147 | * | ||
148 | * @param string $setting Asked setting, keys separated with dots. | ||
149 | * | ||
150 | * @return bool true if the setting exists, false otherwise. | ||
151 | */ | ||
152 | public function exists($setting) | ||
153 | { | ||
154 | // During the ConfigIO transition, map legacy settings to the new ones. | ||
155 | if ($this->configIO instanceof ConfigPhp && isset(ConfigPhp::$LEGACY_KEYS_MAPPING[$setting])) { | ||
156 | $setting = ConfigPhp::$LEGACY_KEYS_MAPPING[$setting]; | ||
157 | } | ||
158 | |||
159 | $settings = explode('.', $setting); | ||
160 | $value = self::getConfig($settings, $this->loadedConfig); | ||
161 | if ($value === self::$NOT_FOUND) { | ||
162 | return false; | ||
163 | } | ||
164 | return true; | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * Call the config writer. | ||
169 | * | ||
170 | * @param bool $isLoggedIn User login state. | ||
171 | * | ||
172 | * @return bool True if the configuration has been successfully written, false otherwise. | ||
173 | * | ||
174 | * @throws MissingFieldConfigException: a mandatory field has not been provided in $conf. | ||
175 | * @throws UnauthorizedConfigException: user is not authorize to change configuration. | ||
176 | * @throws IOException: an error occurred while writing the new config file. | ||
177 | */ | ||
178 | public function write($isLoggedIn) | ||
179 | { | ||
180 | // These fields are required in configuration. | ||
181 | $mandatoryFields = array( | ||
182 | 'credentials.login', | ||
183 | 'credentials.hash', | ||
184 | 'credentials.salt', | ||
185 | 'security.session_protection_disabled', | ||
186 | 'general.timezone', | ||
187 | 'general.title', | ||
188 | 'general.header_link', | ||
189 | 'privacy.default_private_links', | ||
190 | 'redirector.url', | ||
191 | ); | ||
192 | |||
193 | // Only logged in user can alter config. | ||
194 | if (is_file($this->getConfigFileExt()) && !$isLoggedIn) { | ||
195 | throw new UnauthorizedConfigException(); | ||
196 | } | ||
197 | |||
198 | // Check that all mandatory fields are provided in $conf. | ||
199 | foreach ($mandatoryFields as $field) { | ||
200 | if (! $this->exists($field)) { | ||
201 | throw new MissingFieldConfigException($field); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | return $this->configIO->write($this->getConfigFileExt(), $this->loadedConfig); | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * Set the config file path (without extension). | ||
210 | * | ||
211 | * @param string $configFile File path. | ||
212 | */ | ||
213 | public function setConfigFile($configFile) | ||
214 | { | ||
215 | $this->configFile = $configFile; | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * Return the configuration file path (without extension). | ||
220 | * | ||
221 | * @return string Config path. | ||
222 | */ | ||
223 | public function getConfigFile() | ||
224 | { | ||
225 | return $this->configFile; | ||
226 | } | ||
227 | |||
228 | /** | ||
229 | * Get the configuration file path with its extension. | ||
230 | * | ||
231 | * @return string Config file path. | ||
232 | */ | ||
233 | public function getConfigFileExt() | ||
234 | { | ||
235 | return $this->configFile . $this->configIO->getExtension(); | ||
236 | } | ||
237 | |||
238 | /** | ||
239 | * Recursive function which find asked setting in the loaded config. | ||
240 | * | ||
241 | * @param array $settings Ordered array which contains keys to find. | ||
242 | * @param array $conf Loaded settings, then sub-array. | ||
243 | * | ||
244 | * @return mixed Found setting or NOT_FOUND flag. | ||
245 | */ | ||
246 | protected static function getConfig($settings, $conf) | ||
247 | { | ||
248 | if (!is_array($settings) || count($settings) == 0) { | ||
249 | return self::$NOT_FOUND; | ||
250 | } | ||
251 | |||
252 | $setting = array_shift($settings); | ||
253 | if (!isset($conf[$setting])) { | ||
254 | return self::$NOT_FOUND; | ||
255 | } | ||
256 | |||
257 | if (count($settings) > 0) { | ||
258 | return self::getConfig($settings, $conf[$setting]); | ||
259 | } | ||
260 | return $conf[$setting]; | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * Recursive function which find asked setting in the loaded config. | ||
265 | * | ||
266 | * @param array $settings Ordered array which contains keys to find. | ||
267 | * @param mixed $value | ||
268 | * @param array $conf Loaded settings, then sub-array. | ||
269 | * | ||
270 | * @return mixed Found setting or NOT_FOUND flag. | ||
271 | */ | ||
272 | protected static function setConfig($settings, $value, &$conf) | ||
273 | { | ||
274 | if (!is_array($settings) || count($settings) == 0) { | ||
275 | return self::$NOT_FOUND; | ||
276 | } | ||
277 | |||
278 | $setting = array_shift($settings); | ||
279 | if (count($settings) > 0) { | ||
280 | return self::setConfig($settings, $value, $conf[$setting]); | ||
281 | } | ||
282 | $conf[$setting] = $value; | ||
283 | } | ||
284 | |||
285 | /** | ||
286 | * Set a bunch of default values allowing Shaarli to start without a config file. | ||
287 | */ | ||
288 | protected function setDefaultValues() | ||
289 | { | ||
290 | $this->setEmpty('resource.data_dir', 'data'); | ||
291 | $this->setEmpty('resource.config', 'data/config.php'); | ||
292 | $this->setEmpty('resource.datastore', 'data/datastore.php'); | ||
293 | $this->setEmpty('resource.ban_file', 'data/ipbans.php'); | ||
294 | $this->setEmpty('resource.updates', 'data/updates.txt'); | ||
295 | $this->setEmpty('resource.log', 'data/log.txt'); | ||
296 | $this->setEmpty('resource.update_check', 'data/lastupdatecheck.txt'); | ||
297 | $this->setEmpty('resource.raintpl_tpl', 'tpl/'); | ||
298 | $this->setEmpty('resource.raintpl_tmp', 'tmp/'); | ||
299 | $this->setEmpty('resource.thumbnails_cache', 'cache'); | ||
300 | $this->setEmpty('resource.page_cache', 'pagecache'); | ||
301 | |||
302 | $this->setEmpty('security.ban_after', 4); | ||
303 | $this->setEmpty('security.ban_duration', 1800); | ||
304 | $this->setEmpty('security.session_protection_disabled', false); | ||
305 | $this->setEmpty('security.open_shaarli', false); | ||
306 | |||
307 | $this->setEmpty('general.header_link', '?'); | ||
308 | $this->setEmpty('general.links_per_page', 20); | ||
309 | $this->setEmpty('general.enabled_plugins', array('qrcode')); | ||
310 | |||
311 | $this->setEmpty('updates.check_updates', false); | ||
312 | $this->setEmpty('updates.check_updates_branch', 'stable'); | ||
313 | $this->setEmpty('updates.check_updates_interval', 86400); | ||
314 | |||
315 | $this->setEmpty('feed.rss_permalinks', true); | ||
316 | $this->setEmpty('feed.show_atom', false); | ||
317 | |||
318 | $this->setEmpty('privacy.default_private_links', false); | ||
319 | $this->setEmpty('privacy.hide_public_links', false); | ||
320 | $this->setEmpty('privacy.hide_timestamps', false); | ||
321 | |||
322 | $this->setEmpty('thumbnail.enable_thumbnails', true); | ||
323 | $this->setEmpty('thumbnail.enable_localcache', true); | ||
324 | |||
325 | $this->setEmpty('redirector.url', ''); | ||
326 | $this->setEmpty('redirector.encode_url', true); | ||
327 | |||
328 | $this->setEmpty('plugins', array()); | ||
329 | } | ||
330 | |||
331 | /** | ||
332 | * Set only if the setting does not exists. | ||
333 | * | ||
334 | * @param string $key Setting key. | ||
335 | * @param mixed $value Setting value. | ||
336 | */ | ||
337 | public function setEmpty($key, $value) | ||
338 | { | ||
339 | if (! $this->exists($key)) { | ||
340 | $this->set($key, $value); | ||
341 | } | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * @return ConfigIO | ||
346 | */ | ||
347 | public function getConfigIO() | ||
348 | { | ||
349 | return $this->configIO; | ||
350 | } | ||
351 | |||
352 | /** | ||
353 | * @param ConfigIO $configIO | ||
354 | */ | ||
355 | public function setConfigIO($configIO) | ||
356 | { | ||
357 | $this->configIO = $configIO; | ||
358 | } | ||
359 | } | ||
360 | |||
361 | /** | ||
362 | * Exception used if a mandatory field is missing in given configuration. | ||
363 | */ | ||
364 | class MissingFieldConfigException extends Exception | ||
365 | { | ||
366 | public $field; | ||
367 | |||
368 | /** | ||
369 | * Construct exception. | ||
370 | * | ||
371 | * @param string $field field name missing. | ||
372 | */ | ||
373 | public function __construct($field) | ||
374 | { | ||
375 | $this->field = $field; | ||
376 | $this->message = 'Configuration value is required for '. $this->field; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | /** | ||
381 | * Exception used if an unauthorized attempt to edit configuration has been made. | ||
382 | */ | ||
383 | class UnauthorizedConfigException extends Exception | ||
384 | { | ||
385 | /** | ||
386 | * Construct exception. | ||
387 | */ | ||
388 | public function __construct() | ||
389 | { | ||
390 | $this->message = 'You are not authorized to alter config.'; | ||
391 | } | ||
392 | } | ||
diff --git a/application/config/ConfigPhp.php b/application/config/ConfigPhp.php new file mode 100644 index 00000000..27187b66 --- /dev/null +++ b/application/config/ConfigPhp.php | |||
@@ -0,0 +1,132 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Class ConfigPhp (ConfigIO implementation) | ||
5 | * | ||
6 | * Handle Shaarli's legacy PHP configuration file. | ||
7 | * Note: this is only designed to support the transition to JSON configuration. | ||
8 | */ | ||
9 | class ConfigPhp implements ConfigIO | ||
10 | { | ||
11 | /** | ||
12 | * @var array List of config key without group. | ||
13 | */ | ||
14 | public static $ROOT_KEYS = array( | ||
15 | 'login', | ||
16 | 'hash', | ||
17 | 'salt', | ||
18 | 'timezone', | ||
19 | 'title', | ||
20 | 'titleLink', | ||
21 | 'redirector', | ||
22 | 'disablesessionprotection', | ||
23 | 'privateLinkByDefault', | ||
24 | ); | ||
25 | |||
26 | /** | ||
27 | * Map legacy config keys with the new ones. | ||
28 | * If ConfigPhp is used, getting <newkey> will actually look for <legacykey>. | ||
29 | * The Updater will use this array to transform keys when switching to JSON. | ||
30 | * | ||
31 | * @var array current key => legacy key. | ||
32 | */ | ||
33 | public static $LEGACY_KEYS_MAPPING = array( | ||
34 | 'credentials.login' => 'login', | ||
35 | 'credentials.hash' => 'hash', | ||
36 | 'credentials.salt' => 'salt', | ||
37 | 'resource.data_dir' => 'config.DATADIR', | ||
38 | 'resource.config' => 'config.CONFIG_FILE', | ||
39 | 'resource.datastore' => 'config.DATASTORE', | ||
40 | 'resource.updates' => 'config.UPDATES_FILE', | ||
41 | 'resource.log' => 'config.LOG_FILE', | ||
42 | 'resource.update_check' => 'config.UPDATECHECK_FILENAME', | ||
43 | 'resource.raintpl_tpl' => 'config.RAINTPL_TPL', | ||
44 | 'resource.raintpl_tmp' => 'config.RAINTPL_TMP', | ||
45 | 'resource.thumbnails_cache' => 'config.CACHEDIR', | ||
46 | 'resource.page_cache' => 'config.PAGECACHE', | ||
47 | 'resource.ban_file' => 'config.IPBANS_FILENAME', | ||
48 | 'security.session_protection_disabled' => 'disablesessionprotection', | ||
49 | 'security.ban_after' => 'config.BAN_AFTER', | ||
50 | 'security.ban_duration' => 'config.BAN_DURATION', | ||
51 | 'general.title' => 'title', | ||
52 | 'general.timezone' => 'timezone', | ||
53 | 'general.header_link' => 'titleLink', | ||
54 | 'updates.check_updates' => 'config.ENABLE_UPDATECHECK', | ||
55 | 'updates.check_updates_branch' => 'config.UPDATECHECK_BRANCH', | ||
56 | 'updates.check_updates_interval' => 'config.UPDATECHECK_INTERVAL', | ||
57 | 'privacy.default_private_links' => 'privateLinkByDefault', | ||
58 | 'feed.rss_permalinks' => 'config.ENABLE_RSS_PERMALINKS', | ||
59 | 'general.links_per_page' => 'config.LINKS_PER_PAGE', | ||
60 | 'thumbnail.enable_thumbnails' => 'config.ENABLE_THUMBNAILS', | ||
61 | 'thumbnail.enable_localcache' => 'config.ENABLE_LOCALCACHE', | ||
62 | 'general.enabled_plugins' => 'config.ENABLED_PLUGINS', | ||
63 | 'redirector.url' => 'redirector', | ||
64 | 'redirector.encode_url' => 'config.REDIRECTOR_URLENCODE', | ||
65 | 'feed.show_atom' => 'config.SHOW_ATOM', | ||
66 | 'privacy.hide_public_links' => 'config.HIDE_PUBLIC_LINKS', | ||
67 | 'privacy.hide_timestamps' => 'config.HIDE_TIMESTAMPS', | ||
68 | 'security.open_shaarli' => 'config.OPEN_SHAARLI', | ||
69 | ); | ||
70 | |||
71 | /** | ||
72 | * @inheritdoc | ||
73 | */ | ||
74 | function read($filepath) | ||
75 | { | ||
76 | if (! file_exists($filepath) || ! is_readable($filepath)) { | ||
77 | return array(); | ||
78 | } | ||
79 | |||
80 | include $filepath; | ||
81 | |||
82 | $out = array(); | ||
83 | foreach (self::$ROOT_KEYS as $key) { | ||
84 | $out[$key] = $GLOBALS[$key]; | ||
85 | } | ||
86 | $out['config'] = $GLOBALS['config']; | ||
87 | $out['plugins'] = !empty($GLOBALS['plugins']) ? $GLOBALS['plugins'] : array(); | ||
88 | return $out; | ||
89 | } | ||
90 | |||
91 | /** | ||
92 | * @inheritdoc | ||
93 | */ | ||
94 | function write($filepath, $conf) | ||
95 | { | ||
96 | $configStr = '<?php '. PHP_EOL; | ||
97 | foreach (self::$ROOT_KEYS as $key) { | ||
98 | if (isset($conf[$key])) { | ||
99 | $configStr .= '$GLOBALS[\'' . $key . '\'] = ' . var_export($conf[$key], true) . ';' . PHP_EOL; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | // Store all $conf['config'] | ||
104 | foreach ($conf['config'] as $key => $value) { | ||
105 | $configStr .= '$GLOBALS[\'config\'][\''. $key .'\'] = '.var_export($conf['config'][$key], true).';'. PHP_EOL; | ||
106 | } | ||
107 | |||
108 | if (isset($conf['plugins'])) { | ||
109 | foreach ($conf['plugins'] as $key => $value) { | ||
110 | $configStr .= '$GLOBALS[\'plugins\'][\''. $key .'\'] = '.var_export($conf['plugins'][$key], true).';'. PHP_EOL; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | if (!file_put_contents($filepath, $configStr) | ||
115 | || strcmp(file_get_contents($filepath), $configStr) != 0 | ||
116 | ) { | ||
117 | throw new IOException( | ||
118 | $filepath, | ||
119 | 'Shaarli could not create the config file. | ||
120 | Please make sure Shaarli has the right to write in the folder is it installed in.' | ||
121 | ); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * @inheritdoc | ||
127 | */ | ||
128 | function getExtension() | ||
129 | { | ||
130 | return '.php'; | ||
131 | } | ||
132 | } | ||
diff --git a/application/config/ConfigPlugin.php b/application/config/ConfigPlugin.php new file mode 100644 index 00000000..047d2b03 --- /dev/null +++ b/application/config/ConfigPlugin.php | |||
@@ -0,0 +1,120 @@ | |||
1 | <?php | ||
2 | /** | ||
3 | * Plugin configuration helper functions. | ||
4 | * | ||
5 | * Note: no access to configuration files here. | ||
6 | */ | ||
7 | |||
8 | /** | ||
9 | * Process plugin administration form data and save it in an array. | ||
10 | * | ||
11 | * @param array $formData Data sent by the plugin admin form. | ||
12 | * | ||
13 | * @return array New list of enabled plugin, ordered. | ||
14 | * | ||
15 | * @throws PluginConfigOrderException Plugins can't be sorted because their order is invalid. | ||
16 | */ | ||
17 | function save_plugin_config($formData) | ||
18 | { | ||
19 | // Make sure there are no duplicates in orders. | ||
20 | if (!validate_plugin_order($formData)) { | ||
21 | throw new PluginConfigOrderException(); | ||
22 | } | ||
23 | |||
24 | $plugins = array(); | ||
25 | $newEnabledPlugins = array(); | ||
26 | foreach ($formData as $key => $data) { | ||
27 | if (startsWith($key, 'order')) { | ||
28 | continue; | ||
29 | } | ||
30 | |||
31 | // If there is no order, it means a disabled plugin has been enabled. | ||
32 | if (isset($formData['order_' . $key])) { | ||
33 | $plugins[(int) $formData['order_' . $key]] = $key; | ||
34 | } | ||
35 | else { | ||
36 | $newEnabledPlugins[] = $key; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | // New enabled plugins will be added at the end of order. | ||
41 | $plugins = array_merge($plugins, $newEnabledPlugins); | ||
42 | |||
43 | // Sort plugins by order. | ||
44 | if (!ksort($plugins)) { | ||
45 | throw new PluginConfigOrderException(); | ||
46 | } | ||
47 | |||
48 | $finalPlugins = array(); | ||
49 | // Make plugins order continuous. | ||
50 | foreach ($plugins as $plugin) { | ||
51 | $finalPlugins[] = $plugin; | ||
52 | } | ||
53 | |||
54 | return $finalPlugins; | ||
55 | } | ||
56 | |||
57 | /** | ||
58 | * Validate plugin array submitted. | ||
59 | * Will fail if there is duplicate orders value. | ||
60 | * | ||
61 | * @param array $formData Data from submitted form. | ||
62 | * | ||
63 | * @return bool true if ok, false otherwise. | ||
64 | */ | ||
65 | function validate_plugin_order($formData) | ||
66 | { | ||
67 | $orders = array(); | ||
68 | foreach ($formData as $key => $value) { | ||
69 | // No duplicate order allowed. | ||
70 | if (in_array($value, $orders)) { | ||
71 | return false; | ||
72 | } | ||
73 | |||
74 | if (startsWith($key, 'order')) { | ||
75 | $orders[] = $value; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | return true; | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * Affect plugin parameters values into plugins array. | ||
84 | * | ||
85 | * @param mixed $plugins Plugins array ($plugins[<plugin_name>]['parameters']['param_name'] = <value>. | ||
86 | * @param mixed $conf Plugins configuration. | ||
87 | * | ||
88 | * @return mixed Updated $plugins array. | ||
89 | */ | ||
90 | function load_plugin_parameter_values($plugins, $conf) | ||
91 | { | ||
92 | $out = $plugins; | ||
93 | foreach ($plugins as $name => $plugin) { | ||
94 | if (empty($plugin['parameters'])) { | ||
95 | continue; | ||
96 | } | ||
97 | |||
98 | foreach ($plugin['parameters'] as $key => $param) { | ||
99 | if (!empty($conf[$key])) { | ||
100 | $out[$name]['parameters'][$key] = $conf[$key]; | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | |||
105 | return $out; | ||
106 | } | ||
107 | |||
108 | /** | ||
109 | * Exception used if an error occur while saving plugin configuration. | ||
110 | */ | ||
111 | class PluginConfigOrderException extends Exception | ||
112 | { | ||
113 | /** | ||
114 | * Construct exception. | ||
115 | */ | ||
116 | public function __construct() | ||
117 | { | ||
118 | $this->message = 'An error occurred while trying to save plugins loading order.'; | ||
119 | } | ||
120 | } | ||
diff --git a/composer.json b/composer.json index 2ded0920..e419dc11 100644 --- a/composer.json +++ b/composer.json | |||
@@ -1,11 +1,17 @@ | |||
1 | { | 1 | { |
2 | "name": "shaarli/shaarli", | 2 | "name": "shaarli/shaarli", |
3 | "description": "The personal, minimalist, super-fast, no-database delicious clone", | 3 | "description": "The personal, minimalist, super-fast, database-free bookmarking service", |
4 | "type": "project", | ||
4 | "license": "MIT", | 5 | "license": "MIT", |
6 | "homepage": "https://github.com/shaarli/Shaarli", | ||
5 | "support": { | 7 | "support": { |
6 | "issues": "https://github.com/shaarli/Shaarli/issues" | 8 | "issues": "https://github.com/shaarli/Shaarli/issues", |
9 | "wiki": "https://github.com/shaarli/Shaarli/wiki" | ||
10 | }, | ||
11 | "keywords": ["bookmark", "link", "share", "web"], | ||
12 | "require": { | ||
13 | "php": ">=5.3.4" | ||
7 | }, | 14 | }, |
8 | "require": {}, | ||
9 | "require-dev": { | 15 | "require-dev": { |
10 | "phpmd/phpmd" : "@stable", | 16 | "phpmd/phpmd" : "@stable", |
11 | "phpunit/phpunit": "4.8.*", | 17 | "phpunit/phpunit": "4.8.*", |
@@ -22,114 +22,13 @@ if (date_default_timezone_get() == '') { | |||
22 | date_default_timezone_set('UTC'); | 22 | date_default_timezone_set('UTC'); |
23 | } | 23 | } |
24 | 24 | ||
25 | /* ----------------------------------------------------------------------------- | ||
26 | * Hardcoded parameters | ||
27 | * You should not touch any code below (or at your own risks!) | ||
28 | * (These parameters can be overwritten by editing the file /data/config.php) | ||
29 | * ----------------------------------------------------------------------------- | ||
30 | */ | ||
31 | |||
32 | /* | ||
33 | * Shaarli directories & configuration files | ||
34 | */ | ||
35 | // Data subdirectory | ||
36 | $GLOBALS['config']['DATADIR'] = 'data'; | ||
37 | |||
38 | // Main configuration file | ||
39 | $GLOBALS['config']['CONFIG_FILE'] = $GLOBALS['config']['DATADIR'].'/config.php'; | ||
40 | |||
41 | // Link datastore | ||
42 | $GLOBALS['config']['DATASTORE'] = $GLOBALS['config']['DATADIR'].'/datastore.php'; | ||
43 | |||
44 | // Banned IPs | ||
45 | $GLOBALS['config']['IPBANS_FILENAME'] = $GLOBALS['config']['DATADIR'].'/ipbans.php'; | ||
46 | |||
47 | // Processed updates file. | ||
48 | $GLOBALS['config']['UPDATES_FILE'] = $GLOBALS['config']['DATADIR'].'/updates.txt'; | ||
49 | |||
50 | // Access log | ||
51 | $GLOBALS['config']['LOG_FILE'] = $GLOBALS['config']['DATADIR'].'/log.txt'; | ||
52 | |||
53 | // For updates check of Shaarli | ||
54 | $GLOBALS['config']['UPDATECHECK_FILENAME'] = $GLOBALS['config']['DATADIR'].'/lastupdatecheck.txt'; | ||
55 | |||
56 | // Set ENABLE_UPDATECHECK to disabled by default. | ||
57 | $GLOBALS['config']['ENABLE_UPDATECHECK'] = false; | ||
58 | |||
59 | // RainTPL cache directory (keep the trailing slash!) | ||
60 | $GLOBALS['config']['RAINTPL_TMP'] = 'tmp/'; | ||
61 | // Raintpl template directory (keep the trailing slash!) | ||
62 | $GLOBALS['config']['RAINTPL_TPL'] = 'tpl/'; | ||
63 | |||
64 | // Thumbnail cache directory | ||
65 | $GLOBALS['config']['CACHEDIR'] = 'cache'; | ||
66 | |||
67 | // Atom & RSS feed cache directory | ||
68 | $GLOBALS['config']['PAGECACHE'] = 'pagecache'; | ||
69 | |||
70 | /* | ||
71 | * Global configuration | ||
72 | */ | ||
73 | // Ban IP after this many failures | ||
74 | $GLOBALS['config']['BAN_AFTER'] = 4; | ||
75 | // Ban duration for IP address after login failures (in seconds) | ||
76 | $GLOBALS['config']['BAN_DURATION'] = 1800; | ||
77 | |||
78 | // Feed options | ||
79 | // Enable RSS permalinks by default. | ||
80 | // This corresponds to the default behavior of shaarli before this was added as an option. | ||
81 | $GLOBALS['config']['ENABLE_RSS_PERMALINKS'] = true; | ||
82 | // If true, an extra "ATOM feed" button will be displayed in the toolbar | ||
83 | $GLOBALS['config']['SHOW_ATOM'] = false; | ||
84 | |||
85 | // Link display options | ||
86 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] = false; | ||
87 | $GLOBALS['config']['HIDE_TIMESTAMPS'] = false; | ||
88 | $GLOBALS['config']['LINKS_PER_PAGE'] = 20; | ||
89 | |||
90 | // Open Shaarli (true): anyone can add/edit/delete links without having to login | ||
91 | $GLOBALS['config']['OPEN_SHAARLI'] = false; | ||
92 | |||
93 | // Thumbnails | ||
94 | // Display thumbnails in links | ||
95 | $GLOBALS['config']['ENABLE_THUMBNAILS'] = true; | ||
96 | // Store thumbnails in a local cache | ||
97 | $GLOBALS['config']['ENABLE_LOCALCACHE'] = true; | ||
98 | |||
99 | // Update check frequency for Shaarli. 86400 seconds=24 hours | ||
100 | $GLOBALS['config']['UPDATECHECK_BRANCH'] = 'stable'; | ||
101 | $GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400; | ||
102 | |||
103 | $GLOBALS['config']['REDIRECTOR_URLENCODE'] = true; | ||
104 | |||
105 | /* | ||
106 | * Plugin configuration | ||
107 | * | ||
108 | * Warning: order matters! | ||
109 | * | ||
110 | * These settings may be be overriden in: | ||
111 | * - data/config.php | ||
112 | * - each plugin's configuration file | ||
113 | */ | ||
114 | //$GLOBALS['config']['ENABLED_PLUGINS'] = array( | ||
115 | // 'qrcode', 'archiveorg', 'readityourself', 'demo_plugin', 'playvideos', | ||
116 | // 'wallabag', 'markdown', 'addlink_toolbar', | ||
117 | //); | ||
118 | $GLOBALS['config']['ENABLED_PLUGINS'] = array('qrcode'); | ||
119 | |||
120 | // Initialize plugin parameters array. | ||
121 | $GLOBALS['plugins'] = array(); | ||
122 | |||
123 | // PubSubHubbub support. Put an empty string to disable, or put your hub url here to enable. | ||
124 | $GLOBALS['config']['PUBSUBHUB_URL'] = ''; | ||
125 | |||
126 | /* | 25 | /* |
127 | * PHP configuration | 26 | * PHP configuration |
128 | */ | 27 | */ |
129 | define('shaarli_version', '0.7.0'); | 28 | define('shaarli_version', '0.7.0'); |
130 | 29 | ||
131 | // http://server.com/x/shaarli --> /shaarli/ | 30 | // http://server.com/x/shaarli --> /shaarli/ |
132 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); | 31 | define('WEB_PATH', substr($_SERVER['REQUEST_URI'], 0, 1+strrpos($_SERVER['REQUEST_URI'], '/', 0))); |
133 | 32 | ||
134 | // High execution time in case of problematic imports/exports. | 33 | // High execution time in case of problematic imports/exports. |
135 | ini_set('max_input_time','60'); | 34 | ini_set('max_input_time','60'); |
@@ -144,17 +43,13 @@ error_reporting(E_ALL^E_WARNING); | |||
144 | // See all errors (for debugging only) | 43 | // See all errors (for debugging only) |
145 | //error_reporting(-1); | 44 | //error_reporting(-1); |
146 | 45 | ||
147 | /* | ||
148 | * User configuration | ||
149 | */ | ||
150 | if (is_file($GLOBALS['config']['CONFIG_FILE'])) { | ||
151 | require_once $GLOBALS['config']['CONFIG_FILE']; | ||
152 | } | ||
153 | 46 | ||
154 | // Shaarli library | 47 | // Shaarli library |
155 | require_once 'application/ApplicationUtils.php'; | 48 | require_once 'application/ApplicationUtils.php'; |
156 | require_once 'application/Cache.php'; | 49 | require_once 'application/Cache.php'; |
157 | require_once 'application/CachedPage.php'; | 50 | require_once 'application/CachedPage.php'; |
51 | require_once 'application/config/ConfigManager.php'; | ||
52 | require_once 'application/config/ConfigPlugin.php'; | ||
158 | require_once 'application/FeedBuilder.php'; | 53 | require_once 'application/FeedBuilder.php'; |
159 | require_once 'application/FileUtils.php'; | 54 | require_once 'application/FileUtils.php'; |
160 | require_once 'application/HttpUtils.php'; | 55 | require_once 'application/HttpUtils.php'; |
@@ -166,10 +61,10 @@ require_once 'application/PageBuilder.php'; | |||
166 | require_once 'application/TimeZone.php'; | 61 | require_once 'application/TimeZone.php'; |
167 | require_once 'application/Url.php'; | 62 | require_once 'application/Url.php'; |
168 | require_once 'application/Utils.php'; | 63 | require_once 'application/Utils.php'; |
169 | require_once 'application/Config.php'; | ||
170 | require_once 'application/PluginManager.php'; | 64 | require_once 'application/PluginManager.php'; |
171 | require_once 'application/Router.php'; | 65 | require_once 'application/Router.php'; |
172 | require_once 'application/Updater.php'; | 66 | require_once 'application/Updater.php'; |
67 | require_once 'inc/rain.tpl.class.php'; | ||
173 | 68 | ||
174 | // Ensure the PHP version is supported | 69 | // Ensure the PHP version is supported |
175 | try { | 70 | try { |
@@ -210,15 +105,18 @@ if (isset($_COOKIE['shaarli']) && !is_session_id_valid($_COOKIE['shaarli'])) { | |||
210 | $_COOKIE['shaarli'] = session_id(); | 105 | $_COOKIE['shaarli'] = session_id(); |
211 | } | 106 | } |
212 | 107 | ||
213 | include "inc/rain.tpl.class.php"; //include Rain TPL | 108 | $conf = new ConfigManager(); |
214 | raintpl::$tpl_dir = $GLOBALS['config']['RAINTPL_TPL']; // template directory | 109 | $conf->setEmpty('general.timezone', date_default_timezone_get()); |
215 | raintpl::$cache_dir = $GLOBALS['config']['RAINTPL_TMP']; // cache directory | 110 | $conf->setEmpty('general.title', 'Shared links on '. escape(index_url($_SERVER))); |
111 | RainTPL::$tpl_dir = $conf->get('resource.raintpl_tpl'); // template directory | ||
112 | RainTPL::$cache_dir = $conf->get('resource.raintpl_tmp'); // cache directory | ||
216 | 113 | ||
217 | $pluginManager = PluginManager::getInstance(); | 114 | $pluginManager = new PluginManager($conf); |
218 | $pluginManager->load($GLOBALS['config']['ENABLED_PLUGINS']); | 115 | $pluginManager->load($conf->get('general.enabled_plugins')); |
219 | 116 | ||
220 | ob_start(); // Output buffering for the page cache. | 117 | date_default_timezone_set($conf->get('general.timezone', 'UTC')); |
221 | 118 | ||
119 | ob_start(); // Output buffering for the page cache. | ||
222 | 120 | ||
223 | // In case stupid admin has left magic_quotes enabled in php.ini: | 121 | // In case stupid admin has left magic_quotes enabled in php.ini: |
224 | if (get_magic_quotes_gpc()) | 122 | if (get_magic_quotes_gpc()) |
@@ -235,18 +133,9 @@ header("Cache-Control: no-store, no-cache, must-revalidate"); | |||
235 | header("Cache-Control: post-check=0, pre-check=0", false); | 133 | header("Cache-Control: post-check=0, pre-check=0", false); |
236 | header("Pragma: no-cache"); | 134 | header("Pragma: no-cache"); |
237 | 135 | ||
238 | // Handling of old config file which do not have the new parameters. | 136 | if (! is_file($conf->getConfigFileExt())) { |
239 | if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.escape(index_url($_SERVER)); | ||
240 | if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); | ||
241 | if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']=''; | ||
242 | if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false; | ||
243 | if (empty($GLOBALS['privateLinkByDefault'])) $GLOBALS['privateLinkByDefault']=false; | ||
244 | if (empty($GLOBALS['titleLink'])) $GLOBALS['titleLink']='?'; | ||
245 | // I really need to rewrite Shaarli with a proper configuation manager. | ||
246 | |||
247 | if (! is_file($GLOBALS['config']['CONFIG_FILE'])) { | ||
248 | // Ensure Shaarli has proper access to its resources | 137 | // Ensure Shaarli has proper access to its resources |
249 | $errors = ApplicationUtils::checkResourcePermissions($GLOBALS['config']); | 138 | $errors = ApplicationUtils::checkResourcePermissions($conf); |
250 | 139 | ||
251 | if ($errors != array()) { | 140 | if ($errors != array()) { |
252 | $message = '<p>Insufficient permissions:</p><ul>'; | 141 | $message = '<p>Insufficient permissions:</p><ul>'; |
@@ -262,15 +151,11 @@ if (! is_file($GLOBALS['config']['CONFIG_FILE'])) { | |||
262 | } | 151 | } |
263 | 152 | ||
264 | // Display the installation form if no existing config is found | 153 | // Display the installation form if no existing config is found |
265 | install(); | 154 | install($conf); |
266 | } | 155 | } |
267 | 156 | ||
268 | $GLOBALS['title'] = !empty($GLOBALS['title']) ? escape($GLOBALS['title']) : ''; | ||
269 | $GLOBALS['titleLink'] = !empty($GLOBALS['titleLink']) ? escape($GLOBALS['titleLink']) : ''; | ||
270 | $GLOBALS['redirector'] = !empty($GLOBALS['redirector']) ? escape($GLOBALS['redirector']) : ''; | ||
271 | |||
272 | // a token depending of deployment salt, user password, and the current ip | 157 | // a token depending of deployment salt, user password, and the current ip |
273 | define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GLOBALS['salt'])); | 158 | define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['REMOTE_ADDR'] . $conf->get('credentials.salt'))); |
274 | 159 | ||
275 | // Sniff browser language and set date format accordingly. | 160 | // Sniff browser language and set date format accordingly. |
276 | if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { | 161 | if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { |
@@ -278,17 +163,21 @@ if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { | |||
278 | } | 163 | } |
279 | header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling. | 164 | header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling. |
280 | 165 | ||
281 | //================================================================================================== | 166 | /** |
282 | // Checking session state (i.e. is the user still logged in) | 167 | * Checking session state (i.e. is the user still logged in) |
283 | //================================================================================================== | 168 | * |
284 | 169 | * @param ConfigManager $conf The configuration manager. | |
285 | function setup_login_state() { | 170 | * |
286 | if ($GLOBALS['config']['OPEN_SHAARLI']) { | 171 | * @return bool: true if the user is logged in, false otherwise. |
172 | */ | ||
173 | function setup_login_state($conf) | ||
174 | { | ||
175 | if ($conf->get('security.open_shaarli')) { | ||
287 | return true; | 176 | return true; |
288 | } | 177 | } |
289 | $userIsLoggedIn = false; // By default, we do not consider the user as logged in; | 178 | $userIsLoggedIn = false; // By default, we do not consider the user as logged in; |
290 | $loginFailure = false; // If set to true, every attempt to authenticate the user will fail. This indicates that an important condition isn't met. | 179 | $loginFailure = false; // If set to true, every attempt to authenticate the user will fail. This indicates that an important condition isn't met. |
291 | if (!isset($GLOBALS['login'])) { | 180 | if (! $conf->exists('credentials.login')) { |
292 | $userIsLoggedIn = false; // Shaarli is not configured yet. | 181 | $userIsLoggedIn = false; // Shaarli is not configured yet. |
293 | $loginFailure = true; | 182 | $loginFailure = true; |
294 | } | 183 | } |
@@ -296,13 +185,13 @@ function setup_login_state() { | |||
296 | $_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN && | 185 | $_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN && |
297 | !$loginFailure) | 186 | !$loginFailure) |
298 | { | 187 | { |
299 | fillSessionInfo(); | 188 | fillSessionInfo($conf); |
300 | $userIsLoggedIn = true; | 189 | $userIsLoggedIn = true; |
301 | } | 190 | } |
302 | // If session does not exist on server side, or IP address has changed, or session has expired, logout. | 191 | // If session does not exist on server side, or IP address has changed, or session has expired, logout. |
303 | if (empty($_SESSION['uid']) || | 192 | if (empty($_SESSION['uid']) |
304 | ($GLOBALS['disablesessionprotection']==false && $_SESSION['ip']!=allIPs()) || | 193 | || ($conf->get('security.session_protection_disabled') == false && $_SESSION['ip'] != allIPs()) |
305 | time() >= $_SESSION['expires_on']) | 194 | || time() >= $_SESSION['expires_on']) |
306 | { | 195 | { |
307 | logout(); | 196 | logout(); |
308 | $userIsLoggedIn = false; | 197 | $userIsLoggedIn = false; |
@@ -320,22 +209,26 @@ function setup_login_state() { | |||
320 | 209 | ||
321 | return $userIsLoggedIn; | 210 | return $userIsLoggedIn; |
322 | } | 211 | } |
323 | $userIsLoggedIn = setup_login_state(); | 212 | $userIsLoggedIn = setup_login_state($conf); |
324 | 213 | ||
325 | // ------------------------------------------------------------------------------------------ | 214 | /** |
326 | // PubSubHubbub protocol support (if enabled) [UNTESTED] | 215 | * PubSubHubbub protocol support (if enabled) [UNTESTED] |
327 | // (Source: http://aldarone.fr/les-flux-rss-shaarli-et-pubsubhubbub/ ) | 216 | * (Source: http://aldarone.fr/les-flux-rss-shaarli-et-pubsubhubbub/ ) |
328 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) include './publisher.php'; | 217 | * |
329 | function pubsubhub() | 218 | * @param ConfigManager $conf Configuration Manager instance. |
219 | */ | ||
220 | function pubsubhub($conf) | ||
330 | { | 221 | { |
331 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) | 222 | $pshUrl = $conf->get('config.PUBSUBHUB_URL'); |
223 | if (!empty($pshUrl)) | ||
332 | { | 224 | { |
333 | $p = new Publisher($GLOBALS['config']['PUBSUBHUB_URL']); | 225 | include_once './publisher.php'; |
334 | $topic_url = array ( | 226 | $p = new Publisher($pshUrl); |
335 | index_url($_SERVER).'?do=atom', | 227 | $topic_url = array ( |
336 | index_url($_SERVER).'?do=rss' | 228 | index_url($_SERVER).'?do=atom', |
337 | ); | 229 | index_url($_SERVER).'?do=rss' |
338 | $p->publish_update($topic_url); | 230 | ); |
231 | $p->publish_update($topic_url); | ||
339 | } | 232 | } |
340 | } | 233 | } |
341 | 234 | ||
@@ -345,32 +238,46 @@ function pubsubhub() | |||
345 | // Returns the IP address of the client (Used to prevent session cookie hijacking.) | 238 | // Returns the IP address of the client (Used to prevent session cookie hijacking.) |
346 | function allIPs() | 239 | function allIPs() |
347 | { | 240 | { |
348 | $ip = $_SERVER["REMOTE_ADDR"]; | 241 | $ip = $_SERVER['REMOTE_ADDR']; |
349 | // Then we use more HTTP headers to prevent session hijacking from users behind the same proxy. | 242 | // Then we use more HTTP headers to prevent session hijacking from users behind the same proxy. |
350 | if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip=$ip.'_'.$_SERVER['HTTP_X_FORWARDED_FOR']; } | 243 | if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip=$ip.'_'.$_SERVER['HTTP_X_FORWARDED_FOR']; } |
351 | if (isset($_SERVER['HTTP_CLIENT_IP'])) { $ip=$ip.'_'.$_SERVER['HTTP_CLIENT_IP']; } | 244 | if (isset($_SERVER['HTTP_CLIENT_IP'])) { $ip=$ip.'_'.$_SERVER['HTTP_CLIENT_IP']; } |
352 | return $ip; | 245 | return $ip; |
353 | } | 246 | } |
354 | 247 | ||
355 | function fillSessionInfo() { | 248 | /** |
249 | * Load user session. | ||
250 | * | ||
251 | * @param ConfigManager $conf Configuration Manager instance. | ||
252 | */ | ||
253 | function fillSessionInfo($conf) | ||
254 | { | ||
356 | $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // Generate unique random number (different than phpsessionid) | 255 | $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // Generate unique random number (different than phpsessionid) |
357 | $_SESSION['ip']=allIPs(); // We store IP address(es) of the client to make sure session is not hijacked. | 256 | $_SESSION['ip']=allIPs(); // We store IP address(es) of the client to make sure session is not hijacked. |
358 | $_SESSION['username']=$GLOBALS['login']; | 257 | $_SESSION['username']= $conf->get('credentials.login'); |
359 | $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration. | 258 | $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration. |
360 | } | 259 | } |
361 | 260 | ||
362 | // Check that user/password is correct. | 261 | /** |
363 | function check_auth($login,$password) | 262 | * Check that user/password is correct. |
263 | * | ||
264 | * @param string $login Username | ||
265 | * @param string $password User password | ||
266 | * @param ConfigManager $conf Configuration Manager instance. | ||
267 | * | ||
268 | * @return bool: authentication successful or not. | ||
269 | */ | ||
270 | function check_auth($login, $password, $conf) | ||
364 | { | 271 | { |
365 | $hash = sha1($password.$login.$GLOBALS['salt']); | 272 | $hash = sha1($password . $login . $conf->get('credentials.salt')); |
366 | if ($login==$GLOBALS['login'] && $hash==$GLOBALS['hash']) | 273 | if ($login == $conf->get('credentials.login') && $hash == $conf->get('credentials.hash')) |
367 | { // Login/password is correct. | 274 | { // Login/password is correct. |
368 | fillSessionInfo(); | 275 | fillSessionInfo($conf); |
369 | logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], 'Login successful'); | 276 | logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Login successful'); |
370 | return True; | 277 | return true; |
371 | } | 278 | } |
372 | logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], 'Login failed for user '.$login); | 279 | logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Login failed for user '.$login); |
373 | return False; | 280 | return false; |
374 | } | 281 | } |
375 | 282 | ||
376 | // Returns true if the user is logged in. | 283 | // Returns true if the user is logged in. |
@@ -395,34 +302,62 @@ function logout() { | |||
395 | // ------------------------------------------------------------------------------------------ | 302 | // ------------------------------------------------------------------------------------------ |
396 | // Brute force protection system | 303 | // Brute force protection system |
397 | // Several consecutive failed logins will ban the IP address for 30 minutes. | 304 | // Several consecutive failed logins will ban the IP address for 30 minutes. |
398 | if (!is_file($GLOBALS['config']['IPBANS_FILENAME'])) file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export(array('FAILURES'=>array(),'BANS'=>array()),true).";\n?>"); | 305 | if (!is_file($conf->get('resource.ban_file', 'data/ipbans.php'))) { |
399 | include $GLOBALS['config']['IPBANS_FILENAME']; | 306 | // FIXME! globals |
400 | // Signal a failed login. Will ban the IP if too many failures: | 307 | file_put_contents( |
401 | function ban_loginFailed() | 308 | $conf->get('resource.ban_file', 'data/ipbans.php'), |
309 | "<?php\n\$GLOBALS['IPBANS']=".var_export(array('FAILURES'=>array(),'BANS'=>array()),true).";\n?>" | ||
310 | ); | ||
311 | } | ||
312 | include $conf->get('resource.ban_file', 'data/ipbans.php'); | ||
313 | /** | ||
314 | * Signal a failed login. Will ban the IP if too many failures: | ||
315 | * | ||
316 | * @param ConfigManager $conf Configuration Manager instance. | ||
317 | */ | ||
318 | function ban_loginFailed($conf) | ||
402 | { | 319 | { |
403 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; | 320 | $ip = $_SERVER['REMOTE_ADDR']; |
321 | $gb = $GLOBALS['IPBANS']; | ||
404 | if (!isset($gb['FAILURES'][$ip])) $gb['FAILURES'][$ip]=0; | 322 | if (!isset($gb['FAILURES'][$ip])) $gb['FAILURES'][$ip]=0; |
405 | $gb['FAILURES'][$ip]++; | 323 | $gb['FAILURES'][$ip]++; |
406 | if ($gb['FAILURES'][$ip]>($GLOBALS['config']['BAN_AFTER']-1)) | 324 | if ($gb['FAILURES'][$ip] > ($conf->get('security.ban_after') - 1)) |
407 | { | 325 | { |
408 | $gb['BANS'][$ip]=time()+$GLOBALS['config']['BAN_DURATION']; | 326 | $gb['BANS'][$ip] = time() + $conf->get('security.ban_after', 1800); |
409 | logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], 'IP address banned from login'); | 327 | logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'IP address banned from login'); |
410 | } | 328 | } |
411 | $GLOBALS['IPBANS'] = $gb; | 329 | $GLOBALS['IPBANS'] = $gb; |
412 | file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); | 330 | file_put_contents( |
331 | $conf->get('resource.ban_file', 'data/ipbans.php'), | ||
332 | "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>" | ||
333 | ); | ||
413 | } | 334 | } |
414 | 335 | ||
415 | // Signals a successful login. Resets failed login counter. | 336 | /** |
416 | function ban_loginOk() | 337 | * Signals a successful login. Resets failed login counter. |
338 | * | ||
339 | * @param ConfigManager $conf Configuration Manager instance. | ||
340 | */ | ||
341 | function ban_loginOk($conf) | ||
417 | { | 342 | { |
418 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; | 343 | $ip = $_SERVER['REMOTE_ADDR']; |
344 | $gb = $GLOBALS['IPBANS']; | ||
419 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); | 345 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); |
420 | $GLOBALS['IPBANS'] = $gb; | 346 | $GLOBALS['IPBANS'] = $gb; |
421 | file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); | 347 | file_put_contents( |
348 | $conf->get('resource.ban_file', 'data/ipbans.php'), | ||
349 | "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>" | ||
350 | ); | ||
422 | } | 351 | } |
423 | 352 | ||
424 | // Checks if the user CAN login. If 'true', the user can try to login. | 353 | /** |
425 | function ban_canLogin() | 354 | * Checks if the user CAN login. If 'true', the user can try to login. |
355 | * | ||
356 | * @param ConfigManager $conf Configuration Manager instance. | ||
357 | * | ||
358 | * @return bool: true if the user is allowed to login. | ||
359 | */ | ||
360 | function ban_canLogin($conf) | ||
426 | { | 361 | { |
427 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; | 362 | $ip=$_SERVER["REMOTE_ADDR"]; $gb=$GLOBALS['IPBANS']; |
428 | if (isset($gb['BANS'][$ip])) | 363 | if (isset($gb['BANS'][$ip])) |
@@ -430,9 +365,12 @@ function ban_canLogin() | |||
430 | // User is banned. Check if the ban has expired: | 365 | // User is banned. Check if the ban has expired: |
431 | if ($gb['BANS'][$ip]<=time()) | 366 | if ($gb['BANS'][$ip]<=time()) |
432 | { // Ban expired, user can try to login again. | 367 | { // Ban expired, user can try to login again. |
433 | logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], 'Ban lifted.'); | 368 | logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Ban lifted.'); |
434 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); | 369 | unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); |
435 | file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); | 370 | file_put_contents( |
371 | $conf->get('resource.ban_file', 'data/ipbans.php'), | ||
372 | "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>" | ||
373 | ); | ||
436 | return true; // Ban has expired, user can login. | 374 | return true; // Ban has expired, user can login. |
437 | } | 375 | } |
438 | return false; // User is banned. | 376 | return false; // User is banned. |
@@ -444,10 +382,12 @@ function ban_canLogin() | |||
444 | // Process login form: Check if login/password is correct. | 382 | // Process login form: Check if login/password is correct. |
445 | if (isset($_POST['login'])) | 383 | if (isset($_POST['login'])) |
446 | { | 384 | { |
447 | if (!ban_canLogin()) die('I said: NO. You are banned for the moment. Go away.'); | 385 | if (!ban_canLogin($conf)) die('I said: NO. You are banned for the moment. Go away.'); |
448 | if (isset($_POST['password']) && tokenOk($_POST['token']) && (check_auth($_POST['login'], $_POST['password']))) | 386 | if (isset($_POST['password']) |
449 | { // Login/password is OK. | 387 | && tokenOk($_POST['token']) |
450 | ban_loginOk(); | 388 | && (check_auth($_POST['login'], $_POST['password'], $conf)) |
389 | ) { // Login/password is OK. | ||
390 | ban_loginOk($conf); | ||
451 | // If user wants to keep the session cookie even after the browser closes: | 391 | // If user wants to keep the session cookie even after the browser closes: |
452 | if (!empty($_POST['longlastingsession'])) | 392 | if (!empty($_POST['longlastingsession'])) |
453 | { | 393 | { |
@@ -495,7 +435,7 @@ if (isset($_POST['login'])) | |||
495 | } | 435 | } |
496 | else | 436 | else |
497 | { | 437 | { |
498 | ban_loginFailed(); | 438 | ban_loginFailed($conf); |
499 | $redir = '&username='. $_POST['login']; | 439 | $redir = '&username='. $_POST['login']; |
500 | if (isset($_GET['post'])) { | 440 | if (isset($_GET['post'])) { |
501 | $redir .= '&post=' . urlencode($_GET['post']); | 441 | $redir .= '&post=' . urlencode($_GET['post']); |
@@ -543,10 +483,16 @@ function getMaxFileSize() | |||
543 | // Token should be used in any form which acts on data (create,update,delete,import...). | 483 | // Token should be used in any form which acts on data (create,update,delete,import...). |
544 | if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array(); // Token are attached to the session. | 484 | if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array(); // Token are attached to the session. |
545 | 485 | ||
546 | // Returns a token. | 486 | /** |
547 | function getToken() | 487 | * Returns a token. |
488 | * | ||
489 | * @param ConfigManager $conf Configuration Manager instance. | ||
490 | * | ||
491 | * @return string token. | ||
492 | */ | ||
493 | function getToken($conf) | ||
548 | { | 494 | { |
549 | $rnd = sha1(uniqid('',true).'_'.mt_rand().$GLOBALS['salt']); // We generate a random string. | 495 | $rnd = sha1(uniqid('', true) .'_'. mt_rand() . $conf->get('credentials.salt')); // We generate a random string. |
550 | $_SESSION['tokens'][$rnd]=1; // Store it on the server side. | 496 | $_SESSION['tokens'][$rnd]=1; // Store it on the server side. |
551 | return $rnd; | 497 | return $rnd; |
552 | } | 498 | } |
@@ -563,15 +509,18 @@ function tokenOk($token) | |||
563 | return false; // Wrong token, or already used. | 509 | return false; // Wrong token, or already used. |
564 | } | 510 | } |
565 | 511 | ||
566 | // ------------------------------------------------------------------------------------------ | 512 | /** |
567 | // Daily RSS feed: 1 RSS entry per day giving all the links on that day. | 513 | * Daily RSS feed: 1 RSS entry per day giving all the links on that day. |
568 | // Gives the last 7 days (which have links). | 514 | * Gives the last 7 days (which have links). |
569 | // This RSS feed cannot be filtered. | 515 | * This RSS feed cannot be filtered. |
570 | function showDailyRSS() { | 516 | * |
517 | * @param ConfigManager $conf Configuration Manager instance. | ||
518 | */ | ||
519 | function showDailyRSS($conf) { | ||
571 | // Cache system | 520 | // Cache system |
572 | $query = $_SERVER['QUERY_STRING']; | 521 | $query = $_SERVER['QUERY_STRING']; |
573 | $cache = new CachedPage( | 522 | $cache = new CachedPage( |
574 | $GLOBALS['config']['PAGECACHE'], | 523 | $conf->get('config.PAGE_CACHE'), |
575 | page_url($_SERVER), | 524 | page_url($_SERVER), |
576 | startsWith($query,'do=dailyrss') && !isLoggedIn() | 525 | startsWith($query,'do=dailyrss') && !isLoggedIn() |
577 | ); | 526 | ); |
@@ -584,11 +533,11 @@ function showDailyRSS() { | |||
584 | // If cached was not found (or not usable), then read the database and build the response: | 533 | // If cached was not found (or not usable), then read the database and build the response: |
585 | // Read links from database (and filter private links if used it not logged in). | 534 | // Read links from database (and filter private links if used it not logged in). |
586 | $LINKSDB = new LinkDB( | 535 | $LINKSDB = new LinkDB( |
587 | $GLOBALS['config']['DATASTORE'], | 536 | $conf->get('resource.datastore'), |
588 | isLoggedIn(), | 537 | isLoggedIn(), |
589 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], | 538 | $conf->get('privacy.hide_public_links'), |
590 | $GLOBALS['redirector'], | 539 | $conf->get('redirector.url'), |
591 | $GLOBALS['config']['REDIRECTOR_URLENCODE'] | 540 | $conf->get('redirector.encode_url') |
592 | ); | 541 | ); |
593 | 542 | ||
594 | /* Some Shaarlies may have very few links, so we need to look | 543 | /* Some Shaarlies may have very few links, so we need to look |
@@ -600,7 +549,7 @@ function showDailyRSS() { | |||
600 | } | 549 | } |
601 | rsort($linkdates); | 550 | rsort($linkdates); |
602 | $nb_of_days = 7; // We take 7 days. | 551 | $nb_of_days = 7; // We take 7 days. |
603 | $today = Date('Ymd'); | 552 | $today = date('Ymd'); |
604 | $days = array(); | 553 | $days = array(); |
605 | 554 | ||
606 | foreach ($linkdates as $linkdate) { | 555 | foreach ($linkdates as $linkdate) { |
@@ -622,7 +571,7 @@ function showDailyRSS() { | |||
622 | $pageaddr = escape(index_url($_SERVER)); | 571 | $pageaddr = escape(index_url($_SERVER)); |
623 | echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">'; | 572 | echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">'; |
624 | echo '<channel>'; | 573 | echo '<channel>'; |
625 | echo '<title>Daily - '. $GLOBALS['title'] . '</title>'; | 574 | echo '<title>Daily - '. $conf->get('general.title') . '</title>'; |
626 | echo '<link>'. $pageaddr .'</link>'; | 575 | echo '<link>'. $pageaddr .'</link>'; |
627 | echo '<description>Daily shared links</description>'; | 576 | echo '<description>Daily shared links</description>'; |
628 | echo '<language>en-en</language>'; | 577 | echo '<language>en-en</language>'; |
@@ -641,8 +590,8 @@ function showDailyRSS() { | |||
641 | // We pre-format some fields for proper output. | 590 | // We pre-format some fields for proper output. |
642 | foreach ($linkdates as $linkdate) { | 591 | foreach ($linkdates as $linkdate) { |
643 | $l = $LINKSDB[$linkdate]; | 592 | $l = $LINKSDB[$linkdate]; |
644 | $l['formatedDescription'] = format_description($l['description'], $GLOBALS['redirector']); | 593 | $l['formatedDescription'] = format_description($l['description'], $conf->get('redirector.url')); |
645 | $l['thumbnail'] = thumbnail($l['url']); | 594 | $l['thumbnail'] = thumbnail($conf, $l['url']); |
646 | $l_date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $l['linkdate']); | 595 | $l_date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $l['linkdate']); |
647 | $l['timestamp'] = $l_date->getTimestamp(); | 596 | $l['timestamp'] = $l_date->getTimestamp(); |
648 | if (startsWith($l['url'], '?')) { | 597 | if (startsWith($l['url'], '?')) { |
@@ -653,11 +602,12 @@ function showDailyRSS() { | |||
653 | 602 | ||
654 | // Then build the HTML for this day: | 603 | // Then build the HTML for this day: |
655 | $tpl = new RainTPL; | 604 | $tpl = new RainTPL; |
656 | $tpl->assign('title', $GLOBALS['title']); | 605 | $tpl->assign('title', $conf->get('general.title')); |
657 | $tpl->assign('daydate', $dayDate->getTimestamp()); | 606 | $tpl->assign('daydate', $dayDate->getTimestamp()); |
658 | $tpl->assign('absurl', $absurl); | 607 | $tpl->assign('absurl', $absurl); |
659 | $tpl->assign('links', $links); | 608 | $tpl->assign('links', $links); |
660 | $tpl->assign('rssdate', escape($dayDate->format(DateTime::RSS))); | 609 | $tpl->assign('rssdate', escape($dayDate->format(DateTime::RSS))); |
610 | $tpl->assign('hide_timestamps', $conf->get('privacy.hide_timestamps', false)); | ||
661 | $html = $tpl->draw('dailyrss', $return_string=true); | 611 | $html = $tpl->draw('dailyrss', $return_string=true); |
662 | 612 | ||
663 | echo $html . PHP_EOL; | 613 | echo $html . PHP_EOL; |
@@ -672,12 +622,14 @@ function showDailyRSS() { | |||
672 | /** | 622 | /** |
673 | * Show the 'Daily' page. | 623 | * Show the 'Daily' page. |
674 | * | 624 | * |
675 | * @param PageBuilder $pageBuilder Template engine wrapper. | 625 | * @param PageBuilder $pageBuilder Template engine wrapper. |
676 | * @param LinkDB $LINKSDB LinkDB instance. | 626 | * @param LinkDB $LINKSDB LinkDB instance. |
627 | * @param ConfigManager $conf Configuration Manager instance. | ||
628 | * @param PluginManager $pluginManager Plugin Manager instane. | ||
677 | */ | 629 | */ |
678 | function showDaily($pageBuilder, $LINKSDB) | 630 | function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) |
679 | { | 631 | { |
680 | $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. | 632 | $day=date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. |
681 | if (isset($_GET['day'])) $day=$_GET['day']; | 633 | if (isset($_GET['day'])) $day=$_GET['day']; |
682 | 634 | ||
683 | $days = $LINKSDB->days(); | 635 | $days = $LINKSDB->days(); |
@@ -705,8 +657,8 @@ function showDaily($pageBuilder, $LINKSDB) | |||
705 | $taglist = explode(' ',$link['tags']); | 657 | $taglist = explode(' ',$link['tags']); |
706 | uasort($taglist, 'strcasecmp'); | 658 | uasort($taglist, 'strcasecmp'); |
707 | $linksToDisplay[$key]['taglist']=$taglist; | 659 | $linksToDisplay[$key]['taglist']=$taglist; |
708 | $linksToDisplay[$key]['formatedDescription'] = format_description($link['description'], $GLOBALS['redirector']); | 660 | $linksToDisplay[$key]['formatedDescription'] = format_description($link['description'], $conf->get('redirector.url')); |
709 | $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']); | 661 | $linksToDisplay[$key]['thumbnail'] = thumbnail($conf, $link['url']); |
710 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | 662 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); |
711 | $linksToDisplay[$key]['timestamp'] = $date->getTimestamp(); | 663 | $linksToDisplay[$key]['timestamp'] = $date->getTimestamp(); |
712 | } | 664 | } |
@@ -741,7 +693,7 @@ function showDaily($pageBuilder, $LINKSDB) | |||
741 | 'previousday' => $previousday, | 693 | 'previousday' => $previousday, |
742 | 'nextday' => $nextday, | 694 | 'nextday' => $nextday, |
743 | ); | 695 | ); |
744 | $pluginManager = PluginManager::getInstance(); | 696 | |
745 | $pluginManager->executeHooks('render_daily', $data, array('loggedin' => isLoggedIn())); | 697 | $pluginManager->executeHooks('render_daily', $data, array('loggedin' => isLoggedIn())); |
746 | 698 | ||
747 | foreach ($data as $key => $value) { | 699 | foreach ($data as $key => $value) { |
@@ -752,36 +704,46 @@ function showDaily($pageBuilder, $LINKSDB) | |||
752 | exit; | 704 | exit; |
753 | } | 705 | } |
754 | 706 | ||
755 | // Renders the linklist | 707 | /** |
756 | function showLinkList($PAGE, $LINKSDB) { | 708 | * Renders the linklist |
757 | buildLinkList($PAGE,$LINKSDB); // Compute list of links to display | 709 | * |
710 | * @param pageBuilder $PAGE pageBuilder instance. | ||
711 | * @param LinkDB $LINKSDB LinkDB instance. | ||
712 | * @param ConfigManager $conf Configuration Manager instance. | ||
713 | * @param PluginManager $pluginManager Plugin Manager instance. | ||
714 | */ | ||
715 | function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager) { | ||
716 | buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager); // Compute list of links to display | ||
758 | $PAGE->renderPage('linklist'); | 717 | $PAGE->renderPage('linklist'); |
759 | } | 718 | } |
760 | 719 | ||
761 | 720 | /** | |
762 | // ------------------------------------------------------------------------------------------ | 721 | * Render HTML page (according to URL parameters and user rights) |
763 | // Render HTML page (according to URL parameters and user rights) | 722 | * |
764 | function renderPage() | 723 | * @param ConfigManager $conf Configuration Manager instance. |
724 | * @param PluginManager $pluginManager Plugin Manager instance, | ||
725 | */ | ||
726 | function renderPage($conf, $pluginManager) | ||
765 | { | 727 | { |
766 | $LINKSDB = new LinkDB( | 728 | $LINKSDB = new LinkDB( |
767 | $GLOBALS['config']['DATASTORE'], | 729 | $conf->get('resource.datastore'), |
768 | isLoggedIn(), | 730 | isLoggedIn(), |
769 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], | 731 | $conf->get('privacy.hide_public_links'), |
770 | $GLOBALS['redirector'], | 732 | $conf->get('redirector.url'), |
771 | $GLOBALS['config']['REDIRECTOR_URLENCODE'] | 733 | $conf->get('redirector.encode_url') |
772 | ); | 734 | ); |
773 | 735 | ||
774 | $updater = new Updater( | 736 | $updater = new Updater( |
775 | read_updates_file($GLOBALS['config']['UPDATES_FILE']), | 737 | read_updates_file($conf->get('resource.updates')), |
776 | $GLOBALS, | ||
777 | $LINKSDB, | 738 | $LINKSDB, |
739 | $conf, | ||
778 | isLoggedIn() | 740 | isLoggedIn() |
779 | ); | 741 | ); |
780 | try { | 742 | try { |
781 | $newUpdates = $updater->update(); | 743 | $newUpdates = $updater->update(); |
782 | if (! empty($newUpdates)) { | 744 | if (! empty($newUpdates)) { |
783 | write_updates_file( | 745 | write_updates_file( |
784 | $GLOBALS['config']['UPDATES_FILE'], | 746 | $conf->get('resource.updates'), |
785 | $updater->getDoneUpdates() | 747 | $updater->getDoneUpdates() |
786 | ); | 748 | ); |
787 | } | 749 | } |
@@ -790,7 +752,7 @@ function renderPage() | |||
790 | die($e->getMessage()); | 752 | die($e->getMessage()); |
791 | } | 753 | } |
792 | 754 | ||
793 | $PAGE = new PageBuilder(); | 755 | $PAGE = new PageBuilder($conf); |
794 | $PAGE->assign('linkcount', count($LINKSDB)); | 756 | $PAGE->assign('linkcount', count($LINKSDB)); |
795 | $PAGE->assign('privateLinkcount', count_private($LINKSDB)); | 757 | $PAGE->assign('privateLinkcount', count_private($LINKSDB)); |
796 | 758 | ||
@@ -805,7 +767,7 @@ function renderPage() | |||
805 | 'header', | 767 | 'header', |
806 | 'footer', | 768 | 'footer', |
807 | ); | 769 | ); |
808 | $pluginManager = PluginManager::getInstance(); | 770 | |
809 | foreach($common_hooks as $name) { | 771 | foreach($common_hooks as $name) { |
810 | $plugin_data = array(); | 772 | $plugin_data = array(); |
811 | $pluginManager->executeHooks('render_' . $name, $plugin_data, | 773 | $pluginManager->executeHooks('render_' . $name, $plugin_data, |
@@ -820,8 +782,8 @@ function renderPage() | |||
820 | // -------- Display login form. | 782 | // -------- Display login form. |
821 | if ($targetPage == Router::$PAGE_LOGIN) | 783 | if ($targetPage == Router::$PAGE_LOGIN) |
822 | { | 784 | { |
823 | if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; } // No need to login for open Shaarli | 785 | if ($conf->get('security.open_shaarli')) { header('Location: ?'); exit; } // No need to login for open Shaarli |
824 | $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful. | 786 | $token=''; if (ban_canLogin($conf)) $token=getToken($conf); // Do not waste token generation if not useful. |
825 | $PAGE->assign('token',$token); | 787 | $PAGE->assign('token',$token); |
826 | if (isset($_GET['username'])) { | 788 | if (isset($_GET['username'])) { |
827 | $PAGE->assign('username', escape($_GET['username'])); | 789 | $PAGE->assign('username', escape($_GET['username'])); |
@@ -833,7 +795,7 @@ function renderPage() | |||
833 | // -------- User wants to logout. | 795 | // -------- User wants to logout. |
834 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) | 796 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) |
835 | { | 797 | { |
836 | invalidateCaches($GLOBALS['config']['PAGECACHE']); | 798 | invalidateCaches($conf->get('resource.page_cache')); |
837 | logout(); | 799 | logout(); |
838 | header('Location: ?'); | 800 | header('Location: ?'); |
839 | exit; | 801 | exit; |
@@ -850,7 +812,7 @@ function renderPage() | |||
850 | foreach($links as $link) | 812 | foreach($links as $link) |
851 | { | 813 | { |
852 | $permalink='?'.escape(smallhash($link['linkdate'])); | 814 | $permalink='?'.escape(smallhash($link['linkdate'])); |
853 | $thumb=lazyThumbnail($link['url'],$permalink); | 815 | $thumb=lazyThumbnail($conf, $link['url'],$permalink); |
854 | if ($thumb!='') // Only output links which have a thumbnail. | 816 | if ($thumb!='') // Only output links which have a thumbnail. |
855 | { | 817 | { |
856 | $link['thumbnail']=$thumb; // Thumbnail HTML code. | 818 | $link['thumbnail']=$thumb; // Thumbnail HTML code. |
@@ -922,7 +884,7 @@ function renderPage() | |||
922 | 884 | ||
923 | // Daily page. | 885 | // Daily page. |
924 | if ($targetPage == Router::$PAGE_DAILY) { | 886 | if ($targetPage == Router::$PAGE_DAILY) { |
925 | showDaily($PAGE, $LINKSDB); | 887 | showDaily($PAGE, $LINKSDB, $conf, $pluginManager); |
926 | } | 888 | } |
927 | 889 | ||
928 | // ATOM and RSS feed. | 890 | // ATOM and RSS feed. |
@@ -933,7 +895,7 @@ function renderPage() | |||
933 | // Cache system | 895 | // Cache system |
934 | $query = $_SERVER['QUERY_STRING']; | 896 | $query = $_SERVER['QUERY_STRING']; |
935 | $cache = new CachedPage( | 897 | $cache = new CachedPage( |
936 | $GLOBALS['config']['PAGECACHE'], | 898 | $conf->get('resource.page_cache'), |
937 | page_url($_SERVER), | 899 | page_url($_SERVER), |
938 | startsWith($query,'do='. $targetPage) && !isLoggedIn() | 900 | startsWith($query,'do='. $targetPage) && !isLoggedIn() |
939 | ); | 901 | ); |
@@ -946,15 +908,15 @@ function renderPage() | |||
946 | // Generate data. | 908 | // Generate data. |
947 | $feedGenerator = new FeedBuilder($LINKSDB, $feedType, $_SERVER, $_GET, isLoggedIn()); | 909 | $feedGenerator = new FeedBuilder($LINKSDB, $feedType, $_SERVER, $_GET, isLoggedIn()); |
948 | $feedGenerator->setLocale(strtolower(setlocale(LC_COLLATE, 0))); | 910 | $feedGenerator->setLocale(strtolower(setlocale(LC_COLLATE, 0))); |
949 | $feedGenerator->setHideDates($GLOBALS['config']['HIDE_TIMESTAMPS'] && !isLoggedIn()); | 911 | $feedGenerator->setHideDates($conf->get('privacy.hide_timestamps') && !isLoggedIn()); |
950 | $feedGenerator->setUsePermalinks(isset($_GET['permalinks']) || !$GLOBALS['config']['ENABLE_RSS_PERMALINKS']); | 912 | $feedGenerator->setUsePermalinks(isset($_GET['permalinks']) || !$conf->get('feed.rss_permalinks')); |
951 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) { | 913 | $pshUrl = $conf->get('config.PUBSUBHUB_URL'); |
952 | $feedGenerator->setPubsubhubUrl($GLOBALS['config']['PUBSUBHUB_URL']); | 914 | if (!empty($pshUrl)) { |
915 | $feedGenerator->setPubsubhubUrl($pshUrl); | ||
953 | } | 916 | } |
954 | $data = $feedGenerator->buildData(); | 917 | $data = $feedGenerator->buildData(); |
955 | 918 | ||
956 | // Process plugin hook. | 919 | // Process plugin hook. |
957 | $pluginManager = PluginManager::getInstance(); | ||
958 | $pluginManager->executeHooks('render_feed', $data, array( | 920 | $pluginManager->executeHooks('render_feed', $data, array( |
959 | 'loggedin' => isLoggedIn(), | 921 | 'loggedin' => isLoggedIn(), |
960 | 'target' => $targetPage, | 922 | 'target' => $targetPage, |
@@ -1080,7 +1042,7 @@ function renderPage() | |||
1080 | exit; | 1042 | exit; |
1081 | } | 1043 | } |
1082 | 1044 | ||
1083 | showLinkList($PAGE, $LINKSDB); | 1045 | showLinkList($PAGE, $LINKSDB, $conf, $pluginManager); |
1084 | if (isset($_GET['edit_link'])) { | 1046 | if (isset($_GET['edit_link'])) { |
1085 | header('Location: ?do=login&edit_link='. escape($_GET['edit_link'])); | 1047 | header('Location: ?do=login&edit_link='. escape($_GET['edit_link'])); |
1086 | exit; | 1048 | exit; |
@@ -1110,19 +1072,23 @@ function renderPage() | |||
1110 | // -------- User wants to change his/her password. | 1072 | // -------- User wants to change his/her password. |
1111 | if ($targetPage == Router::$PAGE_CHANGEPASSWORD) | 1073 | if ($targetPage == Router::$PAGE_CHANGEPASSWORD) |
1112 | { | 1074 | { |
1113 | if ($GLOBALS['config']['OPEN_SHAARLI']) die('You are not supposed to change a password on an Open Shaarli.'); | 1075 | if ($conf->get('security.open_shaarli')) { |
1076 | die('You are not supposed to change a password on an Open Shaarli.'); | ||
1077 | } | ||
1078 | |||
1114 | if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) | 1079 | if (!empty($_POST['setpassword']) && !empty($_POST['oldpassword'])) |
1115 | { | 1080 | { |
1116 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away! | 1081 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away! |
1117 | 1082 | ||
1118 | // Make sure old password is correct. | 1083 | // Make sure old password is correct. |
1119 | $oldhash = sha1($_POST['oldpassword'].$GLOBALS['login'].$GLOBALS['salt']); | 1084 | $oldhash = sha1($_POST['oldpassword'].$conf->get('credentials.login').$conf->get('credentials.salt')); |
1120 | if ($oldhash!=$GLOBALS['hash']) { echo '<script>alert("The old password is not correct.");document.location=\'?do=changepasswd\';</script>'; exit; } | 1085 | if ($oldhash!= $conf->get('credentials.hash')) { echo '<script>alert("The old password is not correct.");document.location=\'?do=changepasswd\';</script>'; exit; } |
1121 | // Save new password | 1086 | // Save new password |
1122 | $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. | 1087 | // Salt renders rainbow-tables attacks useless. |
1123 | $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); | 1088 | $conf->set('credentials.salt', sha1(uniqid('', true) .'_'. mt_rand())); |
1089 | $conf->set('credentials.hash', sha1($_POST['setpassword'] . $conf->get('credentials.login') . $conf->get('credentials.salt'))); | ||
1124 | try { | 1090 | try { |
1125 | writeConfig($GLOBALS, isLoggedIn()); | 1091 | $conf->write(isLoggedIn()); |
1126 | } | 1092 | } |
1127 | catch(Exception $e) { | 1093 | catch(Exception $e) { |
1128 | error_log( | 1094 | error_log( |
@@ -1139,7 +1105,7 @@ function renderPage() | |||
1139 | } | 1105 | } |
1140 | else // show the change password form. | 1106 | else // show the change password form. |
1141 | { | 1107 | { |
1142 | $PAGE->assign('token',getToken()); | 1108 | $PAGE->assign('token',getToken($conf)); |
1143 | $PAGE->renderPage('changepassword'); | 1109 | $PAGE->renderPage('changepassword'); |
1144 | exit; | 1110 | exit; |
1145 | } | 1111 | } |
@@ -1159,17 +1125,17 @@ function renderPage() | |||
1159 | ) { | 1125 | ) { |
1160 | $tz = $_POST['continent'] . '/' . $_POST['city']; | 1126 | $tz = $_POST['continent'] . '/' . $_POST['city']; |
1161 | } | 1127 | } |
1162 | $GLOBALS['timezone'] = $tz; | 1128 | $conf->set('general.timezone', $tz); |
1163 | $GLOBALS['title']=$_POST['title']; | 1129 | $conf->set('general.title', escape($_POST['title'])); |
1164 | $GLOBALS['titleLink']=$_POST['titleLink']; | 1130 | $conf->set('general.header_link', escape($_POST['titleLink'])); |
1165 | $GLOBALS['redirector']=$_POST['redirector']; | 1131 | $conf->set('redirector.url', escape($_POST['redirector'])); |
1166 | $GLOBALS['disablesessionprotection']=!empty($_POST['disablesessionprotection']); | 1132 | $conf->set('security.session_protection_disabled', !empty($_POST['disablesessionprotection'])); |
1167 | $GLOBALS['privateLinkByDefault']=!empty($_POST['privateLinkByDefault']); | 1133 | $conf->set('privacy.default_private_links', !empty($_POST['privateLinkByDefault'])); |
1168 | $GLOBALS['config']['ENABLE_RSS_PERMALINKS']= !empty($_POST['enableRssPermalinks']); | 1134 | $conf->set('feed.rss_permalinks', !empty($_POST['enableRssPermalinks'])); |
1169 | $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); | 1135 | $conf->set('updates.check_updates', !empty($_POST['updateCheck'])); |
1170 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'] = !empty($_POST['hidePublicLinks']); | 1136 | $conf->set('privacy.hide_public_links', !empty($_POST['hidePublicLinks'])); |
1171 | try { | 1137 | try { |
1172 | writeConfig($GLOBALS, isLoggedIn()); | 1138 | $conf->write(isLoggedIn()); |
1173 | } | 1139 | } |
1174 | catch(Exception $e) { | 1140 | catch(Exception $e) { |
1175 | error_log( | 1141 | error_log( |
@@ -1178,20 +1144,24 @@ function renderPage() | |||
1178 | ); | 1144 | ); |
1179 | 1145 | ||
1180 | // TODO: do not handle exceptions/errors in JS. | 1146 | // TODO: do not handle exceptions/errors in JS. |
1181 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=tools\';</script>'; | 1147 | echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=configure\';</script>'; |
1182 | exit; | 1148 | exit; |
1183 | } | 1149 | } |
1184 | echo '<script>alert("Configuration was saved.");document.location=\'?do=tools\';</script>'; | 1150 | echo '<script>alert("Configuration was saved.");document.location=\'?do=configure\';</script>'; |
1185 | exit; | 1151 | exit; |
1186 | } | 1152 | } |
1187 | else // Show the configuration form. | 1153 | else // Show the configuration form. |
1188 | { | 1154 | { |
1189 | $PAGE->assign('token',getToken()); | 1155 | $PAGE->assign('token',getToken($conf)); |
1190 | $PAGE->assign('title', empty($GLOBALS['title']) ? '' : $GLOBALS['title'] ); | 1156 | $PAGE->assign('title', $conf->get('general.title')); |
1191 | $PAGE->assign('redirector', empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] ); | 1157 | $PAGE->assign('redirector', $conf->get('redirector.url')); |
1192 | list($timezone_form, $timezone_js) = generateTimeZoneForm($GLOBALS['timezone']); | 1158 | list($timezone_form, $timezone_js) = generateTimeZoneForm($conf->get('general.timezone')); |
1193 | $PAGE->assign('timezone_form', $timezone_form); | 1159 | $PAGE->assign('timezone_form', $timezone_form); |
1194 | $PAGE->assign('timezone_js',$timezone_js); | 1160 | $PAGE->assign('timezone_js',$timezone_js); |
1161 | $PAGE->assign('private_links_default', $conf->get('privacy.default_private_links', false)); | ||
1162 | $PAGE->assign('enable_rss_permalinks', $conf->get('feed.rss_permalinks', false)); | ||
1163 | $PAGE->assign('enable_update_check', $conf->get('updates.check_updates', true)); | ||
1164 | $PAGE->assign('hide_public_links', $conf->get('privacy.hide_public_links', false)); | ||
1195 | $PAGE->renderPage('configure'); | 1165 | $PAGE->renderPage('configure'); |
1196 | exit; | 1166 | exit; |
1197 | } | 1167 | } |
@@ -1201,7 +1171,7 @@ function renderPage() | |||
1201 | if ($targetPage == Router::$PAGE_CHANGETAG) | 1171 | if ($targetPage == Router::$PAGE_CHANGETAG) |
1202 | { | 1172 | { |
1203 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { | 1173 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { |
1204 | $PAGE->assign('token', getToken()); | 1174 | $PAGE->assign('token', getToken($conf)); |
1205 | $PAGE->assign('tags', $LINKSDB->allTags()); | 1175 | $PAGE->assign('tags', $LINKSDB->allTags()); |
1206 | $PAGE->renderPage('changetag'); | 1176 | $PAGE->renderPage('changetag'); |
1207 | exit; | 1177 | exit; |
@@ -1223,7 +1193,7 @@ function renderPage() | |||
1223 | $value['tags']=trim(implode(' ',$tags)); | 1193 | $value['tags']=trim(implode(' ',$tags)); |
1224 | $LINKSDB[$key]=$value; | 1194 | $LINKSDB[$key]=$value; |
1225 | } | 1195 | } |
1226 | $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); | 1196 | $LINKSDB->savedb($conf->get('resource.page_cache')); |
1227 | echo '<script>alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?\';</script>'; | 1197 | echo '<script>alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?\';</script>'; |
1228 | exit; | 1198 | exit; |
1229 | } | 1199 | } |
@@ -1240,7 +1210,7 @@ function renderPage() | |||
1240 | $value['tags']=trim(implode(' ',$tags)); | 1210 | $value['tags']=trim(implode(' ',$tags)); |
1241 | $LINKSDB[$key]=$value; | 1211 | $LINKSDB[$key]=$value; |
1242 | } | 1212 | } |
1243 | $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); // Save to disk. | 1213 | $LINKSDB->savedb($conf->get('resource.page_cache')); // Save to disk. |
1244 | echo '<script>alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode($_POST['totag']).'\';</script>'; | 1214 | echo '<script>alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode($_POST['totag']).'\';</script>'; |
1245 | exit; | 1215 | exit; |
1246 | } | 1216 | } |
@@ -1291,8 +1261,8 @@ function renderPage() | |||
1291 | $pluginManager->executeHooks('save_link', $link); | 1261 | $pluginManager->executeHooks('save_link', $link); |
1292 | 1262 | ||
1293 | $LINKSDB[$linkdate] = $link; | 1263 | $LINKSDB[$linkdate] = $link; |
1294 | $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); | 1264 | $LINKSDB->savedb($conf->get('resource.page_cache')); |
1295 | pubsubhub(); | 1265 | pubsubhub($conf); |
1296 | 1266 | ||
1297 | // If we are called from the bookmarklet, we must close the popup: | 1267 | // If we are called from the bookmarklet, we must close the popup: |
1298 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { | 1268 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { |
@@ -1333,7 +1303,7 @@ function renderPage() | |||
1333 | $pluginManager->executeHooks('delete_link', $LINKSDB[$linkdate]); | 1303 | $pluginManager->executeHooks('delete_link', $LINKSDB[$linkdate]); |
1334 | 1304 | ||
1335 | unset($LINKSDB[$linkdate]); | 1305 | unset($LINKSDB[$linkdate]); |
1336 | $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); // save to disk | 1306 | $LINKSDB->savedb('resource.page_cache'); // save to disk |
1337 | 1307 | ||
1338 | // If we are called from the bookmarklet, we must close the popup: | 1308 | // If we are called from the bookmarklet, we must close the popup: |
1339 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } | 1309 | if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; } |
@@ -1376,7 +1346,7 @@ function renderPage() | |||
1376 | $data = array( | 1346 | $data = array( |
1377 | 'link' => $link, | 1347 | 'link' => $link, |
1378 | 'link_is_new' => false, | 1348 | 'link_is_new' => false, |
1379 | 'token' => getToken(), | 1349 | 'token' => getToken($conf), |
1380 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), | 1350 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), |
1381 | 'tags' => $LINKSDB->allTags(), | 1351 | 'tags' => $LINKSDB->allTags(), |
1382 | ); | 1352 | ); |
@@ -1443,10 +1413,11 @@ function renderPage() | |||
1443 | $data = array( | 1413 | $data = array( |
1444 | 'link' => $link, | 1414 | 'link' => $link, |
1445 | 'link_is_new' => $link_is_new, | 1415 | 'link_is_new' => $link_is_new, |
1446 | 'token' => getToken(), // XSRF protection. | 1416 | 'token' => getToken($conf), // XSRF protection. |
1447 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), | 1417 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), |
1448 | 'source' => (isset($_GET['source']) ? $_GET['source'] : ''), | 1418 | 'source' => (isset($_GET['source']) ? $_GET['source'] : ''), |
1449 | 'tags' => $LINKSDB->allTags(), | 1419 | 'tags' => $LINKSDB->allTags(), |
1420 | 'default_private_links' => $conf->get('default_private_links', false), | ||
1450 | ); | 1421 | ); |
1451 | $pluginManager->executeHooks('render_editlink', $data); | 1422 | $pluginManager->executeHooks('render_editlink', $data); |
1452 | 1423 | ||
@@ -1520,7 +1491,7 @@ function renderPage() | |||
1520 | // -------- Show upload/import dialog: | 1491 | // -------- Show upload/import dialog: |
1521 | if ($targetPage == Router::$PAGE_IMPORT) | 1492 | if ($targetPage == Router::$PAGE_IMPORT) |
1522 | { | 1493 | { |
1523 | $PAGE->assign('token',getToken()); | 1494 | $PAGE->assign('token',getToken($conf)); |
1524 | $PAGE->assign('maxfilesize',getMaxFileSize()); | 1495 | $PAGE->assign('maxfilesize',getMaxFileSize()); |
1525 | $PAGE->renderPage('import'); | 1496 | $PAGE->renderPage('import'); |
1526 | exit; | 1497 | exit; |
@@ -1533,7 +1504,7 @@ function renderPage() | |||
1533 | // Split plugins into 2 arrays: ordered enabled plugins and disabled. | 1504 | // Split plugins into 2 arrays: ordered enabled plugins and disabled. |
1534 | $enabledPlugins = array_filter($pluginMeta, function($v) { return $v['order'] !== false; }); | 1505 | $enabledPlugins = array_filter($pluginMeta, function($v) { return $v['order'] !== false; }); |
1535 | // Load parameters. | 1506 | // Load parameters. |
1536 | $enabledPlugins = load_plugin_parameter_values($enabledPlugins, $GLOBALS['plugins']); | 1507 | $enabledPlugins = load_plugin_parameter_values($enabledPlugins, $conf->get('plugins', array())); |
1537 | uasort( | 1508 | uasort( |
1538 | $enabledPlugins, | 1509 | $enabledPlugins, |
1539 | function($a, $b) { return $a['order'] - $b['order']; } | 1510 | function($a, $b) { return $a['order'] - $b['order']; } |
@@ -1552,13 +1523,13 @@ function renderPage() | |||
1552 | if (isset($_POST['parameters_form'])) { | 1523 | if (isset($_POST['parameters_form'])) { |
1553 | unset($_POST['parameters_form']); | 1524 | unset($_POST['parameters_form']); |
1554 | foreach ($_POST as $param => $value) { | 1525 | foreach ($_POST as $param => $value) { |
1555 | $GLOBALS['plugins'][$param] = escape($value); | 1526 | $conf->set('plugins.'. $param, escape($value)); |
1556 | } | 1527 | } |
1557 | } | 1528 | } |
1558 | else { | 1529 | else { |
1559 | $GLOBALS['config']['ENABLED_PLUGINS'] = save_plugin_config($_POST); | 1530 | $conf->set('general.enabled_plugins', save_plugin_config($_POST)); |
1560 | } | 1531 | } |
1561 | writeConfig($GLOBALS, isLoggedIn()); | 1532 | $conf->write(isLoggedIn()); |
1562 | } | 1533 | } |
1563 | catch (Exception $e) { | 1534 | catch (Exception $e) { |
1564 | error_log( | 1535 | error_log( |
@@ -1575,13 +1546,17 @@ function renderPage() | |||
1575 | } | 1546 | } |
1576 | 1547 | ||
1577 | // -------- Otherwise, simply display search form and links: | 1548 | // -------- Otherwise, simply display search form and links: |
1578 | showLinkList($PAGE, $LINKSDB); | 1549 | showLinkList($PAGE, $LINKSDB, $conf, $pluginManager); |
1579 | exit; | 1550 | exit; |
1580 | } | 1551 | } |
1581 | 1552 | ||
1582 | // ----------------------------------------------------------------------------------------------- | 1553 | /** |
1583 | // Process the import file form. | 1554 | * Process the import file form. |
1584 | function importFile($LINKSDB) | 1555 | * |
1556 | * @param LinkDB $LINKSDB Loaded LinkDB instance. | ||
1557 | * @param ConfigManager $conf Configuration Manager instance. | ||
1558 | */ | ||
1559 | function importFile($LINKSDB, $conf) | ||
1585 | { | 1560 | { |
1586 | if (!isLoggedIn()) { die('Not allowed.'); } | 1561 | if (!isLoggedIn()) { die('Not allowed.'); } |
1587 | 1562 | ||
@@ -1654,7 +1629,7 @@ function importFile($LINKSDB) | |||
1654 | } | 1629 | } |
1655 | } | 1630 | } |
1656 | } | 1631 | } |
1657 | $LINKSDB->savedb($GLOBALS['config']['PAGECACHE']); | 1632 | $LINKSDB->savedb($conf->get('resource.page_cache')); |
1658 | 1633 | ||
1659 | echo '<script>alert("File '.json_encode($filename).' ('.$filesize.' bytes) was successfully processed: '.$import_count.' links imported.");document.location=\'?\';</script>'; | 1634 | echo '<script>alert("File '.json_encode($filename).' ('.$filesize.' bytes) was successfully processed: '.$import_count.' links imported.");document.location=\'?\';</script>'; |
1660 | } | 1635 | } |
@@ -1668,10 +1643,12 @@ function importFile($LINKSDB) | |||
1668 | * Template for the list of links (<div id="linklist">) | 1643 | * Template for the list of links (<div id="linklist">) |
1669 | * This function fills all the necessary fields in the $PAGE for the template 'linklist.html' | 1644 | * This function fills all the necessary fields in the $PAGE for the template 'linklist.html' |
1670 | * | 1645 | * |
1671 | * @param pageBuilder $PAGE pageBuilder instance. | 1646 | * @param pageBuilder $PAGE pageBuilder instance. |
1672 | * @param LinkDB $LINKSDB LinkDB instance. | 1647 | * @param LinkDB $LINKSDB LinkDB instance. |
1648 | * @param ConfigManager $conf Configuration Manager instance. | ||
1649 | * @param PluginManager $pluginManager Plugin Manager instance. | ||
1673 | */ | 1650 | */ |
1674 | function buildLinkList($PAGE,$LINKSDB) | 1651 | function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) |
1675 | { | 1652 | { |
1676 | // Used in templates | 1653 | // Used in templates |
1677 | $searchtags = !empty($_GET['searchtags']) ? escape($_GET['searchtags']) : ''; | 1654 | $searchtags = !empty($_GET['searchtags']) ? escape($_GET['searchtags']) : ''; |
@@ -1700,7 +1677,7 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1700 | 1677 | ||
1701 | // If there is only a single link, we change on-the-fly the title of the page. | 1678 | // If there is only a single link, we change on-the-fly the title of the page. |
1702 | if (count($linksToDisplay) == 1) { | 1679 | if (count($linksToDisplay) == 1) { |
1703 | $GLOBALS['pagetitle'] = $linksToDisplay[$keys[0]]['title'].' - '.$GLOBALS['title']; | 1680 | $conf->set('pagetitle', $linksToDisplay[$keys[0]]['title'] .' - '. $conf->get('general.title')); |
1704 | } | 1681 | } |
1705 | 1682 | ||
1706 | // Select articles according to paging. | 1683 | // Select articles according to paging. |
@@ -1716,7 +1693,7 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1716 | while ($i<$end && $i<count($keys)) | 1693 | while ($i<$end && $i<count($keys)) |
1717 | { | 1694 | { |
1718 | $link = $linksToDisplay[$keys[$i]]; | 1695 | $link = $linksToDisplay[$keys[$i]]; |
1719 | $link['description'] = format_description($link['description'], $GLOBALS['redirector']); | 1696 | $link['description'] = format_description($link['description'], $conf->get('redirector.url')); |
1720 | $classLi = ($i % 2) != 0 ? '' : 'publicLinkHightLight'; | 1697 | $classLi = ($i % 2) != 0 ? '' : 'publicLinkHightLight'; |
1721 | $link['class'] = $link['private'] == 0 ? $classLi : 'private'; | 1698 | $link['class'] = $link['private'] == 0 ? $classLi : 'private'; |
1722 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | 1699 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); |
@@ -1747,7 +1724,7 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1747 | $next_page_url = '?page=' . ($page-1) . $searchtermUrl . $searchtagsUrl; | 1724 | $next_page_url = '?page=' . ($page-1) . $searchtermUrl . $searchtagsUrl; |
1748 | } | 1725 | } |
1749 | 1726 | ||
1750 | $token = isLoggedIn() ? getToken() : ''; | 1727 | $token = isLoggedIn() ? getToken($conf) : ''; |
1751 | 1728 | ||
1752 | // Fill all template fields. | 1729 | // Fill all template fields. |
1753 | $data = array( | 1730 | $data = array( |
@@ -1758,17 +1735,16 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1758 | 'result_count' => count($linksToDisplay), | 1735 | 'result_count' => count($linksToDisplay), |
1759 | 'search_term' => $searchterm, | 1736 | 'search_term' => $searchterm, |
1760 | 'search_tags' => $searchtags, | 1737 | 'search_tags' => $searchtags, |
1761 | 'redirector' => empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'], // Optional redirector URL. | 1738 | 'redirector' => $conf->get('redirector.url'), // Optional redirector URL. |
1762 | 'token' => $token, | 1739 | 'token' => $token, |
1763 | 'links' => $linkDisp, | 1740 | 'links' => $linkDisp, |
1764 | 'tags' => $LINKSDB->allTags(), | 1741 | 'tags' => $LINKSDB->allTags(), |
1765 | ); | 1742 | ); |
1766 | // FIXME! temporary fix - see #399. | 1743 | // FIXME! temporary fix - see #399. |
1767 | if (!empty($GLOBALS['pagetitle']) && count($linkDisp) == 1) { | 1744 | if ($conf->exists('pagetitle') && count($linkDisp) == 1) { |
1768 | $data['pagetitle'] = $GLOBALS['pagetitle']; | 1745 | $data['pagetitle'] = $conf->get('pagetitle'); |
1769 | } | 1746 | } |
1770 | 1747 | ||
1771 | $pluginManager = PluginManager::getInstance(); | ||
1772 | $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => isLoggedIn())); | 1748 | $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => isLoggedIn())); |
1773 | 1749 | ||
1774 | foreach ($data as $key => $value) { | 1750 | foreach ($data as $key => $value) { |
@@ -1778,18 +1754,26 @@ function buildLinkList($PAGE,$LINKSDB) | |||
1778 | return; | 1754 | return; |
1779 | } | 1755 | } |
1780 | 1756 | ||
1781 | // Compute the thumbnail for a link. | 1757 | /** |
1782 | // | 1758 | * Compute the thumbnail for a link. |
1783 | // With a link to the original URL. | 1759 | * |
1784 | // Understands various services (youtube.com...) | 1760 | * With a link to the original URL. |
1785 | // Input: $url = URL for which the thumbnail must be found. | 1761 | * Understands various services (youtube.com...) |
1786 | // $href = if provided, this URL will be followed instead of $url | 1762 | * Input: $url = URL for which the thumbnail must be found. |
1787 | // Returns an associative array with thumbnail attributes (src,href,width,height,style,alt) | 1763 | * $href = if provided, this URL will be followed instead of $url |
1788 | // Some of them may be missing. | 1764 | * Returns an associative array with thumbnail attributes (src,href,width,height,style,alt) |
1789 | // Return an empty array if no thumbnail available. | 1765 | * Some of them may be missing. |
1790 | function computeThumbnail($url,$href=false) | 1766 | * Return an empty array if no thumbnail available. |
1767 | * | ||
1768 | * @param ConfigManager $conf Configuration Manager instance. | ||
1769 | * @param string $url | ||
1770 | * @param string|bool $href | ||
1771 | * | ||
1772 | * @return array | ||
1773 | */ | ||
1774 | function computeThumbnail($conf, $url, $href = false) | ||
1791 | { | 1775 | { |
1792 | if (!$GLOBALS['config']['ENABLE_THUMBNAILS']) return array(); | 1776 | if (!$conf->get('thumbnail.enable_thumbnails')) return array(); |
1793 | if ($href==false) $href=$url; | 1777 | if ($href==false) $href=$url; |
1794 | 1778 | ||
1795 | // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. | 1779 | // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. |
@@ -1857,7 +1841,7 @@ function computeThumbnail($url,$href=false) | |||
1857 | // So we deport the thumbnail generation in order not to slow down page generation | 1841 | // So we deport the thumbnail generation in order not to slow down page generation |
1858 | // (and we also cache the thumbnail) | 1842 | // (and we also cache the thumbnail) |
1859 | 1843 | ||
1860 | if (!$GLOBALS['config']['ENABLE_LOCALCACHE']) return array(); // If local cache is disabled, no thumbnails for services which require the use a local cache. | 1844 | if (! $conf->get('thumbnail.enable_localcache')) return array(); // If local cache is disabled, no thumbnails for services which require the use a local cache. |
1861 | 1845 | ||
1862 | if ($domain=='flickr.com' || endsWith($domain,'.flickr.com') | 1846 | if ($domain=='flickr.com' || endsWith($domain,'.flickr.com') |
1863 | || $domain=='vimeo.com' | 1847 | || $domain=='vimeo.com' |
@@ -1880,7 +1864,7 @@ function computeThumbnail($url,$href=false) | |||
1880 | $path = parse_url($url,PHP_URL_PATH); | 1864 | $path = parse_url($url,PHP_URL_PATH); |
1881 | if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. | 1865 | if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. |
1882 | } | 1866 | } |
1883 | $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) | 1867 | $sign = hash_hmac('sha256', $url, $conf->get('credentials.salt')); // We use the salt to sign data (it's random, secret, and specific to each installation) |
1884 | return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), | 1868 | return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), |
1885 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); | 1869 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); |
1886 | } | 1870 | } |
@@ -1891,7 +1875,7 @@ function computeThumbnail($url,$href=false) | |||
1891 | $ext=strtolower(pathinfo($url,PATHINFO_EXTENSION)); | 1875 | $ext=strtolower(pathinfo($url,PATHINFO_EXTENSION)); |
1892 | if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') | 1876 | if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') |
1893 | { | 1877 | { |
1894 | $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) | 1878 | $sign = hash_hmac('sha256', $url, $conf->get('credentials.salt')); // We use the salt to sign data (it's random, secret, and specific to each installation) |
1895 | return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), | 1879 | return array('src'=>index_url($_SERVER).'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url), |
1896 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); | 1880 | 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); |
1897 | } | 1881 | } |
@@ -1908,7 +1892,9 @@ function computeThumbnail($url,$href=false) | |||
1908 | // Returns '' if no thumbnail available. | 1892 | // Returns '' if no thumbnail available. |
1909 | function thumbnail($url,$href=false) | 1893 | function thumbnail($url,$href=false) |
1910 | { | 1894 | { |
1911 | $t = computeThumbnail($url,$href); | 1895 | // FIXME! |
1896 | global $conf; | ||
1897 | $t = computeThumbnail($conf, $url,$href); | ||
1912 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. | 1898 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. |
1913 | 1899 | ||
1914 | $html='<a href="'.escape($t['href']).'"><img src="'.escape($t['src']).'"'; | 1900 | $html='<a href="'.escape($t['href']).'"><img src="'.escape($t['src']).'"'; |
@@ -1926,9 +1912,11 @@ function thumbnail($url,$href=false) | |||
1926 | // Input: $url = URL for which the thumbnail must be found. | 1912 | // Input: $url = URL for which the thumbnail must be found. |
1927 | // $href = if provided, this URL will be followed instead of $url | 1913 | // $href = if provided, this URL will be followed instead of $url |
1928 | // Returns '' if no thumbnail available. | 1914 | // Returns '' if no thumbnail available. |
1929 | function lazyThumbnail($url,$href=false) | 1915 | function lazyThumbnail($conf, $url,$href=false) |
1930 | { | 1916 | { |
1931 | $t = computeThumbnail($url,$href); | 1917 | // FIXME! |
1918 | global $conf; | ||
1919 | $t = computeThumbnail($conf, $url,$href); | ||
1932 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. | 1920 | if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. |
1933 | 1921 | ||
1934 | $html='<a href="'.escape($t['href']).'">'; | 1922 | $html='<a href="'.escape($t['href']).'">'; |
@@ -1954,10 +1942,13 @@ function lazyThumbnail($url,$href=false) | |||
1954 | } | 1942 | } |
1955 | 1943 | ||
1956 | 1944 | ||
1957 | // ----------------------------------------------------------------------------------------------- | 1945 | /** |
1958 | // Installation | 1946 | * Installation |
1959 | // This function should NEVER be called if the file data/config.php exists. | 1947 | * This function should NEVER be called if the file data/config.php exists. |
1960 | function install() | 1948 | * |
1949 | * @param ConfigManager $conf Configuration Manager instance. | ||
1950 | */ | ||
1951 | function install($conf) | ||
1961 | { | 1952 | { |
1962 | // On free.fr host, make sure the /sessions directory exists, otherwise login will not work. | 1953 | // On free.fr host, make sure the /sessions directory exists, otherwise login will not work. |
1963 | if (endsWith($_SERVER['HTTP_HOST'],'.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions',0705); | 1954 | if (endsWith($_SERVER['HTTP_HOST'],'.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions',0705); |
@@ -1994,15 +1985,21 @@ function install() | |||
1994 | ) { | 1985 | ) { |
1995 | $tz = $_POST['continent'].'/'.$_POST['city']; | 1986 | $tz = $_POST['continent'].'/'.$_POST['city']; |
1996 | } | 1987 | } |
1997 | $GLOBALS['timezone'] = $tz; | 1988 | $conf->set('general.timezone', $tz); |
1998 | // Everything is ok, let's create config file. | 1989 | $login = $_POST['setlogin']; |
1999 | $GLOBALS['login'] = $_POST['setlogin']; | 1990 | $conf->set('credentials.login', $login); |
2000 | $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. | 1991 | $salt = sha1(uniqid('', true) .'_'. mt_rand()); |
2001 | $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); | 1992 | $conf->set('credentials.salt', $salt); |
2002 | $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.escape(index_url($_SERVER)) : $_POST['title'] ); | 1993 | $conf->set('credentials.hash', sha1($_POST['setpassword'] . $login . $salt)); |
2003 | $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); | 1994 | if (!empty($_POST['title'])) { |
1995 | $conf->set('general.title', escape($_POST['title'])); | ||
1996 | } else { | ||
1997 | $conf->set('general.title', 'Shared links on '.escape(index_url($_SERVER))); | ||
1998 | } | ||
1999 | $conf->set('updates.check_updates', !empty($_POST['updateCheck'])); | ||
2004 | try { | 2000 | try { |
2005 | writeConfig($GLOBALS, isLoggedIn()); | 2001 | // Everything is ok, let's create config file. |
2002 | $conf->write(isLoggedIn()); | ||
2006 | } | 2003 | } |
2007 | catch(Exception $e) { | 2004 | catch(Exception $e) { |
2008 | error_log( | 2005 | error_log( |
@@ -2025,42 +2022,46 @@ function install() | |||
2025 | $timezone_html = '<tr><td><b>Timezone:</b></td><td>'.$timezone_form.'</td></tr>'; | 2022 | $timezone_html = '<tr><td><b>Timezone:</b></td><td>'.$timezone_form.'</td></tr>'; |
2026 | } | 2023 | } |
2027 | 2024 | ||
2028 | $PAGE = new PageBuilder(); | 2025 | $PAGE = new PageBuilder($conf); |
2029 | $PAGE->assign('timezone_html',$timezone_html); | 2026 | $PAGE->assign('timezone_html',$timezone_html); |
2030 | $PAGE->assign('timezone_js',$timezone_js); | 2027 | $PAGE->assign('timezone_js',$timezone_js); |
2031 | $PAGE->renderPage('install'); | 2028 | $PAGE->renderPage('install'); |
2032 | exit; | 2029 | exit; |
2033 | } | 2030 | } |
2034 | 2031 | ||
2035 | /* Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL, | 2032 | /** |
2036 | I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. | 2033 | * Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL, |
2037 | The following function takes the URL a link (e.g. a flickr page) and return the proper thumbnail. | 2034 | * I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. |
2038 | This function is called by passing the URL: | 2035 | * The following function takes the URL a link (e.g. a flickr page) and return the proper thumbnail. |
2039 | http://mywebsite.com/shaarli/?do=genthumbnail&hmac=[HMAC]&url=[URL] | 2036 | * This function is called by passing the URL: |
2040 | [URL] is the URL of the link (e.g. a flickr page) | 2037 | * http://mywebsite.com/shaarli/?do=genthumbnail&hmac=[HMAC]&url=[URL] |
2041 | [HMAC] is the signature for the [URL] (so that these URL cannot be forged). | 2038 | * [URL] is the URL of the link (e.g. a flickr page) |
2042 | The function below will fetch the image from the webservice and store it in the cache. | 2039 | * [HMAC] is the signature for the [URL] (so that these URL cannot be forged). |
2043 | */ | 2040 | * The function below will fetch the image from the webservice and store it in the cache. |
2044 | function genThumbnail() | 2041 | * |
2042 | * @param ConfigManager $conf Configuration Manager instance, | ||
2043 | */ | ||
2044 | function genThumbnail($conf) | ||
2045 | { | 2045 | { |
2046 | // Make sure the parameters in the URL were generated by us. | 2046 | // Make sure the parameters in the URL were generated by us. |
2047 | $sign = hash_hmac('sha256', $_GET['url'], $GLOBALS['salt']); | 2047 | $sign = hash_hmac('sha256', $_GET['url'], $conf->get('credentials.salt')); |
2048 | if ($sign!=$_GET['hmac']) die('Naughty boy!'); | 2048 | if ($sign!=$_GET['hmac']) die('Naughty boy!'); |
2049 | 2049 | ||
2050 | $cacheDir = $conf->get('resource.thumbnails_cache', 'cache'); | ||
2050 | // Let's see if we don't already have the image for this URL in the cache. | 2051 | // Let's see if we don't already have the image for this URL in the cache. |
2051 | $thumbname=hash('sha1',$_GET['url']).'.jpg'; | 2052 | $thumbname=hash('sha1',$_GET['url']).'.jpg'; |
2052 | if (is_file($GLOBALS['config']['CACHEDIR'].'/'.$thumbname)) | 2053 | if (is_file($cacheDir .'/'. $thumbname)) |
2053 | { // We have the thumbnail, just serve it: | 2054 | { // We have the thumbnail, just serve it: |
2054 | header('Content-Type: image/jpeg'); | 2055 | header('Content-Type: image/jpeg'); |
2055 | echo file_get_contents($GLOBALS['config']['CACHEDIR'].'/'.$thumbname); | 2056 | echo file_get_contents($cacheDir .'/'. $thumbname); |
2056 | return; | 2057 | return; |
2057 | } | 2058 | } |
2058 | // We may also serve a blank image (if service did not respond) | 2059 | // We may also serve a blank image (if service did not respond) |
2059 | $blankname=hash('sha1',$_GET['url']).'.gif'; | 2060 | $blankname=hash('sha1',$_GET['url']).'.gif'; |
2060 | if (is_file($GLOBALS['config']['CACHEDIR'].'/'.$blankname)) | 2061 | if (is_file($cacheDir .'/'. $blankname)) |
2061 | { | 2062 | { |
2062 | header('Content-Type: image/gif'); | 2063 | header('Content-Type: image/gif'); |
2063 | echo file_get_contents($GLOBALS['config']['CACHEDIR'].'/'.$blankname); | 2064 | echo file_get_contents($cacheDir .'/'. $blankname); |
2064 | return; | 2065 | return; |
2065 | } | 2066 | } |
2066 | 2067 | ||
@@ -2107,7 +2108,7 @@ function genThumbnail() | |||
2107 | list($headers, $content) = get_http_response($imageurl, 10); | 2108 | list($headers, $content) = get_http_response($imageurl, 10); |
2108 | if (strpos($headers[0], '200 OK') !== false) { | 2109 | if (strpos($headers[0], '200 OK') !== false) { |
2109 | // Save image to cache. | 2110 | // Save image to cache. |
2110 | file_put_contents($GLOBALS['config']['CACHEDIR'].'/' . $thumbname, $content); | 2111 | file_put_contents($cacheDir .'/'. $thumbname, $content); |
2111 | header('Content-Type: image/jpeg'); | 2112 | header('Content-Type: image/jpeg'); |
2112 | echo $content; | 2113 | echo $content; |
2113 | return; | 2114 | return; |
@@ -2128,7 +2129,7 @@ function genThumbnail() | |||
2128 | list($headers, $content) = get_http_response($imageurl, 10); | 2129 | list($headers, $content) = get_http_response($imageurl, 10); |
2129 | if (strpos($headers[0], '200 OK') !== false) { | 2130 | if (strpos($headers[0], '200 OK') !== false) { |
2130 | // Save image to cache. | 2131 | // Save image to cache. |
2131 | file_put_contents($GLOBALS['config']['CACHEDIR'] . '/' . $thumbname, $content); | 2132 | file_put_contents($cacheDir .'/'. $thumbname, $content); |
2132 | header('Content-Type: image/jpeg'); | 2133 | header('Content-Type: image/jpeg'); |
2133 | echo $content; | 2134 | echo $content; |
2134 | return; | 2135 | return; |
@@ -2151,7 +2152,7 @@ function genThumbnail() | |||
2151 | // No control on image size, so wait long enough | 2152 | // No control on image size, so wait long enough |
2152 | list($headers, $content) = get_http_response($imageurl, 20); | 2153 | list($headers, $content) = get_http_response($imageurl, 20); |
2153 | if (strpos($headers[0], '200 OK') !== false) { | 2154 | if (strpos($headers[0], '200 OK') !== false) { |
2154 | $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname; | 2155 | $filepath = $cacheDir .'/'. $thumbname; |
2155 | file_put_contents($filepath, $content); // Save image to cache. | 2156 | file_put_contents($filepath, $content); // Save image to cache. |
2156 | if (resizeImage($filepath)) | 2157 | if (resizeImage($filepath)) |
2157 | { | 2158 | { |
@@ -2179,7 +2180,7 @@ function genThumbnail() | |||
2179 | // No control on image size, so wait long enough | 2180 | // No control on image size, so wait long enough |
2180 | list($headers, $content) = get_http_response($imageurl, 20); | 2181 | list($headers, $content) = get_http_response($imageurl, 20); |
2181 | if (strpos($headers[0], '200 OK') !== false) { | 2182 | if (strpos($headers[0], '200 OK') !== false) { |
2182 | $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname; | 2183 | $filepath = $cacheDir.'/'.$thumbname; |
2183 | // Save image to cache. | 2184 | // Save image to cache. |
2184 | file_put_contents($filepath, $content); | 2185 | file_put_contents($filepath, $content); |
2185 | if (resizeImage($filepath)) | 2186 | if (resizeImage($filepath)) |
@@ -2199,7 +2200,7 @@ function genThumbnail() | |||
2199 | // We allow 30 seconds max to download (and downloads are limited to 4 Mb) | 2200 | // We allow 30 seconds max to download (and downloads are limited to 4 Mb) |
2200 | list($headers, $content) = get_http_response($url, 30); | 2201 | list($headers, $content) = get_http_response($url, 30); |
2201 | if (strpos($headers[0], '200 OK') !== false) { | 2202 | if (strpos($headers[0], '200 OK') !== false) { |
2202 | $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname; | 2203 | $filepath = $cacheDir .'/'.$thumbname; |
2203 | // Save image to cache. | 2204 | // Save image to cache. |
2204 | file_put_contents($filepath, $content); | 2205 | file_put_contents($filepath, $content); |
2205 | if (resizeImage($filepath)) | 2206 | if (resizeImage($filepath)) |
@@ -2214,7 +2215,8 @@ function genThumbnail() | |||
2214 | 2215 | ||
2215 | // Otherwise, return an empty image (8x8 transparent gif) | 2216 | // Otherwise, return an empty image (8x8 transparent gif) |
2216 | $blankgif = base64_decode('R0lGODlhCAAIAIAAAP///////yH5BAEKAAEALAAAAAAIAAgAAAIHjI+py+1dAAA7'); | 2217 | $blankgif = base64_decode('R0lGODlhCAAIAIAAAP///////yH5BAEKAAEALAAAAAAIAAgAAAIHjI+py+1dAAA7'); |
2217 | file_put_contents($GLOBALS['config']['CACHEDIR'].'/'.$blankname,$blankgif); // Also put something in cache so that this URL is not requested twice. | 2218 | // Also put something in cache so that this URL is not requested twice. |
2219 | file_put_contents($cacheDir .'/'. $blankname, $blankgif); | ||
2218 | header('Content-Type: image/gif'); | 2220 | header('Content-Type: image/gif'); |
2219 | echo $blankgif; | 2221 | echo $blankgif; |
2220 | } | 2222 | } |
@@ -2252,8 +2254,9 @@ function resizeImage($filepath) | |||
2252 | return true; | 2254 | return true; |
2253 | } | 2255 | } |
2254 | 2256 | ||
2255 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=genthumbnail')) { genThumbnail(); exit; } // Thumbnail generation/cache does not need the link database. | 2257 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=genthumbnail')) { genThumbnail($conf); exit; } // Thumbnail generation/cache does not need the link database. |
2256 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) { showDailyRSS(); exit; } | 2258 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) { showDailyRSS($conf); exit; } |
2257 | if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=$GLOBALS['config']['LINKS_PER_PAGE']; | 2259 | if (!isset($_SESSION['LINKS_PER_PAGE'])) { |
2258 | renderPage(); | 2260 | $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20); |
2259 | ?> | 2261 | } |
2262 | renderPage($conf, $pluginManager); | ||
diff --git a/plugins/readityourself/config.php.dist b/plugins/readityourself/config.php.dist deleted file mode 100644 index d6b5cb85..00000000 --- a/plugins/readityourself/config.php.dist +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | $GLOBALS['plugins']['READITYOUSELF_URL'] = 'http://someurl.com'; \ No newline at end of file | ||
diff --git a/plugins/readityourself/readityourself.php b/plugins/readityourself/readityourself.php index c8df4c4f..4bfcf501 100644 --- a/plugins/readityourself/readityourself.php +++ b/plugins/readityourself/readityourself.php | |||
@@ -8,34 +8,31 @@ | |||
8 | // it seems kinda dead. | 8 | // it seems kinda dead. |
9 | // Not tested. | 9 | // Not tested. |
10 | 10 | ||
11 | // don't raise unnecessary warnings | 11 | $riyUrl = $conf->get('plugins.READITYOUSELF_URL'); |
12 | if (is_file(PluginManager::$PLUGINS_PATH . '/readityourself/config.php')) { | 12 | if (empty($riyUrl)) { |
13 | include PluginManager::$PLUGINS_PATH . '/readityourself/config.php'; | ||
14 | } | ||
15 | |||
16 | if (empty($GLOBALS['plugins']['READITYOUSELF_URL'])) { | ||
17 | $GLOBALS['plugin_errors'][] = 'Readityourself plugin error: '. | 13 | $GLOBALS['plugin_errors'][] = 'Readityourself plugin error: '. |
18 | 'Please define "$GLOBALS[\'plugins\'][\'READITYOUSELF_URL\']" '. | 14 | 'Please define the "READITYOUSELF_URL" setting in the plugin administration page.'; |
19 | 'in "plugins/readityourself/config.php" or in your Shaarli config.php file.'; | ||
20 | } | 15 | } |
21 | 16 | ||
22 | /** | 17 | /** |
23 | * Add readityourself icon to link_plugin when rendering linklist. | 18 | * Add readityourself icon to link_plugin when rendering linklist. |
24 | * | 19 | * |
25 | * @param mixed $data - linklist data. | 20 | * @param mixed $data Linklist data. |
21 | * @param ConfigManager $conf Configuration Manager instance. | ||
26 | * | 22 | * |
27 | * @return mixed - linklist data with readityourself plugin. | 23 | * @return mixed - linklist data with readityourself plugin. |
28 | */ | 24 | */ |
29 | function hook_readityourself_render_linklist($data) | 25 | function hook_readityourself_render_linklist($data, $conf) |
30 | { | 26 | { |
31 | if (!isset($GLOBALS['plugins']['READITYOUSELF_URL'])) { | 27 | $riyUrl = $conf->get('plugins.READITYOUSELF_URL'); |
28 | if (empty($riyUrl)) { | ||
32 | return $data; | 29 | return $data; |
33 | } | 30 | } |
34 | 31 | ||
35 | $readityourself_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/readityourself/readityourself.html'); | 32 | $readityourself_html = file_get_contents(PluginManager::$PLUGINS_PATH . '/readityourself/readityourself.html'); |
36 | 33 | ||
37 | foreach ($data['links'] as &$value) { | 34 | foreach ($data['links'] as &$value) { |
38 | $readityourself = sprintf($readityourself_html, $GLOBALS['plugins']['READITYOUSELF_URL'], $value['url'], PluginManager::$PLUGINS_PATH); | 35 | $readityourself = sprintf($readityourself_html, $riyUrl, $value['url'], PluginManager::$PLUGINS_PATH); |
39 | $value['link_plugin'][] = $readityourself; | 36 | $value['link_plugin'][] = $readityourself; |
40 | } | 37 | } |
41 | 38 | ||
diff --git a/plugins/wallabag/README.md b/plugins/wallabag/README.md index 5bc35be1..3f930564 100644 --- a/plugins/wallabag/README.md +++ b/plugins/wallabag/README.md | |||
@@ -12,31 +12,26 @@ The directory structure should look like: | |||
12 | └── plugins | 12 | └── plugins |
13 |   └── wallabag | 13 |   └── wallabag |
14 |   ├── README.md | 14 |   ├── README.md |
15 | ├── config.php.dist | ||
16 |   ├── wallabag.html | 15 |   ├── wallabag.html |
16 |   ├── wallabag.meta | ||
17 |   ├── wallabag.php | 17 |   ├── wallabag.php |
18 |   └── wallabag.png | 18 |   ├── wallabag.php |
19 |   └── WallabagInstance.php | ||
19 | ``` | 20 | ``` |
20 | 21 | ||
21 | To enable the plugin, add `'wallabag'` to your list of enabled plugins in `data/options.php` (`PLUGINS` array). | 22 | To enable the plugin, you can either: |
22 | This should look like: | ||
23 | 23 | ||
24 | ``` | 24 | * enable it in the plugins administration page (`?do=pluginadmin`). |
25 | $GLOBALS['config']['PLUGINS'] = array('qrcode', 'any_other_plugin', 'wallabag') | 25 | * add `wallabag` to your list of enabled plugins in `data/config.json.php` (`general.enabled_plugins` section). |
26 | ``` | ||
27 | 26 | ||
28 | ### Configuration | 27 | ### Configuration |
29 | 28 | ||
30 | Copy `config.php.dist` into `config.php` and setup your instance. | 29 | Go to the plugin administration page, and edit the following settings (with the plugin enabled). |
31 | 30 | ||
32 | *Wallabag instance URL* | 31 | **WALLABAG_URL**: *Wallabag instance URL* |
33 | ``` | 32 | Example value: `http://v2.wallabag.org` |
34 | $GLOBALS['config']['WALLABAG_URL'] = 'http://v2.wallabag.org' ; | ||
35 | ``` | ||
36 | 33 | ||
37 | *Wallabag version*: either `1` (for 1.x) or `2` (for 2.x) | 34 | **WALLABAG_VERSION**: *Wallabag version* |
38 | ``` | 35 | Value: either `1` (for 1.x) or `2` (for 2.x) |
39 | $GLOBALS['config']['WALLABAG_VERSION'] = 2; | ||
40 | ``` | ||
41 | 36 | ||
42 | > Note: these settings can also be set in `data/config.php`. \ No newline at end of file | 37 | > Note: these settings can also be set in `data/config.json.php`, in the plugins section. \ No newline at end of file |
diff --git a/plugins/wallabag/config.php.dist b/plugins/wallabag/config.php.dist deleted file mode 100644 index a602708f..00000000 --- a/plugins/wallabag/config.php.dist +++ /dev/null | |||
@@ -1,4 +0,0 @@ | |||
1 | <?php | ||
2 | |||
3 | $GLOBALS['plugins']['WALLABAG_URL'] = 'https://demo.wallabag.org'; | ||
4 | $GLOBALS['plugins']['WALLABAG_VERSION'] = 1; \ No newline at end of file | ||
diff --git a/plugins/wallabag/wallabag.php b/plugins/wallabag/wallabag.php index 0d6fc66d..ec09c8a1 100644 --- a/plugins/wallabag/wallabag.php +++ b/plugins/wallabag/wallabag.php | |||
@@ -6,34 +6,29 @@ | |||
6 | 6 | ||
7 | require_once 'WallabagInstance.php'; | 7 | require_once 'WallabagInstance.php'; |
8 | 8 | ||
9 | // don't raise unnecessary warnings | 9 | $wallabagUrl = $conf->get('plugins.WALLABAG_URL'); |
10 | if (is_file(PluginManager::$PLUGINS_PATH . '/wallabag/config.php')) { | 10 | if (empty($wallabagUrl)) { |
11 | include PluginManager::$PLUGINS_PATH . '/wallabag/config.php'; | ||
12 | } | ||
13 | |||
14 | if (empty($GLOBALS['plugins']['WALLABAG_URL'])) { | ||
15 | $GLOBALS['plugin_errors'][] = 'Wallabag plugin error: '. | 11 | $GLOBALS['plugin_errors'][] = 'Wallabag plugin error: '. |
16 | 'Please define "$GLOBALS[\'plugins\'][\'WALLABAG_URL\']" '. | 12 | 'Please define the "WALLABAG_URL" setting in the plugin administration page.'; |
17 | 'in "plugins/wallabag/config.php" or in your Shaarli config.php file.'; | ||
18 | } | 13 | } |
19 | 14 | ||
20 | /** | 15 | /** |
21 | * Add wallabag icon to link_plugin when rendering linklist. | 16 | * Add wallabag icon to link_plugin when rendering linklist. |
22 | * | 17 | * |
23 | * @param mixed $data - linklist data. | 18 | * @param mixed $data Linklist data. |
19 | * @param ConfigManager $conf Configuration Manager instance. | ||
24 | * | 20 | * |
25 | * @return mixed - linklist data with wallabag plugin. | 21 | * @return mixed - linklist data with wallabag plugin. |
26 | */ | 22 | */ |
27 | function hook_wallabag_render_linklist($data) | 23 | function hook_wallabag_render_linklist($data, $conf) |
28 | { | 24 | { |
29 | if (!isset($GLOBALS['plugins']['WALLABAG_URL'])) { | 25 | $wallabagUrl = $conf->get('plugins.WALLABAG_URL'); |
26 | if (empty($wallabagUrl)) { | ||
30 | return $data; | 27 | return $data; |
31 | } | 28 | } |
32 | 29 | ||
33 | $version = isset($GLOBALS['plugins']['WALLABAG_VERSION']) | 30 | $version = $conf->get('plugins.WALLABAG_VERSION'); |
34 | ? $GLOBALS['plugins']['WALLABAG_VERSION'] | 31 | $wallabagInstance = new WallabagInstance($wallabagUrl, $version); |
35 | : ''; | ||
36 | $wallabagInstance = new WallabagInstance($GLOBALS['plugins']['WALLABAG_URL'], $version); | ||
37 | 32 | ||
38 | $wallabagHtml = file_get_contents(PluginManager::$PLUGINS_PATH . '/wallabag/wallabag.html'); | 33 | $wallabagHtml = file_get_contents(PluginManager::$PLUGINS_PATH . '/wallabag/wallabag.html'); |
39 | 34 | ||
diff --git a/tests/ApplicationUtilsTest.php b/tests/ApplicationUtilsTest.php index 6064357d..c37a94f0 100644 --- a/tests/ApplicationUtilsTest.php +++ b/tests/ApplicationUtilsTest.php | |||
@@ -3,6 +3,7 @@ | |||
3 | * ApplicationUtils' tests | 3 | * ApplicationUtils' tests |
4 | */ | 4 | */ |
5 | 5 | ||
6 | require_once 'application/config/ConfigManager.php'; | ||
6 | require_once 'application/ApplicationUtils.php'; | 7 | require_once 'application/ApplicationUtils.php'; |
7 | 8 | ||
8 | /** | 9 | /** |
@@ -59,7 +60,7 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase | |||
59 | $testTimeout | 60 | $testTimeout |
60 | ) | 61 | ) |
61 | ); | 62 | ); |
62 | $this->assertRegexp( | 63 | $this->assertRegExp( |
63 | self::$versionPattern, | 64 | self::$versionPattern, |
64 | ApplicationUtils::getLatestGitVersionCode( | 65 | ApplicationUtils::getLatestGitVersionCode( |
65 | 'https://raw.githubusercontent.com/shaarli/Shaarli/' | 66 | 'https://raw.githubusercontent.com/shaarli/Shaarli/' |
@@ -275,21 +276,21 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase | |||
275 | */ | 276 | */ |
276 | public function testCheckCurrentResourcePermissions() | 277 | public function testCheckCurrentResourcePermissions() |
277 | { | 278 | { |
278 | $config = array( | 279 | $conf = new ConfigManager(''); |
279 | 'CACHEDIR' => 'cache', | 280 | $conf->set('resource.thumbnails_cache', 'cache'); |
280 | 'CONFIG_FILE' => 'data/config.php', | 281 | $conf->set('resource.config', 'data/config.php'); |
281 | 'DATADIR' => 'data', | 282 | $conf->set('resource.data_dir', 'data'); |
282 | 'DATASTORE' => 'data/datastore.php', | 283 | $conf->set('resource.datastore', 'data/datastore.php'); |
283 | 'IPBANS_FILENAME' => 'data/ipbans.php', | 284 | $conf->set('resource.ban_file', 'data/ipbans.php'); |
284 | 'LOG_FILE' => 'data/log.txt', | 285 | $conf->set('resource.log', 'data/log.txt'); |
285 | 'PAGECACHE' => 'pagecache', | 286 | $conf->set('resource.page_cache', 'pagecache'); |
286 | 'RAINTPL_TMP' => 'tmp', | 287 | $conf->set('resource.raintpl_tmp', 'tmp'); |
287 | 'RAINTPL_TPL' => 'tpl', | 288 | $conf->set('resource.raintpl_tpl', 'tpl'); |
288 | 'UPDATECHECK_FILENAME' => 'data/lastupdatecheck.txt' | 289 | $conf->set('resource.update_check', 'data/lastupdatecheck.txt'); |
289 | ); | 290 | |
290 | $this->assertEquals( | 291 | $this->assertEquals( |
291 | array(), | 292 | array(), |
292 | ApplicationUtils::checkResourcePermissions($config) | 293 | ApplicationUtils::checkResourcePermissions($conf) |
293 | ); | 294 | ); |
294 | } | 295 | } |
295 | 296 | ||
@@ -298,18 +299,17 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase | |||
298 | */ | 299 | */ |
299 | public function testCheckCurrentResourcePermissionsErrors() | 300 | public function testCheckCurrentResourcePermissionsErrors() |
300 | { | 301 | { |
301 | $config = array( | 302 | $conf = new ConfigManager(''); |
302 | 'CACHEDIR' => 'null/cache', | 303 | $conf->set('resource.thumbnails_cache', 'null/cache'); |
303 | 'CONFIG_FILE' => 'null/data/config.php', | 304 | $conf->set('resource.config', 'null/data/config.php'); |
304 | 'DATADIR' => 'null/data', | 305 | $conf->set('resource.data_dir', 'null/data'); |
305 | 'DATASTORE' => 'null/data/store.php', | 306 | $conf->set('resource.datastore', 'null/data/store.php'); |
306 | 'IPBANS_FILENAME' => 'null/data/ipbans.php', | 307 | $conf->set('resource.ban_file', 'null/data/ipbans.php'); |
307 | 'LOG_FILE' => 'null/data/log.txt', | 308 | $conf->set('resource.log', 'null/data/log.txt'); |
308 | 'PAGECACHE' => 'null/pagecache', | 309 | $conf->set('resource.page_cache', 'null/pagecache'); |
309 | 'RAINTPL_TMP' => 'null/tmp', | 310 | $conf->set('resource.raintpl_tmp', 'null/tmp'); |
310 | 'RAINTPL_TPL' => 'null/tpl', | 311 | $conf->set('resource.raintpl_tpl', 'null/tpl'); |
311 | 'UPDATECHECK_FILENAME' => 'null/data/lastupdatecheck.txt' | 312 | $conf->set('resource.update_check', 'null/data/lastupdatecheck.txt'); |
312 | ); | ||
313 | $this->assertEquals( | 313 | $this->assertEquals( |
314 | array( | 314 | array( |
315 | '"null/tpl" directory is not readable', | 315 | '"null/tpl" directory is not readable', |
@@ -322,7 +322,7 @@ class ApplicationUtilsTest extends PHPUnit_Framework_TestCase | |||
322 | '"null/tmp" directory is not readable', | 322 | '"null/tmp" directory is not readable', |
323 | '"null/tmp" directory is not writable' | 323 | '"null/tmp" directory is not writable' |
324 | ), | 324 | ), |
325 | ApplicationUtils::checkResourcePermissions($config) | 325 | ApplicationUtils::checkResourcePermissions($conf) |
326 | ); | 326 | ); |
327 | } | 327 | } |
328 | } | 328 | } |
diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php deleted file mode 100644 index 7200aae6..00000000 --- a/tests/ConfigTest.php +++ /dev/null | |||
@@ -1,244 +0,0 @@ | |||
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 = array( | ||
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' => array( | ||
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 save_plugin_config with valid data. | ||
138 | * | ||
139 | * @throws PluginConfigOrderException | ||
140 | */ | ||
141 | public function testSavePluginConfigValid() | ||
142 | { | ||
143 | $data = array( | ||
144 | 'order_plugin1' => 2, // no plugin related | ||
145 | 'plugin2' => 0, // new - at the end | ||
146 | 'plugin3' => 0, // 2nd | ||
147 | 'order_plugin3' => 8, | ||
148 | 'plugin4' => 0, // 1st | ||
149 | 'order_plugin4' => 5, | ||
150 | ); | ||
151 | |||
152 | $expected = array( | ||
153 | 'plugin3', | ||
154 | 'plugin4', | ||
155 | 'plugin2', | ||
156 | ); | ||
157 | |||
158 | $out = save_plugin_config($data); | ||
159 | $this->assertEquals($expected, $out); | ||
160 | } | ||
161 | |||
162 | /** | ||
163 | * Test save_plugin_config with invalid data. | ||
164 | * | ||
165 | * @expectedException PluginConfigOrderException | ||
166 | */ | ||
167 | public function testSavePluginConfigInvalid() | ||
168 | { | ||
169 | $data = array( | ||
170 | 'plugin2' => 0, | ||
171 | 'plugin3' => 0, | ||
172 | 'order_plugin3' => 0, | ||
173 | 'plugin4' => 0, | ||
174 | 'order_plugin4' => 0, | ||
175 | ); | ||
176 | |||
177 | save_plugin_config($data); | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * Test save_plugin_config without data. | ||
182 | */ | ||
183 | public function testSavePluginConfigEmpty() | ||
184 | { | ||
185 | $this->assertEquals(array(), save_plugin_config(array())); | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * Test validate_plugin_order with valid data. | ||
190 | */ | ||
191 | public function testValidatePluginOrderValid() | ||
192 | { | ||
193 | $data = array( | ||
194 | 'order_plugin1' => 2, | ||
195 | 'plugin2' => 0, | ||
196 | 'plugin3' => 0, | ||
197 | 'order_plugin3' => 1, | ||
198 | 'plugin4' => 0, | ||
199 | 'order_plugin4' => 5, | ||
200 | ); | ||
201 | |||
202 | $this->assertTrue(validate_plugin_order($data)); | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * Test validate_plugin_order with invalid data. | ||
207 | */ | ||
208 | public function testValidatePluginOrderInvalid() | ||
209 | { | ||
210 | $data = array( | ||
211 | 'order_plugin1' => 2, | ||
212 | 'order_plugin3' => 1, | ||
213 | 'order_plugin4' => 1, | ||
214 | ); | ||
215 | |||
216 | $this->assertFalse(validate_plugin_order($data)); | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * Test load_plugin_parameter_values. | ||
221 | */ | ||
222 | public function testLoadPluginParameterValues() | ||
223 | { | ||
224 | $plugins = array( | ||
225 | 'plugin_name' => array( | ||
226 | 'parameters' => array( | ||
227 | 'param1' => true, | ||
228 | 'param2' => false, | ||
229 | 'param3' => '', | ||
230 | ) | ||
231 | ) | ||
232 | ); | ||
233 | |||
234 | $parameters = array( | ||
235 | 'param1' => 'value1', | ||
236 | 'param2' => 'value2', | ||
237 | ); | ||
238 | |||
239 | $result = load_plugin_parameter_values($plugins, $parameters); | ||
240 | $this->assertEquals('value1', $result['plugin_name']['parameters']['param1']); | ||
241 | $this->assertEquals('value2', $result['plugin_name']['parameters']['param2']); | ||
242 | $this->assertEquals('', $result['plugin_name']['parameters']['param3']); | ||
243 | } | ||
244 | } | ||
diff --git a/tests/FeedBuilderTest.php b/tests/FeedBuilderTest.php index 647b2db2..460fb0c5 100644 --- a/tests/FeedBuilderTest.php +++ b/tests/FeedBuilderTest.php | |||
@@ -76,7 +76,7 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase | |||
76 | // Test headers (RSS) | 76 | // Test headers (RSS) |
77 | $this->assertEquals(self::$RSS_LANGUAGE, $data['language']); | 77 | $this->assertEquals(self::$RSS_LANGUAGE, $data['language']); |
78 | $this->assertEmpty($data['pubsubhub_url']); | 78 | $this->assertEmpty($data['pubsubhub_url']); |
79 | $this->assertEquals('Tue, 10 Mar 2015 11:46:51 +0100', $data['last_update']); | 79 | $this->assertRegExp('/Tue, 10 Mar 2015 11:46:51 \+\d{4}/', $data['last_update']); |
80 | $this->assertEquals(true, $data['show_dates']); | 80 | $this->assertEquals(true, $data['show_dates']); |
81 | $this->assertEquals('http://host.tld/index.php?do=feed', $data['self_link']); | 81 | $this->assertEquals('http://host.tld/index.php?do=feed', $data['self_link']); |
82 | $this->assertEquals('http://host.tld/', $data['index_url']); | 82 | $this->assertEquals('http://host.tld/', $data['index_url']); |
@@ -88,7 +88,7 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase | |||
88 | $this->assertEquals('20150310_114651', $link['linkdate']); | 88 | $this->assertEquals('20150310_114651', $link['linkdate']); |
89 | $this->assertEquals('http://host.tld/?WDWyig', $link['guid']); | 89 | $this->assertEquals('http://host.tld/?WDWyig', $link['guid']); |
90 | $this->assertEquals('http://host.tld/?WDWyig', $link['url']); | 90 | $this->assertEquals('http://host.tld/?WDWyig', $link['url']); |
91 | $this->assertEquals('Tue, 10 Mar 2015 11:46:51 +0100', $link['iso_date']); | 91 | $this->assertRegExp('/Tue, 10 Mar 2015 11:46:51 \+\d{4}/', $link['iso_date']); |
92 | $this->assertContains('Stallman has a beard', $link['description']); | 92 | $this->assertContains('Stallman has a beard', $link['description']); |
93 | $this->assertContains('Permalink', $link['description']); | 93 | $this->assertContains('Permalink', $link['description']); |
94 | $this->assertContains('http://host.tld/?WDWyig', $link['description']); | 94 | $this->assertContains('http://host.tld/?WDWyig', $link['description']); |
@@ -113,7 +113,7 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase | |||
113 | $data = $feedBuilder->buildData(); | 113 | $data = $feedBuilder->buildData(); |
114 | $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); | 114 | $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links'])); |
115 | $link = array_shift($data['links']); | 115 | $link = array_shift($data['links']); |
116 | $this->assertEquals('2015-03-10T11:46:51+01:00', $link['iso_date']); | 116 | $this->assertRegExp('/2015-03-10T11:46:51\+\d{2}:+\d{2}/', $link['iso_date']); |
117 | } | 117 | } |
118 | 118 | ||
119 | /** | 119 | /** |
diff --git a/tests/LinkDBTest.php b/tests/LinkDBTest.php index 0db81fd6..46956f20 100644 --- a/tests/LinkDBTest.php +++ b/tests/LinkDBTest.php | |||
@@ -101,7 +101,7 @@ class LinkDBTest extends PHPUnit_Framework_TestCase | |||
101 | * Attempt to instantiate a LinkDB whereas the datastore is not writable | 101 | * Attempt to instantiate a LinkDB whereas the datastore is not writable |
102 | * | 102 | * |
103 | * @expectedException IOException | 103 | * @expectedException IOException |
104 | * @expectedExceptionMessageRegExp /Error accessing null/ | 104 | * @expectedExceptionMessageRegExp /Error accessing\nnull/ |
105 | */ | 105 | */ |
106 | public function testConstructDatastoreNotWriteable() | 106 | public function testConstructDatastoreNotWriteable() |
107 | { | 107 | { |
diff --git a/tests/PluginManagerTest.php b/tests/PluginManagerTest.php index 348082c7..61efce68 100644 --- a/tests/PluginManagerTest.php +++ b/tests/PluginManagerTest.php | |||
@@ -24,29 +24,38 @@ class PluginManagerTest extends PHPUnit_Framework_TestCase | |||
24 | private static $pluginName = 'test'; | 24 | private static $pluginName = 'test'; |
25 | 25 | ||
26 | /** | 26 | /** |
27 | * @var PluginManager $pluginManager Plugin Mananger instance. | ||
28 | */ | ||
29 | protected $pluginManager; | ||
30 | |||
31 | public function setUp() | ||
32 | { | ||
33 | $conf = new ConfigManager(''); | ||
34 | $this->pluginManager = new PluginManager($conf); | ||
35 | } | ||
36 | |||
37 | /** | ||
27 | * Test plugin loading and hook execution. | 38 | * Test plugin loading and hook execution. |
28 | * | 39 | * |
29 | * @return void | 40 | * @return void |
30 | */ | 41 | */ |
31 | public function testPlugin() | 42 | public function testPlugin() |
32 | { | 43 | { |
33 | $pluginManager = PluginManager::getInstance(); | ||
34 | |||
35 | PluginManager::$PLUGINS_PATH = self::$pluginPath; | 44 | PluginManager::$PLUGINS_PATH = self::$pluginPath; |
36 | $pluginManager->load(array(self::$pluginName)); | 45 | $this->pluginManager->load(array(self::$pluginName)); |
37 | 46 | ||
38 | $this->assertTrue(function_exists('hook_test_random')); | 47 | $this->assertTrue(function_exists('hook_test_random')); |
39 | 48 | ||
40 | $data = array(0 => 'woot'); | 49 | $data = array(0 => 'woot'); |
41 | $pluginManager->executeHooks('random', $data); | 50 | $this->pluginManager->executeHooks('random', $data); |
42 | $this->assertEquals('woot', $data[1]); | 51 | $this->assertEquals('woot', $data[1]); |
43 | 52 | ||
44 | $data = array(0 => 'woot'); | 53 | $data = array(0 => 'woot'); |
45 | $pluginManager->executeHooks('random', $data, array('target' => 'test')); | 54 | $this->pluginManager->executeHooks('random', $data, array('target' => 'test')); |
46 | $this->assertEquals('page test', $data[1]); | 55 | $this->assertEquals('page test', $data[1]); |
47 | 56 | ||
48 | $data = array(0 => 'woot'); | 57 | $data = array(0 => 'woot'); |
49 | $pluginManager->executeHooks('random', $data, array('loggedin' => true)); | 58 | $this->pluginManager->executeHooks('random', $data, array('loggedin' => true)); |
50 | $this->assertEquals('loggedin', $data[1]); | 59 | $this->assertEquals('loggedin', $data[1]); |
51 | } | 60 | } |
52 | 61 | ||
@@ -57,11 +66,8 @@ class PluginManagerTest extends PHPUnit_Framework_TestCase | |||
57 | */ | 66 | */ |
58 | public function testPluginNotFound() | 67 | public function testPluginNotFound() |
59 | { | 68 | { |
60 | $pluginManager = PluginManager::getInstance(); | 69 | $this->pluginManager->load(array()); |
61 | 70 | $this->pluginManager->load(array('nope', 'renope')); | |
62 | $pluginManager->load(array()); | ||
63 | |||
64 | $pluginManager->load(array('nope', 'renope')); | ||
65 | } | 71 | } |
66 | 72 | ||
67 | /** | 73 | /** |
@@ -69,16 +75,14 @@ class PluginManagerTest extends PHPUnit_Framework_TestCase | |||
69 | */ | 75 | */ |
70 | public function testGetPluginsMeta() | 76 | public function testGetPluginsMeta() |
71 | { | 77 | { |
72 | $pluginManager = PluginManager::getInstance(); | ||
73 | |||
74 | PluginManager::$PLUGINS_PATH = self::$pluginPath; | 78 | PluginManager::$PLUGINS_PATH = self::$pluginPath; |
75 | $pluginManager->load(array(self::$pluginName)); | 79 | $this->pluginManager->load(array(self::$pluginName)); |
76 | 80 | ||
77 | $expectedParameters = array( | 81 | $expectedParameters = array( |
78 | 'pop' => '', | 82 | 'pop' => '', |
79 | 'hip' => '', | 83 | 'hip' => '', |
80 | ); | 84 | ); |
81 | $meta = $pluginManager->getPluginsMeta(); | 85 | $meta = $this->pluginManager->getPluginsMeta(); |
82 | $this->assertEquals('test plugin', $meta[self::$pluginName]['description']); | 86 | $this->assertEquals('test plugin', $meta[self::$pluginName]['description']); |
83 | $this->assertEquals($expectedParameters, $meta[self::$pluginName]['parameters']); | 87 | $this->assertEquals($expectedParameters, $meta[self::$pluginName]['parameters']); |
84 | } | 88 | } |
diff --git a/tests/Updater/DummyUpdater.php b/tests/Updater/DummyUpdater.php index e9ef2aaa..a0be4413 100644 --- a/tests/Updater/DummyUpdater.php +++ b/tests/Updater/DummyUpdater.php | |||
@@ -11,14 +11,14 @@ class DummyUpdater extends Updater | |||
11 | /** | 11 | /** |
12 | * Object constructor. | 12 | * Object constructor. |
13 | * | 13 | * |
14 | * @param array $doneUpdates Updates which are already done. | 14 | * @param array $doneUpdates Updates which are already done. |
15 | * @param array $config Shaarli's configuration array. | 15 | * @param LinkDB $linkDB LinkDB instance. |
16 | * @param LinkDB $linkDB LinkDB instance. | 16 | * @param ConfigManager $conf Configuration Manager instance. |
17 | * @param boolean $isLoggedIn True if the user is logged in. | 17 | * @param boolean $isLoggedIn True if the user is logged in. |
18 | */ | 18 | */ |
19 | public function __construct($doneUpdates, $config, $linkDB, $isLoggedIn) | 19 | public function __construct($doneUpdates, $linkDB, $conf, $isLoggedIn) |
20 | { | 20 | { |
21 | parent::__construct($doneUpdates, $config, $linkDB, $isLoggedIn); | 21 | parent::__construct($doneUpdates, $linkDB, $conf, $isLoggedIn); |
22 | 22 | ||
23 | // Retrieve all update methods. | 23 | // Retrieve all update methods. |
24 | // For unit test, only retrieve final methods, | 24 | // For unit test, only retrieve final methods, |
diff --git a/tests/Updater/UpdaterTest.php b/tests/Updater/UpdaterTest.php index a29d9067..6bdce08b 100644 --- a/tests/Updater/UpdaterTest.php +++ b/tests/Updater/UpdaterTest.php | |||
@@ -1,5 +1,6 @@ | |||
1 | <?php | 1 | <?php |
2 | 2 | ||
3 | require_once 'application/config/ConfigManager.php'; | ||
3 | require_once 'tests/Updater/DummyUpdater.php'; | 4 | require_once 'tests/Updater/DummyUpdater.php'; |
4 | 5 | ||
5 | /** | 6 | /** |
@@ -9,58 +10,26 @@ require_once 'tests/Updater/DummyUpdater.php'; | |||
9 | class UpdaterTest extends PHPUnit_Framework_TestCase | 10 | class UpdaterTest extends PHPUnit_Framework_TestCase |
10 | { | 11 | { |
11 | /** | 12 | /** |
12 | * @var array Configuration input set. | 13 | * @var string Path to test datastore. |
13 | */ | 14 | */ |
14 | private static $configFields; | 15 | protected static $testDatastore = 'sandbox/datastore.php'; |
15 | 16 | ||
16 | /** | 17 | /** |
17 | * @var string Path to test datastore. | 18 | * @var string Config file path (without extension). |
18 | */ | 19 | */ |
19 | protected static $testDatastore = 'sandbox/datastore.php'; | 20 | protected static $configFile = 'tests/utils/config/configJson'; |
20 | 21 | ||
21 | /** | 22 | /** |
22 | * Executed before each test. | 23 | * @var ConfigManager |
23 | */ | 24 | */ |
24 | public function setUp() | 25 | protected $conf; |
25 | { | ||
26 | self::$configFields = array( | ||
27 | 'login' => 'login', | ||
28 | 'hash' => 'hash', | ||
29 | 'salt' => 'salt', | ||
30 | 'timezone' => 'Europe/Paris', | ||
31 | 'title' => 'title', | ||
32 | 'titleLink' => 'titleLink', | ||
33 | 'redirector' => '', | ||
34 | 'disablesessionprotection' => false, | ||
35 | 'privateLinkByDefault' => false, | ||
36 | 'config' => array( | ||
37 | 'CONFIG_FILE' => 'tests/Updater/config.php', | ||
38 | 'DATADIR' => 'tests/Updater', | ||
39 | 'PAGECACHE' => 'sandbox/pagecache', | ||
40 | 'config1' => 'config1data', | ||
41 | 'config2' => 'config2data', | ||
42 | ) | ||
43 | ); | ||
44 | } | ||
45 | 26 | ||
46 | /** | 27 | /** |
47 | * Executed after each test. | 28 | * Executed before each test. |
48 | * | ||
49 | * @return void | ||
50 | */ | 29 | */ |
51 | public function tearDown() | 30 | public function setUp() |
52 | { | 31 | { |
53 | if (is_file(self::$configFields['config']['CONFIG_FILE'])) { | 32 | $this->conf = new ConfigManager(self::$configFile); |
54 | unlink(self::$configFields['config']['CONFIG_FILE']); | ||
55 | } | ||
56 | |||
57 | if (is_file(self::$configFields['config']['DATADIR'] . '/options.php')) { | ||
58 | unlink(self::$configFields['config']['DATADIR'] . '/options.php'); | ||
59 | } | ||
60 | |||
61 | if (is_file(self::$configFields['config']['DATADIR'] . '/updates.json')) { | ||
62 | unlink(self::$configFields['config']['DATADIR'] . '/updates.json'); | ||
63 | } | ||
64 | } | 33 | } |
65 | 34 | ||
66 | /** | 35 | /** |
@@ -69,9 +38,10 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
69 | public function testReadEmptyUpdatesFile() | 38 | public function testReadEmptyUpdatesFile() |
70 | { | 39 | { |
71 | $this->assertEquals(array(), read_updates_file('')); | 40 | $this->assertEquals(array(), read_updates_file('')); |
72 | $updatesFile = self::$configFields['config']['DATADIR'] . '/updates.json'; | 41 | $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt'; |
73 | touch($updatesFile); | 42 | touch($updatesFile); |
74 | $this->assertEquals(array(), read_updates_file($updatesFile)); | 43 | $this->assertEquals(array(), read_updates_file($updatesFile)); |
44 | unlink($updatesFile); | ||
75 | } | 45 | } |
76 | 46 | ||
77 | /** | 47 | /** |
@@ -79,7 +49,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
79 | */ | 49 | */ |
80 | public function testReadWriteUpdatesFile() | 50 | public function testReadWriteUpdatesFile() |
81 | { | 51 | { |
82 | $updatesFile = self::$configFields['config']['DATADIR'] . '/updates.json'; | 52 | $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt'; |
83 | $updatesMethods = array('m1', 'm2', 'm3'); | 53 | $updatesMethods = array('m1', 'm2', 'm3'); |
84 | 54 | ||
85 | write_updates_file($updatesFile, $updatesMethods); | 55 | write_updates_file($updatesFile, $updatesMethods); |
@@ -91,6 +61,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
91 | write_updates_file($updatesFile, $updatesMethods); | 61 | write_updates_file($updatesFile, $updatesMethods); |
92 | $readMethods = read_updates_file($updatesFile); | 62 | $readMethods = read_updates_file($updatesFile); |
93 | $this->assertEquals($readMethods, $updatesMethods); | 63 | $this->assertEquals($readMethods, $updatesMethods); |
64 | unlink($updatesFile); | ||
94 | } | 65 | } |
95 | 66 | ||
96 | /** | 67 | /** |
@@ -112,10 +83,15 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
112 | */ | 83 | */ |
113 | public function testWriteUpdatesFileNotWritable() | 84 | public function testWriteUpdatesFileNotWritable() |
114 | { | 85 | { |
115 | $updatesFile = self::$configFields['config']['DATADIR'] . '/updates.json'; | 86 | $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt'; |
116 | touch($updatesFile); | 87 | touch($updatesFile); |
117 | chmod($updatesFile, 0444); | 88 | chmod($updatesFile, 0444); |
118 | @write_updates_file($updatesFile, array('test')); | 89 | try { |
90 | @write_updates_file($updatesFile, array('test')); | ||
91 | } catch (Exception $e) { | ||
92 | unlink($updatesFile); | ||
93 | throw $e; | ||
94 | } | ||
119 | } | 95 | } |
120 | 96 | ||
121 | /** | 97 | /** |
@@ -131,10 +107,10 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
131 | 'updateMethodDummy3', | 107 | 'updateMethodDummy3', |
132 | 'updateMethodException', | 108 | 'updateMethodException', |
133 | ); | 109 | ); |
134 | $updater = new DummyUpdater($updates, array(), array(), true); | 110 | $updater = new DummyUpdater($updates, array(), $this->conf, true); |
135 | $this->assertEquals(array(), $updater->update()); | 111 | $this->assertEquals(array(), $updater->update()); |
136 | 112 | ||
137 | $updater = new DummyUpdater(array(), array(), array(), false); | 113 | $updater = new DummyUpdater(array(), array(), $this->conf, false); |
138 | $this->assertEquals(array(), $updater->update()); | 114 | $this->assertEquals(array(), $updater->update()); |
139 | } | 115 | } |
140 | 116 | ||
@@ -149,7 +125,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
149 | 'updateMethodDummy2', | 125 | 'updateMethodDummy2', |
150 | 'updateMethodDummy3', | 126 | 'updateMethodDummy3', |
151 | ); | 127 | ); |
152 | $updater = new DummyUpdater($updates, array(), array(), true); | 128 | $updater = new DummyUpdater($updates, array(), $this->conf, true); |
153 | $this->assertEquals($expectedUpdates, $updater->update()); | 129 | $this->assertEquals($expectedUpdates, $updater->update()); |
154 | } | 130 | } |
155 | 131 | ||
@@ -165,7 +141,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
165 | ); | 141 | ); |
166 | $expectedUpdate = array('updateMethodDummy2'); | 142 | $expectedUpdate = array('updateMethodDummy2'); |
167 | 143 | ||
168 | $updater = new DummyUpdater($updates, array(), array(), true); | 144 | $updater = new DummyUpdater($updates, array(), $this->conf, true); |
169 | $this->assertEquals($expectedUpdate, $updater->update()); | 145 | $this->assertEquals($expectedUpdate, $updater->update()); |
170 | } | 146 | } |
171 | 147 | ||
@@ -182,7 +158,7 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
182 | 'updateMethodDummy3', | 158 | 'updateMethodDummy3', |
183 | ); | 159 | ); |
184 | 160 | ||
185 | $updater = new DummyUpdater($updates, array(), array(), true); | 161 | $updater = new DummyUpdater($updates, array(), $this->conf, true); |
186 | $updater->update(); | 162 | $updater->update(); |
187 | } | 163 | } |
188 | 164 | ||
@@ -195,26 +171,28 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
195 | */ | 171 | */ |
196 | public function testUpdateMergeDeprecatedConfig() | 172 | public function testUpdateMergeDeprecatedConfig() |
197 | { | 173 | { |
198 | // init | 174 | $this->conf->setConfigFile('tests/utils/config/configPhp'); |
199 | writeConfig(self::$configFields, true); | 175 | $this->conf->reset(); |
200 | $configCopy = self::$configFields; | ||
201 | $invert = !$configCopy['privateLinkByDefault']; | ||
202 | $configCopy['privateLinkByDefault'] = $invert; | ||
203 | 176 | ||
204 | // Use writeConfig to create a options.php | 177 | $optionsFile = 'tests/Updater/options.php'; |
205 | $configCopy['config']['CONFIG_FILE'] = 'tests/Updater/options.php'; | 178 | $options = '<?php |
206 | writeConfig($configCopy, true); | 179 | $GLOBALS[\'privateLinkByDefault\'] = true;'; |
180 | file_put_contents($optionsFile, $options); | ||
207 | 181 | ||
208 | $this->assertTrue(is_file($configCopy['config']['CONFIG_FILE'])); | 182 | // tmp config file. |
183 | $this->conf->setConfigFile('tests/Updater/config'); | ||
209 | 184 | ||
210 | // merge configs | 185 | // merge configs |
211 | $updater = new Updater(array(), self::$configFields, array(), true); | 186 | $updater = new Updater(array(), array(), $this->conf, true); |
187 | // This writes a new config file in tests/Updater/config.php | ||
212 | $updater->updateMethodMergeDeprecatedConfigFile(); | 188 | $updater->updateMethodMergeDeprecatedConfigFile(); |
213 | 189 | ||
214 | // make sure updated field is changed | 190 | // make sure updated field is changed |
215 | include self::$configFields['config']['CONFIG_FILE']; | 191 | $this->conf->reload(); |
216 | $this->assertEquals($invert, $GLOBALS['privateLinkByDefault']); | 192 | $this->assertTrue($this->conf->get('privacy.default_private_links')); |
217 | $this->assertFalse(is_file($configCopy['config']['CONFIG_FILE'])); | 193 | $this->assertFalse(is_file($optionsFile)); |
194 | // Delete the generated file. | ||
195 | unlink($this->conf->getConfigFileExt()); | ||
218 | } | 196 | } |
219 | 197 | ||
220 | /** | 198 | /** |
@@ -222,23 +200,67 @@ class UpdaterTest extends PHPUnit_Framework_TestCase | |||
222 | */ | 200 | */ |
223 | public function testMergeDeprecatedConfigNoFile() | 201 | public function testMergeDeprecatedConfigNoFile() |
224 | { | 202 | { |
225 | writeConfig(self::$configFields, true); | 203 | $updater = new Updater(array(), array(), $this->conf, true); |
226 | |||
227 | $updater = new Updater(array(), self::$configFields, array(), true); | ||
228 | $updater->updateMethodMergeDeprecatedConfigFile(); | 204 | $updater->updateMethodMergeDeprecatedConfigFile(); |
229 | 205 | ||
230 | include self::$configFields['config']['CONFIG_FILE']; | 206 | $this->assertEquals('root', $this->conf->get('credentials.login')); |
231 | $this->assertEquals(self::$configFields['login'], $GLOBALS['login']); | ||
232 | } | 207 | } |
233 | 208 | ||
209 | /** | ||
210 | * Test renameDashTags update method. | ||
211 | */ | ||
234 | public function testRenameDashTags() | 212 | public function testRenameDashTags() |
235 | { | 213 | { |
236 | $refDB = new ReferenceLinkDB(); | 214 | $refDB = new ReferenceLinkDB(); |
237 | $refDB->write(self::$testDatastore); | 215 | $refDB->write(self::$testDatastore); |
238 | $linkDB = new LinkDB(self::$testDatastore, true, false); | 216 | $linkDB = new LinkDB(self::$testDatastore, true, false); |
239 | $this->assertEmpty($linkDB->filterSearch(array('searchtags' => 'exclude'))); | 217 | $this->assertEmpty($linkDB->filterSearch(array('searchtags' => 'exclude'))); |
240 | $updater = new Updater(array(), self::$configFields, $linkDB, true); | 218 | $updater = new Updater(array(), $linkDB, $this->conf, true); |
241 | $updater->updateMethodRenameDashTags(); | 219 | $updater->updateMethodRenameDashTags(); |
242 | $this->assertNotEmpty($linkDB->filterSearch(array('searchtags' => 'exclude'))); | 220 | $this->assertNotEmpty($linkDB->filterSearch(array('searchtags' => 'exclude'))); |
243 | } | 221 | } |
222 | |||
223 | /** | ||
224 | * Convert old PHP config file to JSON config. | ||
225 | */ | ||
226 | public function testConfigToJson() | ||
227 | { | ||
228 | $configFile = 'tests/utils/config/configPhp'; | ||
229 | $this->conf->setConfigFile($configFile); | ||
230 | $this->conf->reset(); | ||
231 | |||
232 | // The ConfigIO is initialized with ConfigPhp. | ||
233 | $this->assertTrue($this->conf->getConfigIO() instanceof ConfigPhp); | ||
234 | |||
235 | $updater = new Updater(array(), array(), $this->conf, false); | ||
236 | $done = $updater->updateMethodConfigToJson(); | ||
237 | $this->assertTrue($done); | ||
238 | |||
239 | // The ConfigIO has been updated to ConfigJson. | ||
240 | $this->assertTrue($this->conf->getConfigIO() instanceof ConfigJson); | ||
241 | $this->assertTrue(file_exists($this->conf->getConfigFileExt())); | ||
242 | |||
243 | // Check JSON config data. | ||
244 | $this->conf->reload(); | ||
245 | $this->assertEquals('root', $this->conf->get('credentials.login')); | ||
246 | $this->assertEquals('lala', $this->conf->get('redirector.url')); | ||
247 | $this->assertEquals('data/datastore.php', $this->conf->get('resource.datastore')); | ||
248 | $this->assertEquals('1', $this->conf->get('plugins.WALLABAG_VERSION')); | ||
249 | |||
250 | rename($configFile . '.save.php', $configFile . '.php'); | ||
251 | unlink($this->conf->getConfigFileExt()); | ||
252 | } | ||
253 | |||
254 | /** | ||
255 | * Launch config conversion update with an existing JSON file => nothing to do. | ||
256 | */ | ||
257 | public function testConfigToJsonNothingToDo() | ||
258 | { | ||
259 | $filetime = filemtime($this->conf->getConfigFileExt()); | ||
260 | $updater = new Updater(array(), array(), $this->conf, false); | ||
261 | $done = $updater->updateMethodConfigToJson(); | ||
262 | $this->assertTrue($done); | ||
263 | $expected = filemtime($this->conf->getConfigFileExt()); | ||
264 | $this->assertEquals($expected, $filetime); | ||
265 | } | ||
244 | } | 266 | } |
diff --git a/tests/config/ConfigJsonTest.php b/tests/config/ConfigJsonTest.php new file mode 100644 index 00000000..99c88820 --- /dev/null +++ b/tests/config/ConfigJsonTest.php | |||
@@ -0,0 +1,133 @@ | |||
1 | <?php | ||
2 | |||
3 | require_once 'application/config/ConfigJson.php'; | ||
4 | |||
5 | /** | ||
6 | * Class ConfigJsonTest | ||
7 | */ | ||
8 | class ConfigJsonTest extends PHPUnit_Framework_TestCase | ||
9 | { | ||
10 | /** | ||
11 | * @var ConfigJson | ||
12 | */ | ||
13 | protected $configIO; | ||
14 | |||
15 | public function setUp() | ||
16 | { | ||
17 | $this->configIO = new ConfigJson(); | ||
18 | } | ||
19 | |||
20 | /** | ||
21 | * Read a simple existing config file. | ||
22 | */ | ||
23 | public function testRead() | ||
24 | { | ||
25 | $conf = $this->configIO->read('tests/utils/config/configJson.json.php'); | ||
26 | $this->assertEquals('root', $conf['credentials']['login']); | ||
27 | $this->assertEquals('lala', $conf['redirector']['url']); | ||
28 | $this->assertEquals('tests/utils/config/datastore.php', $conf['resource']['datastore']); | ||
29 | $this->assertEquals('1', $conf['plugins']['WALLABAG_VERSION']); | ||
30 | } | ||
31 | |||
32 | /** | ||
33 | * Read a non existent config file -> empty array. | ||
34 | */ | ||
35 | public function testReadNonExistent() | ||
36 | { | ||
37 | $this->assertEquals(array(), $this->configIO->read('nope')); | ||
38 | } | ||
39 | |||
40 | /** | ||
41 | * Read a non existent config file -> empty array. | ||
42 | * | ||
43 | * @expectedException Exception | ||
44 | * @expectedExceptionMessage An error occured while parsing JSON file: error code #4 | ||
45 | */ | ||
46 | public function testReadInvalidJson() | ||
47 | { | ||
48 | $this->configIO->read('tests/utils/config/configInvalid.json.php'); | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * Write a new config file. | ||
53 | */ | ||
54 | public function testWriteNew() | ||
55 | { | ||
56 | $dataFile = 'tests/utils/config/configWrite.json.php'; | ||
57 | $data = array( | ||
58 | 'credentials' => array( | ||
59 | 'login' => 'root', | ||
60 | ), | ||
61 | 'resource' => array( | ||
62 | 'datastore' => 'data/datastore.php', | ||
63 | ), | ||
64 | 'redirector' => array( | ||
65 | 'url' => 'lala', | ||
66 | ), | ||
67 | 'plugins' => array( | ||
68 | 'WALLABAG_VERSION' => '1', | ||
69 | ) | ||
70 | ); | ||
71 | $this->configIO->write($dataFile, $data); | ||
72 | // PHP 5.3 doesn't support json pretty print. | ||
73 | if (defined('JSON_PRETTY_PRINT')) { | ||
74 | $expected = '{ | ||
75 | "credentials": { | ||
76 | "login": "root" | ||
77 | }, | ||
78 | "resource": { | ||
79 | "datastore": "data\/datastore.php" | ||
80 | }, | ||
81 | "redirector": { | ||
82 | "url": "lala" | ||
83 | }, | ||
84 | "plugins": { | ||
85 | "WALLABAG_VERSION": "1" | ||
86 | } | ||
87 | }'; | ||
88 | } else { | ||
89 | $expected = '{"credentials":{"login":"root"},"resource":{"datastore":"data\/datastore.php"},"redirector":{"url":"lala"},"plugins":{"WALLABAG_VERSION":"1"}}'; | ||
90 | } | ||
91 | $expected = ConfigJson::getPhpHeaders() . $expected . ConfigJson::getPhpSuffix(); | ||
92 | $this->assertEquals($expected, file_get_contents($dataFile)); | ||
93 | unlink($dataFile); | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * Overwrite an existing setting. | ||
98 | */ | ||
99 | public function testOverwrite() | ||
100 | { | ||
101 | $source = 'tests/utils/config/configJson.json.php'; | ||
102 | $dest = 'tests/utils/config/configOverwrite.json.php'; | ||
103 | copy($source, $dest); | ||
104 | $conf = $this->configIO->read($dest); | ||
105 | $conf['redirector']['url'] = 'blabla'; | ||
106 | $this->configIO->write($dest, $conf); | ||
107 | $conf = $this->configIO->read($dest); | ||
108 | $this->assertEquals('blabla', $conf['redirector']['url']); | ||
109 | unlink($dest); | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * Write to invalid path. | ||
114 | * | ||
115 | * @expectedException IOException | ||
116 | */ | ||
117 | public function testWriteInvalidArray() | ||
118 | { | ||
119 | $conf = array('conf' => 'value'); | ||
120 | @$this->configIO->write(array(), $conf); | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * Write to invalid path. | ||
125 | * | ||
126 | * @expectedException IOException | ||
127 | */ | ||
128 | public function testWriteInvalidBlank() | ||
129 | { | ||
130 | $conf = array('conf' => 'value'); | ||
131 | @$this->configIO->write('', $conf); | ||
132 | } | ||
133 | } | ||
diff --git a/tests/config/ConfigManagerTest.php b/tests/config/ConfigManagerTest.php new file mode 100644 index 00000000..436e3d67 --- /dev/null +++ b/tests/config/ConfigManagerTest.php | |||
@@ -0,0 +1,172 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Unit tests for Class ConfigManagerTest | ||
5 | * | ||
6 | * Note: it only test the manager with ConfigJson, | ||
7 | * ConfigPhp is only a workaround to handle the transition to JSON type. | ||
8 | */ | ||
9 | class ConfigManagerTest extends PHPUnit_Framework_TestCase | ||
10 | { | ||
11 | /** | ||
12 | * @var ConfigManager | ||
13 | */ | ||
14 | protected $conf; | ||
15 | |||
16 | public function setUp() | ||
17 | { | ||
18 | $this->conf = new ConfigManager('tests/utils/config/configJson'); | ||
19 | } | ||
20 | |||
21 | /** | ||
22 | * Simple config test: | ||
23 | * 1. Set settings. | ||
24 | * 2. Check settings value. | ||
25 | */ | ||
26 | public function testSetGet() | ||
27 | { | ||
28 | $this->conf->set('paramInt', 42); | ||
29 | $this->conf->set('paramString', 'value1'); | ||
30 | $this->conf->set('paramBool', false); | ||
31 | $this->conf->set('paramArray', array('foo' => 'bar')); | ||
32 | $this->conf->set('paramNull', null); | ||
33 | |||
34 | $this->assertEquals(42, $this->conf->get('paramInt')); | ||
35 | $this->assertEquals('value1', $this->conf->get('paramString')); | ||
36 | $this->assertFalse($this->conf->get('paramBool')); | ||
37 | $this->assertEquals(array('foo' => 'bar'), $this->conf->get('paramArray')); | ||
38 | $this->assertEquals(null, $this->conf->get('paramNull')); | ||
39 | } | ||
40 | |||
41 | /** | ||
42 | * Set/write/get config test: | ||
43 | * 1. Set settings. | ||
44 | * 2. Write it to the config file. | ||
45 | * 3. Read the file. | ||
46 | * 4. Check settings value. | ||
47 | */ | ||
48 | public function testSetWriteGet() | ||
49 | { | ||
50 | $this->conf->set('paramInt', 42); | ||
51 | $this->conf->set('paramString', 'value1'); | ||
52 | $this->conf->set('paramBool', false); | ||
53 | $this->conf->set('paramArray', array('foo' => 'bar')); | ||
54 | $this->conf->set('paramNull', null); | ||
55 | |||
56 | $this->conf->setConfigFile('tests/utils/config/configTmp'); | ||
57 | $this->conf->write(true); | ||
58 | $this->conf->reload(); | ||
59 | unlink($this->conf->getConfigFileExt()); | ||
60 | |||
61 | $this->assertEquals(42, $this->conf->get('paramInt')); | ||
62 | $this->assertEquals('value1', $this->conf->get('paramString')); | ||
63 | $this->assertFalse($this->conf->get('paramBool')); | ||
64 | $this->assertEquals(array('foo' => 'bar'), $this->conf->get('paramArray')); | ||
65 | $this->assertEquals(null, $this->conf->get('paramNull')); | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * Test set/write/get with nested keys. | ||
70 | */ | ||
71 | public function testSetWriteGetNested() | ||
72 | { | ||
73 | $this->conf->set('foo.bar.key.stuff', 'testSetWriteGetNested'); | ||
74 | |||
75 | $this->conf->setConfigFile('tests/utils/config/configTmp'); | ||
76 | $this->conf->write(true); | ||
77 | $this->conf->reload(); | ||
78 | unlink($this->conf->getConfigFileExt()); | ||
79 | |||
80 | $this->assertEquals('testSetWriteGetNested', $this->conf->get('foo.bar.key.stuff')); | ||
81 | } | ||
82 | |||
83 | /** | ||
84 | * Set with an empty key. | ||
85 | * | ||
86 | * @expectedException Exception | ||
87 | * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*# | ||
88 | */ | ||
89 | public function testSetEmptyKey() | ||
90 | { | ||
91 | $this->conf->set('', 'stuff'); | ||
92 | } | ||
93 | |||
94 | /** | ||
95 | * Set with an array key. | ||
96 | * | ||
97 | * @expectedException Exception | ||
98 | * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*# | ||
99 | */ | ||
100 | public function testSetArrayKey() | ||
101 | { | ||
102 | $this->conf->set(array('foo' => 'bar'), 'stuff'); | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * Try to write the config without mandatory parameter (e.g. 'login'). | ||
107 | * | ||
108 | * @expectedException MissingFieldConfigException | ||
109 | */ | ||
110 | public function testWriteMissingParameter() | ||
111 | { | ||
112 | $this->conf->setConfigFile('tests/utils/config/configTmp'); | ||
113 | $this->assertFalse(file_exists($this->conf->getConfigFileExt())); | ||
114 | $this->conf->reload(); | ||
115 | |||
116 | $this->conf->write(true); | ||
117 | } | ||
118 | |||
119 | /** | ||
120 | * Try to get non existent config keys. | ||
121 | */ | ||
122 | public function testGetNonExistent() | ||
123 | { | ||
124 | $this->assertEquals('', $this->conf->get('nope.test')); | ||
125 | $this->assertEquals('default', $this->conf->get('nope.test', 'default')); | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * Test the 'exists' method with existent values. | ||
130 | */ | ||
131 | public function testExistsOk() | ||
132 | { | ||
133 | $this->assertTrue($this->conf->exists('credentials.login')); | ||
134 | $this->assertTrue($this->conf->exists('config.foo')); | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * Test the 'exists' method with non existent or invalid values. | ||
139 | */ | ||
140 | public function testExistsKo() | ||
141 | { | ||
142 | $this->assertFalse($this->conf->exists('nope')); | ||
143 | $this->assertFalse($this->conf->exists('nope.nope')); | ||
144 | $this->assertFalse($this->conf->exists('')); | ||
145 | $this->assertFalse($this->conf->exists(false)); | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * Reset the ConfigManager instance. | ||
150 | */ | ||
151 | public function testReset() | ||
152 | { | ||
153 | $confIO = $this->conf->getConfigIO(); | ||
154 | $this->conf->reset(); | ||
155 | $this->assertFalse($confIO === $this->conf->getConfigIO()); | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * Reload the config from file. | ||
160 | */ | ||
161 | public function testReload() | ||
162 | { | ||
163 | $this->conf->setConfigFile('tests/utils/config/configTmp'); | ||
164 | $newConf = ConfigJson::getPhpHeaders() . '{ "key": "value" }'; | ||
165 | file_put_contents($this->conf->getConfigFileExt(), $newConf); | ||
166 | $this->conf->reload(); | ||
167 | unlink($this->conf->getConfigFileExt()); | ||
168 | // Previous conf no longer exists, and new values have been loaded. | ||
169 | $this->assertFalse($this->conf->exists('credentials.login')); | ||
170 | $this->assertEquals('value', $this->conf->get('key')); | ||
171 | } | ||
172 | } | ||
diff --git a/tests/config/ConfigPhpTest.php b/tests/config/ConfigPhpTest.php new file mode 100644 index 00000000..58cd8d2a --- /dev/null +++ b/tests/config/ConfigPhpTest.php | |||
@@ -0,0 +1,82 @@ | |||
1 | <?php | ||
2 | |||
3 | require_once 'application/config/ConfigPhp.php'; | ||
4 | |||
5 | /** | ||
6 | * Class ConfigPhpTest | ||
7 | */ | ||
8 | class ConfigPhpTest extends PHPUnit_Framework_TestCase | ||
9 | { | ||
10 | /** | ||
11 | * @var ConfigPhp | ||
12 | */ | ||
13 | protected $configIO; | ||
14 | |||
15 | public function setUp() | ||
16 | { | ||
17 | $this->configIO = new ConfigPhp(); | ||
18 | } | ||
19 | |||
20 | /** | ||
21 | * Read a simple existing config file. | ||
22 | */ | ||
23 | public function testRead() | ||
24 | { | ||
25 | $conf = $this->configIO->read('tests/utils/config/configPhp.php'); | ||
26 | $this->assertEquals('root', $conf['login']); | ||
27 | $this->assertEquals('lala', $conf['redirector']); | ||
28 | $this->assertEquals('data/datastore.php', $conf['config']['DATASTORE']); | ||
29 | $this->assertEquals('1', $conf['plugins']['WALLABAG_VERSION']); | ||
30 | } | ||
31 | |||
32 | /** | ||
33 | * Read a non existent config file -> empty array. | ||
34 | */ | ||
35 | public function testReadNonExistent() | ||
36 | { | ||
37 | $this->assertEquals(array(), $this->configIO->read('nope')); | ||
38 | } | ||
39 | |||
40 | /** | ||
41 | * Write a new config file. | ||
42 | */ | ||
43 | public function testWriteNew() | ||
44 | { | ||
45 | $dataFile = 'tests/utils/config/configWrite.php'; | ||
46 | $data = array( | ||
47 | 'login' => 'root', | ||
48 | 'redirector' => 'lala', | ||
49 | 'config' => array( | ||
50 | 'DATASTORE' => 'data/datastore.php', | ||
51 | ), | ||
52 | 'plugins' => array( | ||
53 | 'WALLABAG_VERSION' => '1', | ||
54 | ) | ||
55 | ); | ||
56 | $this->configIO->write($dataFile, $data); | ||
57 | $expected = '<?php | ||
58 | $GLOBALS[\'login\'] = \'root\'; | ||
59 | $GLOBALS[\'redirector\'] = \'lala\'; | ||
60 | $GLOBALS[\'config\'][\'DATASTORE\'] = \'data/datastore.php\'; | ||
61 | $GLOBALS[\'plugins\'][\'WALLABAG_VERSION\'] = \'1\'; | ||
62 | '; | ||
63 | $this->assertEquals($expected, file_get_contents($dataFile)); | ||
64 | unlink($dataFile); | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * Overwrite an existing setting. | ||
69 | */ | ||
70 | public function testOverwrite() | ||
71 | { | ||
72 | $source = 'tests/utils/config/configPhp.php'; | ||
73 | $dest = 'tests/utils/config/configOverwrite.php'; | ||
74 | copy($source, $dest); | ||
75 | $conf = $this->configIO->read($dest); | ||
76 | $conf['redirector'] = 'blabla'; | ||
77 | $this->configIO->write($dest, $conf); | ||
78 | $conf = $this->configIO->read($dest); | ||
79 | $this->assertEquals('blabla', $conf['redirector']); | ||
80 | unlink($dest); | ||
81 | } | ||
82 | } | ||
diff --git a/tests/config/ConfigPluginTest.php b/tests/config/ConfigPluginTest.php new file mode 100644 index 00000000..716631b0 --- /dev/null +++ b/tests/config/ConfigPluginTest.php | |||
@@ -0,0 +1,121 @@ | |||
1 | <?php | ||
2 | /** | ||
3 | * Config' tests | ||
4 | */ | ||
5 | |||
6 | require_once 'application/config/ConfigPlugin.php'; | ||
7 | |||
8 | /** | ||
9 | * Unitary tests for Shaarli config related functions | ||
10 | */ | ||
11 | class ConfigPluginTest extends PHPUnit_Framework_TestCase | ||
12 | { | ||
13 | /** | ||
14 | * Test save_plugin_config with valid data. | ||
15 | * | ||
16 | * @throws PluginConfigOrderException | ||
17 | */ | ||
18 | public function testSavePluginConfigValid() | ||
19 | { | ||
20 | $data = array( | ||
21 | 'order_plugin1' => 2, // no plugin related | ||
22 | 'plugin2' => 0, // new - at the end | ||
23 | 'plugin3' => 0, // 2nd | ||
24 | 'order_plugin3' => 8, | ||
25 | 'plugin4' => 0, // 1st | ||
26 | 'order_plugin4' => 5, | ||
27 | ); | ||
28 | |||
29 | $expected = array( | ||
30 | 'plugin3', | ||
31 | 'plugin4', | ||
32 | 'plugin2', | ||
33 | ); | ||
34 | |||
35 | $out = save_plugin_config($data); | ||
36 | $this->assertEquals($expected, $out); | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * Test save_plugin_config with invalid data. | ||
41 | * | ||
42 | * @expectedException PluginConfigOrderException | ||
43 | */ | ||
44 | public function testSavePluginConfigInvalid() | ||
45 | { | ||
46 | $data = array( | ||
47 | 'plugin2' => 0, | ||
48 | 'plugin3' => 0, | ||
49 | 'order_plugin3' => 0, | ||
50 | 'plugin4' => 0, | ||
51 | 'order_plugin4' => 0, | ||
52 | ); | ||
53 | |||
54 | save_plugin_config($data); | ||
55 | } | ||
56 | |||
57 | /** | ||
58 | * Test save_plugin_config without data. | ||
59 | */ | ||
60 | public function testSavePluginConfigEmpty() | ||
61 | { | ||
62 | $this->assertEquals(array(), save_plugin_config(array())); | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * Test validate_plugin_order with valid data. | ||
67 | */ | ||
68 | public function testValidatePluginOrderValid() | ||
69 | { | ||
70 | $data = array( | ||
71 | 'order_plugin1' => 2, | ||
72 | 'plugin2' => 0, | ||
73 | 'plugin3' => 0, | ||
74 | 'order_plugin3' => 1, | ||
75 | 'plugin4' => 0, | ||
76 | 'order_plugin4' => 5, | ||
77 | ); | ||
78 | |||
79 | $this->assertTrue(validate_plugin_order($data)); | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * Test validate_plugin_order with invalid data. | ||
84 | */ | ||
85 | public function testValidatePluginOrderInvalid() | ||
86 | { | ||
87 | $data = array( | ||
88 | 'order_plugin1' => 2, | ||
89 | 'order_plugin3' => 1, | ||
90 | 'order_plugin4' => 1, | ||
91 | ); | ||
92 | |||
93 | $this->assertFalse(validate_plugin_order($data)); | ||
94 | } | ||
95 | |||
96 | /** | ||
97 | * Test load_plugin_parameter_values. | ||
98 | */ | ||
99 | public function testLoadPluginParameterValues() | ||
100 | { | ||
101 | $plugins = array( | ||
102 | 'plugin_name' => array( | ||
103 | 'parameters' => array( | ||
104 | 'param1' => true, | ||
105 | 'param2' => false, | ||
106 | 'param3' => '', | ||
107 | ) | ||
108 | ) | ||
109 | ); | ||
110 | |||
111 | $parameters = array( | ||
112 | 'param1' => 'value1', | ||
113 | 'param2' => 'value2', | ||
114 | ); | ||
115 | |||
116 | $result = load_plugin_parameter_values($plugins, $parameters); | ||
117 | $this->assertEquals('value1', $result['plugin_name']['parameters']['param1']); | ||
118 | $this->assertEquals('value2', $result['plugin_name']['parameters']['param2']); | ||
119 | $this->assertEquals('', $result['plugin_name']['parameters']['param3']); | ||
120 | } | ||
121 | } | ||
diff --git a/tests/plugins/PluginReadityourselfTest.php b/tests/plugins/PluginReadityourselfTest.php index 8bf17bf1..d73e666a 100644 --- a/tests/plugins/PluginReadityourselfTest.php +++ b/tests/plugins/PluginReadityourselfTest.php | |||
@@ -4,6 +4,8 @@ | |||
4 | * PluginReadityourselfTest.php.php | 4 | * PluginReadityourselfTest.php.php |
5 | */ | 5 | */ |
6 | 6 | ||
7 | // FIXME! add an init method. | ||
8 | $conf = new ConfigManager(''); | ||
7 | require_once 'plugins/readityourself/readityourself.php'; | 9 | require_once 'plugins/readityourself/readityourself.php'; |
8 | 10 | ||
9 | /** | 11 | /** |
@@ -25,7 +27,8 @@ class PluginReadityourselfTest extends PHPUnit_Framework_TestCase | |||
25 | */ | 27 | */ |
26 | function testReadityourselfLinklist() | 28 | function testReadityourselfLinklist() |
27 | { | 29 | { |
28 | $GLOBALS['plugins']['READITYOUSELF_URL'] = 'value'; | 30 | $conf = new ConfigManager(''); |
31 | $conf->set('plugins.READITYOUSELF_URL', 'value'); | ||
29 | $str = 'http://randomstr.com/test'; | 32 | $str = 'http://randomstr.com/test'; |
30 | $data = array( | 33 | $data = array( |
31 | 'title' => $str, | 34 | 'title' => $str, |
@@ -36,7 +39,7 @@ class PluginReadityourselfTest extends PHPUnit_Framework_TestCase | |||
36 | ) | 39 | ) |
37 | ); | 40 | ); |
38 | 41 | ||
39 | $data = hook_readityourself_render_linklist($data); | 42 | $data = hook_readityourself_render_linklist($data, $conf); |
40 | $link = $data['links'][0]; | 43 | $link = $data['links'][0]; |
41 | // data shouldn't be altered | 44 | // data shouldn't be altered |
42 | $this->assertEquals($str, $data['title']); | 45 | $this->assertEquals($str, $data['title']); |
@@ -52,7 +55,8 @@ class PluginReadityourselfTest extends PHPUnit_Framework_TestCase | |||
52 | */ | 55 | */ |
53 | function testReadityourselfLinklistWithoutConfig() | 56 | function testReadityourselfLinklistWithoutConfig() |
54 | { | 57 | { |
55 | unset($GLOBALS['plugins']['READITYOUSELF_URL']); | 58 | $conf = new ConfigManager(''); |
59 | $conf->set('plugins.READITYOUSELF_URL', null); | ||
56 | $str = 'http://randomstr.com/test'; | 60 | $str = 'http://randomstr.com/test'; |
57 | $data = array( | 61 | $data = array( |
58 | 'title' => $str, | 62 | 'title' => $str, |
@@ -63,7 +67,7 @@ class PluginReadityourselfTest extends PHPUnit_Framework_TestCase | |||
63 | ) | 67 | ) |
64 | ); | 68 | ); |
65 | 69 | ||
66 | $data = hook_readityourself_render_linklist($data); | 70 | $data = hook_readityourself_render_linklist($data, $conf); |
67 | $link = $data['links'][0]; | 71 | $link = $data['links'][0]; |
68 | // data shouldn't be altered | 72 | // data shouldn't be altered |
69 | $this->assertEquals($str, $data['title']); | 73 | $this->assertEquals($str, $data['title']); |
diff --git a/tests/plugins/PluginWallabagTest.php b/tests/plugins/PluginWallabagTest.php index 5d3a60e0..302ee296 100644 --- a/tests/plugins/PluginWallabagTest.php +++ b/tests/plugins/PluginWallabagTest.php | |||
@@ -4,6 +4,8 @@ | |||
4 | * PluginWallabagTest.php.php | 4 | * PluginWallabagTest.php.php |
5 | */ | 5 | */ |
6 | 6 | ||
7 | // FIXME! add an init method. | ||
8 | $conf = new ConfigManager(''); | ||
7 | require_once 'plugins/wallabag/wallabag.php'; | 9 | require_once 'plugins/wallabag/wallabag.php'; |
8 | 10 | ||
9 | /** | 11 | /** |
@@ -25,7 +27,8 @@ class PluginWallabagTest extends PHPUnit_Framework_TestCase | |||
25 | */ | 27 | */ |
26 | function testWallabagLinklist() | 28 | function testWallabagLinklist() |
27 | { | 29 | { |
28 | $GLOBALS['plugins']['WALLABAG_URL'] = 'value'; | 30 | $conf = new ConfigManager(''); |
31 | $conf->set('plugins.WALLABAG_URL', 'value'); | ||
29 | $str = 'http://randomstr.com/test'; | 32 | $str = 'http://randomstr.com/test'; |
30 | $data = array( | 33 | $data = array( |
31 | 'title' => $str, | 34 | 'title' => $str, |
@@ -36,7 +39,7 @@ class PluginWallabagTest extends PHPUnit_Framework_TestCase | |||
36 | ) | 39 | ) |
37 | ); | 40 | ); |
38 | 41 | ||
39 | $data = hook_wallabag_render_linklist($data); | 42 | $data = hook_wallabag_render_linklist($data, $conf); |
40 | $link = $data['links'][0]; | 43 | $link = $data['links'][0]; |
41 | // data shouldn't be altered | 44 | // data shouldn't be altered |
42 | $this->assertEquals($str, $data['title']); | 45 | $this->assertEquals($str, $data['title']); |
@@ -45,7 +48,6 @@ class PluginWallabagTest extends PHPUnit_Framework_TestCase | |||
45 | // plugin data | 48 | // plugin data |
46 | $this->assertEquals(1, count($link['link_plugin'])); | 49 | $this->assertEquals(1, count($link['link_plugin'])); |
47 | $this->assertNotFalse(strpos($link['link_plugin'][0], urlencode($str))); | 50 | $this->assertNotFalse(strpos($link['link_plugin'][0], urlencode($str))); |
48 | $this->assertNotFalse(strpos($link['link_plugin'][0], $GLOBALS['plugins']['WALLABAG_URL'])); | 51 | $this->assertNotFalse(strpos($link['link_plugin'][0], $conf->get('plugins.WALLABAG_URL'))); |
49 | } | 52 | } |
50 | } | 53 | } |
51 | |||
diff --git a/tests/utils/config/configInvalid.json.php b/tests/utils/config/configInvalid.json.php new file mode 100644 index 00000000..167f2168 --- /dev/null +++ b/tests/utils/config/configInvalid.json.php | |||
@@ -0,0 +1,5 @@ | |||
1 | <?php /* | ||
2 | { | ||
3 | bad: bad, | ||
4 | } | ||
5 | */ ?> \ No newline at end of file | ||
diff --git a/tests/utils/config/configJson.json.php b/tests/utils/config/configJson.json.php new file mode 100644 index 00000000..06a302e8 --- /dev/null +++ b/tests/utils/config/configJson.json.php | |||
@@ -0,0 +1,34 @@ | |||
1 | <?php /* | ||
2 | { | ||
3 | "credentials": { | ||
4 | "login":"root", | ||
5 | "hash":"hash", | ||
6 | "salt":"salt" | ||
7 | }, | ||
8 | "security": { | ||
9 | "session_protection_disabled":false | ||
10 | }, | ||
11 | "general": { | ||
12 | "timezone":"Europe\/Paris", | ||
13 | "title": "Shaarli", | ||
14 | "header_link": "?" | ||
15 | }, | ||
16 | "privacy": { | ||
17 | "default_private_links":true | ||
18 | }, | ||
19 | "redirector": { | ||
20 | "url":"lala" | ||
21 | }, | ||
22 | "config": { | ||
23 | "foo": "bar" | ||
24 | }, | ||
25 | "resource": { | ||
26 | "datastore": "tests\/utils\/config\/datastore.php", | ||
27 | "data_dir": "tests\/utils\/config" | ||
28 | }, | ||
29 | "plugins": { | ||
30 | "WALLABAG_VERSION": 1 | ||
31 | } | ||
32 | } | ||
33 | */ ?> | ||
34 | |||
diff --git a/tests/utils/config/configPhp.php b/tests/utils/config/configPhp.php new file mode 100644 index 00000000..0e034175 --- /dev/null +++ b/tests/utils/config/configPhp.php | |||
@@ -0,0 +1,14 @@ | |||
1 | <?php | ||
2 | $GLOBALS['login'] = 'root'; | ||
3 | $GLOBALS['hash'] = 'hash'; | ||
4 | $GLOBALS['salt'] = 'salt'; | ||
5 | $GLOBALS['timezone'] = 'Europe/Paris'; | ||
6 | $GLOBALS['title'] = 'title'; | ||
7 | $GLOBALS['titleLink'] = 'titleLink'; | ||
8 | $GLOBALS['redirector'] = 'lala'; | ||
9 | $GLOBALS['disablesessionprotection'] = false; | ||
10 | $GLOBALS['privateLinkByDefault'] = false; | ||
11 | $GLOBALS['config']['DATADIR'] = 'tests/Updater'; | ||
12 | $GLOBALS['config']['PAGECACHE'] = 'sandbox/pagecache'; | ||
13 | $GLOBALS['config']['DATASTORE'] = 'data/datastore.php'; | ||
14 | $GLOBALS['plugins']['WALLABAG_VERSION'] = '1'; | ||
diff --git a/tpl/configure.html b/tpl/configure.html index 77c8b7d9..ad9a2085 100644 --- a/tpl/configure.html +++ b/tpl/configure.html | |||
@@ -3,48 +3,90 @@ | |||
3 | <head>{include="includes"}</head> | 3 | <head>{include="includes"}</head> |
4 | <body onload="document.configform.title.focus();"> | 4 | <body onload="document.configform.title.focus();"> |
5 | <div id="pageheader"> | 5 | <div id="pageheader"> |
6 | {include="page.header"} | 6 | {include="page.header"} |
7 | {$timezone_js} | 7 | {$timezone_js} |
8 | <form method="POST" action="#" name="configform" id="configform"> | 8 | <form method="POST" action="#" name="configform" id="configform"> |
9 | <input type="hidden" name="token" value="{$token}"> | 9 | <input type="hidden" name="token" value="{$token}"> |
10 | <table id="configuration_table"> | 10 | <table id="configuration_table"> |
11 | 11 | ||
12 | <tr><td><b>Page title:</b></td><td><input type="text" name="title" id="title" size="50" value="{$title}"></td></tr> | 12 | <tr> |
13 | <td><b>Page title:</b></td> | ||
14 | <td><input type="text" name="title" id="title" size="50" value="{$title}"></td> | ||
15 | </tr> | ||
13 | 16 | ||
14 | <tr><td><b>Title link:</b></td><td><input type="text" name="titleLink" id="titleLink" size="50" value="{$titleLink}"><br/><label for="titleLink">(default value is: ?)</label></td></tr> | 17 | <tr> |
15 | <tr><td><b>Timezone:</b></td><td>{$timezone_form}</td></tr> | 18 | <td><b>Title link:</b></td> |
19 | <td><input type="text" name="titleLink" id="titleLink" size="50" value="{$titleLink}"><br/><label | ||
20 | for="titleLink">(default value is: ?)</label></td> | ||
21 | </tr> | ||
22 | <tr> | ||
23 | <td><b>Timezone:</b></td> | ||
24 | <td>{$timezone_form}</td> | ||
25 | </tr> | ||
16 | 26 | ||
17 | <tr><td><b>Redirector</b></td><td><input type="text" name="redirector" id="redirector" size="50" value="{$redirector}"><br>(e.g. <i>http://anonym.to/?</i> will mask the HTTP_REFERER)</td></tr> | 27 | <tr> |
28 | <td><b>Redirector</b></td> | ||
29 | <td> | ||
30 | <input type="text" name="redirector" id="redirector" size="50" value="{$redirector}"><br> | ||
31 | (e.g. <i>http://anonym.to/?</i> will mask the HTTP_REFERER) | ||
32 | </td> | ||
33 | </tr> | ||
18 | 34 | ||
19 | <tr><td><b>Security:</b></td><td><input type="checkbox" name="disablesessionprotection" id="disablesessionprotection" {if="!empty($GLOBALS['disablesessionprotection'])"}checked{/if}><label for="disablesessionprotection"> Disable session cookie hijacking protection (Check this if you get disconnected often or if your IP address changes often.)</label></td></tr> | 35 | <tr> |
36 | <td><b>Security:</b></td> | ||
37 | <td> | ||
38 | <input type="checkbox" name="disablesessionprotection" id="disablesessionprotection" | ||
39 | {if="$private_links_default"}checked{/if}> | ||
40 | <label | ||
41 | for="disablesessionprotection"> Disable session cookie hijacking protection (Check this if you get | ||
42 | disconnected often or if your IP address changes often.)</label> | ||
43 | </td> | ||
44 | </tr> | ||
20 | 45 | ||
21 | <tr><td valign="top"><b>New link:</b></td><td> | 46 | <tr> |
22 | <input type="checkbox" name="privateLinkByDefault" id="privateLinkByDefault" {if="!empty($GLOBALS['privateLinkByDefault'])"}checked{/if}/><label for="privateLinkByDefault"> All new links are private by default</label></td> | 47 | <td valign="top"><b>New link:</b></td> |
23 | </tr> | 48 | <td> |
24 | <tr> | 49 | <input type="checkbox" name="privateLinkByDefault" id="privateLinkByDefault" |
25 | <td valign="top"><b>RSS direct links</b></td> | 50 | {if="$private_links_default"}checked{/if}/> |
26 | <td> | 51 | <label for="privateLinkByDefault"> |
27 | <input type="checkbox" name="enableRssPermalinks" id="enableRssPermalinks" {if="!empty($GLOBALS['config']['ENABLE_RSS_PERMALINKS'])"}checked{/if}/> | 52 | All new links are private by default |
28 | <label for="enableRssPermalinks"> | 53 | </label> |
29 | Disable it to use permalinks in RSS feed instead of direct links to your shaared links. Currently <b>{if="$GLOBALS['config']['ENABLE_RSS_PERMALINKS']"}enabled{else}disabled{/if}.</b> | 54 | </td> |
30 | </label> | 55 | </tr> |
31 | </td> | 56 | <tr> |
32 | </tr> | 57 | <td valign="top"><b>RSS direct links</b></td> |
33 | <tr> | 58 | <td> |
34 | <td valign="top"><b>Hide public links</b></td> | 59 | <input type="checkbox" name="enableRssPermalinks" id="enableRssPermalinks" |
35 | <td> | 60 | {if="$enable_rss_permalinks"}checked{/if}/> |
36 | <input type="checkbox" name="hidePublicLinks" id="hidePublicLinks" {if="!empty($GLOBALS['config']['HIDE_PUBLIC_LINKS'])"}checked{/if}/><label for="hidePublicLinks"> | 61 | <label for="enableRssPermalinks"> |
37 | Do not show any links if the user is not logged in.</label> | 62 | Disable it to use permalinks in RSS feed instead of direct links to your shaared links. Currently <b> |
38 | </td> | 63 | {if="$enable_rss_permalinks"}enabled{else}disabled{/if}.</b> |
39 | </tr> | 64 | </label> |
40 | <tr><td valign="top"><b>Update:</b></td><td> | 65 | </td> |
41 | <input type="checkbox" name="updateCheck" id="updateCheck" {if="!empty($GLOBALS['config']['ENABLE_UPDATECHECK'])"}checked{/if}/> | 66 | </tr> |
42 | <label for="updateCheck"> Notify me when a new release is ready</label></td> | 67 | <tr> |
43 | </tr> | 68 | <td valign="top"><b>Hide public links</b></td> |
69 | <td> | ||
70 | <input type="checkbox" name="hidePublicLinks" id="hidePublicLinks" | ||
71 | {if="$hide_public_links"}checked{/if}/> | ||
72 | <label for="hidePublicLinks"> Do not show any links if the user is not logged in.</label> | ||
73 | </td> | ||
74 | </tr> | ||
75 | <tr> | ||
76 | <td valign="top"><b>Update:</b></td> | ||
77 | <td> | ||
78 | <input type="checkbox" name="updateCheck" id="updateCheck" | ||
79 | {if="$enable_update_check"}checked{/if}/> | ||
80 | <label for="updateCheck"> Notify me when a new release is ready</label> | ||
81 | </td> | ||
82 | </tr> | ||
44 | 83 | ||
45 | <tr><td></td><td class="right"><input type="submit" name="Save" value="Save config" class="bigbutton"></td></tr> | 84 | <tr> |
46 | </table> | 85 | <td></td> |
47 | </form> | 86 | <td class="right"><input type="submit" name="Save" value="Save config" class="bigbutton"></td> |
87 | </tr> | ||
88 | </table> | ||
89 | </form> | ||
48 | </div> | 90 | </div> |
49 | {include="page.footer"} | 91 | {include="page.footer"} |
50 | </body> | 92 | </body> |
diff --git a/tpl/daily.html b/tpl/daily.html index 063dc89a..dde1f376 100644 --- a/tpl/daily.html +++ b/tpl/daily.html | |||
@@ -53,7 +53,7 @@ | |||
53 | <img src="../images/squiggle2.png" width="25" height="26" title="permalink" alt="permalink"> | 53 | <img src="../images/squiggle2.png" width="25" height="26" title="permalink" alt="permalink"> |
54 | </a> | 54 | </a> |
55 | </div> | 55 | </div> |
56 | {if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"} | 56 | {if="!$hide_timestamps || isLoggedIn()"} |
57 | <div class="dailyEntryLinkdate"> | 57 | <div class="dailyEntryLinkdate"> |
58 | <a href="?{$link.linkdate|smallHash}">{function="strftime('%c', $link.timestamp)"}</a> | 58 | <a href="?{$link.linkdate|smallHash}">{function="strftime('%c', $link.timestamp)"}</a> |
59 | </div> | 59 | </div> |
diff --git a/tpl/dailyrss.html b/tpl/dailyrss.html index 4133ca3e..b14a3859 100644 --- a/tpl/dailyrss.html +++ b/tpl/dailyrss.html | |||
@@ -6,7 +6,7 @@ | |||
6 | <description><![CDATA[ | 6 | <description><![CDATA[ |
7 | {loop="links"} | 7 | {loop="links"} |
8 | <h3><a href="{$value.url}">{$value.title}</a></h3> | 8 | <h3><a href="{$value.url}">{$value.title}</a></h3> |
9 | <small>{if="!$GLOBALS['config']['HIDE_TIMESTAMPS']"}{function="strftime('%c', $value.timestamp)"} - {/if}{if="$value.tags"}{$value.tags}{/if}<br> | 9 | <small>{if="!$hide_timestamps"}{function="strftime('%c', $value.timestamp)"} - {/if}{if="$value.tags"}{$value.tags}{/if}<br> |
10 | {$value.url}</small><br> | 10 | {$value.url}</small><br> |
11 | {if="$value.thumbnail"}{$value.thumbnail}{/if}<br> | 11 | {if="$value.thumbnail"}{$value.thumbnail}{/if}<br> |
12 | {if="$value.description"}{$value.formatedDescription}{/if} | 12 | {if="$value.description"}{$value.formatedDescription}{/if} |
diff --git a/tpl/editlink.html b/tpl/editlink.html index 14a2e6c8..441b5302 100644 --- a/tpl/editlink.html +++ b/tpl/editlink.html | |||
@@ -25,7 +25,7 @@ | |||
25 | {$value} | 25 | {$value} |
26 | {/loop} | 26 | {/loop} |
27 | 27 | ||
28 | {if="($link_is_new && $GLOBALS['privateLinkByDefault']==true) || $link.private == true"} | 28 | {if="($link_is_new && $default_private_links) || $link.private == true"} |
29 | <input type="checkbox" checked="checked" name="lf_private" id="lf_private"> | 29 | <input type="checkbox" checked="checked" name="lf_private" id="lf_private"> |
30 | <label for="lf_private"><i>Private</i></label><br> | 30 | <label for="lf_private"><i>Private</i></label><br> |
31 | {else} | 31 | {else} |
@@ -43,12 +43,10 @@ | |||
43 | {if="$source !== 'firefoxsocialapi'"} | 43 | {if="$source !== 'firefoxsocialapi'"} |
44 | {include="page.footer"} | 44 | {include="page.footer"} |
45 | {/if} | 45 | {/if} |
46 | {if="($GLOBALS['config']['OPEN_SHAARLI'] || isLoggedIn())"} | ||
47 | <script src="inc/awesomplete.min.js#"></script> | 46 | <script src="inc/awesomplete.min.js#"></script> |
48 | <script src="inc/awesomplete-multiple-tags.js#"></script> | 47 | <script src="inc/awesomplete-multiple-tags.js#"></script> |
49 | <script> | 48 | <script> |
50 | awesompleteUniqueTag('#lf_tags'); | 49 | awesompleteUniqueTag('#lf_tags'); |
51 | </script> | 50 | </script> |
52 | {/if} | ||
53 | </body> | 51 | </body> |
54 | </html> | 52 | </html> |
diff --git a/tpl/linklist.html b/tpl/linklist.html index c0d42006..2316f145 100644 --- a/tpl/linklist.html +++ b/tpl/linklist.html | |||
@@ -88,7 +88,7 @@ | |||
88 | </span> | 88 | </span> |
89 | <br> | 89 | <br> |
90 | {if="$value.description"}<div class="linkdescription">{$value.description}</div>{/if} | 90 | {if="$value.description"}<div class="linkdescription">{$value.description}</div>{/if} |
91 | {if="!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()"} | 91 | {if="!$hide_timestamps || isLoggedIn()"} |
92 | <span class="linkdate" title="Permalink"><a href="?{$value.linkdate|smallHash}">{function="strftime('%c', $value.timestamp)"} - permalink</a> - </span> | 92 | <span class="linkdate" title="Permalink"><a href="?{$value.linkdate|smallHash}">{function="strftime('%c', $value.timestamp)"} - permalink</a> - </span> |
93 | {else} | 93 | {else} |
94 | <span class="linkdate" title="Short link here"><a href="?{$value.shorturl}">permalink</a> - </span> | 94 | <span class="linkdate" title="Short link here"><a href="?{$value.shorturl}">permalink</a> - </span> |
diff --git a/tpl/page.header.html b/tpl/page.header.html index 3a09ecd9..0012c689 100644 --- a/tpl/page.header.html +++ b/tpl/page.header.html | |||
@@ -21,14 +21,14 @@ | |||
21 | <li><a href="?do=logout">Logout</a></li> | 21 | <li><a href="?do=logout">Logout</a></li> |
22 | <li><a href="?do=tools">Tools</a></li> | 22 | <li><a href="?do=tools">Tools</a></li> |
23 | <li><a href="?do=addlink">Add link</a></li> | 23 | <li><a href="?do=addlink">Add link</a></li> |
24 | {elseif="$GLOBALS['config']['OPEN_SHAARLI']"} | 24 | {elseif="$openshaarli"} |
25 | <li><a href="?do=tools">Tools</a></li> | 25 | <li><a href="?do=tools">Tools</a></li> |
26 | <li><a href="?do=addlink">Add link</a></li> | 26 | <li><a href="?do=addlink">Add link</a></li> |
27 | {else} | 27 | {else} |
28 | <li><a href="?do=login">Login</a></li> | 28 | <li><a href="?do=login">Login</a></li> |
29 | {/if} | 29 | {/if} |
30 | <li><a href="{$feedurl}?do=rss{$searchcrits}" class="nomobile">RSS Feed</a></li> | 30 | <li><a href="{$feedurl}?do=rss{$searchcrits}" class="nomobile">RSS Feed</a></li> |
31 | {if="$GLOBALS['config']['SHOW_ATOM']"} | 31 | {if="$showatom"} |
32 | <li><a href="{$feedurl}?do=atom{$searchcrits}" class="nomobile">ATOM Feed</a></li> | 32 | <li><a href="{$feedurl}?do=atom{$searchcrits}" class="nomobile">ATOM Feed</a></li> |
33 | {/if} | 33 | {/if} |
34 | <li><a href="?do=tagcloud">Tag cloud</a></li> | 34 | <li><a href="?do=tagcloud">Tag cloud</a></li> |
diff --git a/tpl/tools.html b/tpl/tools.html index 78b81663..9e45caad 100644 --- a/tpl/tools.html +++ b/tpl/tools.html | |||
@@ -9,7 +9,7 @@ | |||
9 | <br><br> | 9 | <br><br> |
10 | <a href="?do=pluginadmin"><b>Plugin administration</b><span>: Enable, disable and configure plugins.</span></a> | 10 | <a href="?do=pluginadmin"><b>Plugin administration</b><span>: Enable, disable and configure plugins.</span></a> |
11 | <br><br> | 11 | <br><br> |
12 | {if="!$GLOBALS['config']['OPEN_SHAARLI']"}<a href="?do=changepasswd"><b>Change password</b><span>: Change your password.</span></a> | 12 | {if="$openshaarli"}<a href="?do=changepasswd"><b>Change password</b><span>: Change your password.</span></a> |
13 | <br><br>{/if} | 13 | <br><br>{/if} |
14 | <a href="?do=changetag"><b>Rename/delete tags</b><span>: Rename or delete a tag in all links</span></a> | 14 | <a href="?do=changetag"><b>Rename/delete tags</b><span>: Rename or delete a tag in all links</span></a> |
15 | <br><br> | 15 | <br><br> |
@@ -79,7 +79,7 @@ | |||
79 | icon32URL: baseURL + "/images/favicon.ico", | 79 | icon32URL: baseURL + "/images/favicon.ico", |
80 | icon64URL: baseURL + "/images/favicon.ico", | 80 | icon64URL: baseURL + "/images/favicon.ico", |
81 | 81 | ||
82 | shareURL: baseURL + "{noparse}?post=%{url}&title=%{title}&description=%{description}&source=firefoxsocialapi{/noparse}", | 82 | shareURL: baseURL + "{noparse}?post=%{url}&title=%{title}&description=%{text}&source=firefoxsocialapi{/noparse}", |
83 | homepageURL: baseURL | 83 | homepageURL: baseURL |
84 | }; | 84 | }; |
85 | node.setAttribute("data-service", JSON.stringify(data)); | 85 | node.setAttribute("data-service", JSON.stringify(data)); |