aboutsummaryrefslogtreecommitdiffhomepage
path: root/application
diff options
context:
space:
mode:
Diffstat (limited to 'application')
-rwxr-xr-xapplication/Config.php129
-rw-r--r--application/LinkDB.php129
-rw-r--r--application/Utils.php15
3 files changed, 210 insertions, 63 deletions
diff --git a/application/Config.php b/application/Config.php
new file mode 100755
index 00000000..0b01b524
--- /dev/null
+++ b/application/Config.php
@@ -0,0 +1,129 @@
1<?php
2/**
3 * Functions related to configuration management.
4 */
5
6/**
7 * Re-write configuration file according to given array.
8 * Requires mandatory fields listed in $MANDATORY_FIELDS.
9 *
10 * @param array $config contains all configuration fields.
11 * @param bool $isLoggedIn true if user is logged in.
12 *
13 * @return void
14 *
15 * @throws MissingFieldConfigException: a mandatory field has not been provided in $config.
16 * @throws UnauthorizedConfigException: user is not authorize to change configuration.
17 * @throws Exception: an error occured while writing the new config file.
18 */
19function writeConfig($config, $isLoggedIn)
20{
21 // These fields are required in configuration.
22 $MANDATORY_FIELDS = [
23 'login', 'hash', 'salt', 'timezone', 'title', 'titleLink',
24 'redirector', 'disablesessionprotection', 'privateLinkByDefault'
25 ];
26
27 if (!isset($config['config']['CONFIG_FILE'])) {
28 throw new MissingFieldConfigException('CONFIG_FILE');
29 }
30
31 // Only logged in user can alter config.
32 if (is_file($config['config']['CONFIG_FILE']) && !$isLoggedIn) {
33 throw new UnauthorizedConfigException();
34 }
35
36 // Check that all mandatory fields are provided in $config.
37 foreach ($MANDATORY_FIELDS as $field) {
38 if (!isset($config[$field])) {
39 throw new MissingFieldConfigException($field);
40 }
41 }
42
43 $configStr = '<?php '. PHP_EOL;
44 $configStr .= '$GLOBALS[\'login\'] = '.var_export($config['login'], true).';'. PHP_EOL;
45 $configStr .= '$GLOBALS[\'hash\'] = '.var_export($config['hash'], true).';'. PHP_EOL;
46 $configStr .= '$GLOBALS[\'salt\'] = '.var_export($config['salt'], true).'; '. PHP_EOL;
47 $configStr .= '$GLOBALS[\'timezone\'] = '.var_export($config['timezone'], true).';'. PHP_EOL;
48 $configStr .= 'date_default_timezone_set('.var_export($config['timezone'], true).');'. PHP_EOL;
49 $configStr .= '$GLOBALS[\'title\'] = '.var_export($config['title'], true).';'. PHP_EOL;
50 $configStr .= '$GLOBALS[\'titleLink\'] = '.var_export($config['titleLink'], true).'; '. PHP_EOL;
51 $configStr .= '$GLOBALS[\'redirector\'] = '.var_export($config['redirector'], true).'; '. PHP_EOL;
52 $configStr .= '$GLOBALS[\'disablesessionprotection\'] = '.var_export($config['disablesessionprotection'], true).'; '. PHP_EOL;
53 $configStr .= '$GLOBALS[\'privateLinkByDefault\'] = '.var_export($config['privateLinkByDefault'], true).'; '. PHP_EOL;
54
55 // Store all $config['config']
56 foreach ($config['config'] as $key => $value) {
57 $configStr .= '$GLOBALS[\'config\'][\''. $key .'\'] = '.var_export($config['config'][$key], true).';'. PHP_EOL;
58 }
59 $configStr .= '?>';
60
61 if (!file_put_contents($config['config']['CONFIG_FILE'], $configStr)
62 || strcmp(file_get_contents($config['config']['CONFIG_FILE']), $configStr) != 0
63 ) {
64 throw new Exception(
65 'Shaarli could not create the config file.
66 Please make sure Shaarli has the right to write in the folder is it installed in.'
67 );
68 }
69}
70
71/**
72 * Milestone 0.9 - shaarli/Shaarli#41: options.php is not supported anymore.
73 * ==> if user is loggedIn, merge its content with config.php, then delete options.php.
74 *
75 * @param array $config contains all configuration fields.
76 * @param bool $isLoggedIn true if user is logged in.
77 *
78 * @return void
79 */
80function mergeDeprecatedConfig($config, $isLoggedIn)
81{
82 $config_file = $config['config']['CONFIG_FILE'];
83
84 if (is_file($config['config']['DATADIR'].'/options.php') && $isLoggedIn) {
85 include $config['config']['DATADIR'].'/options.php';
86
87 // Load GLOBALS into config
88 foreach ($GLOBALS as $key => $value) {
89 $config[$key] = $value;
90 }
91 $config['config']['CONFIG_FILE'] = $config_file;
92 writeConfig($config, $isLoggedIn);
93
94 unlink($config['config']['DATADIR'].'/options.php');
95 }
96}
97
98/**
99 * Exception used if a mandatory field is missing in given configuration.
100 */
101class MissingFieldConfigException extends Exception
102{
103 public $field;
104
105 /**
106 * Construct exception.
107 *
108 * @param string $field field name missing.
109 */
110 public function __construct($field)
111 {
112 $this->field = $field;
113 $this->message = 'Configuration value is required for '. $this->field;
114 }
115}
116
117/**
118 * Exception used if an unauthorized attempt to edit configuration has been made.
119 */
120class UnauthorizedConfigException extends Exception
121{
122 /**
123 * Construct exception.
124 */
125 public function __construct()
126 {
127 $this->message = 'You are not authorized to alter config.';
128 }
129} \ No newline at end of file
diff --git a/application/LinkDB.php b/application/LinkDB.php
index a673b086..1e16fef1 100644
--- a/application/LinkDB.php
+++ b/application/LinkDB.php
@@ -28,7 +28,7 @@
28class LinkDB implements Iterator, Countable, ArrayAccess 28class LinkDB implements Iterator, Countable, ArrayAccess
29{ 29{
30 // Links are stored as a PHP serialized string 30 // Links are stored as a PHP serialized string
31 private $datastore; 31 private $_datastore;
32 32
33 // Datastore PHP prefix 33 // Datastore PHP prefix
34 protected static $phpPrefix = '<?php /* '; 34 protected static $phpPrefix = '<?php /* ';
@@ -39,23 +39,23 @@ class LinkDB implements Iterator, Countable, ArrayAccess
39 // List of links (associative array) 39 // List of links (associative array)
40 // - key: link date (e.g. "20110823_124546"), 40 // - key: link date (e.g. "20110823_124546"),
41 // - value: associative array (keys: title, description...) 41 // - value: associative array (keys: title, description...)
42 private $links; 42 private $_links;
43 43
44 // List of all recorded URLs (key=url, value=linkdate) 44 // List of all recorded URLs (key=url, value=linkdate)
45 // for fast reserve search (url-->linkdate) 45 // for fast reserve search (url-->linkdate)
46 private $urls; 46 private $_urls;
47 47
48 // List of linkdate keys (for the Iterator interface implementation) 48 // List of linkdate keys (for the Iterator interface implementation)
49 private $keys; 49 private $_keys;
50 50
51 // Position in the $this->keys array (for the Iterator interface) 51 // Position in the $this->_keys array (for the Iterator interface)
52 private $position; 52 private $_position;
53 53
54 // Is the user logged in? (used to filter private links) 54 // Is the user logged in? (used to filter private links)
55 private $loggedIn; 55 private $_loggedIn;
56 56
57 // Hide public links 57 // Hide public links
58 private $hidePublicLinks; 58 private $_hidePublicLinks;
59 59
60 /** 60 /**
61 * Creates a new LinkDB 61 * Creates a new LinkDB
@@ -66,11 +66,11 @@ class LinkDB implements Iterator, Countable, ArrayAccess
66 */ 66 */
67 function __construct($datastore, $isLoggedIn, $hidePublicLinks) 67 function __construct($datastore, $isLoggedIn, $hidePublicLinks)
68 { 68 {
69 $this->datastore = $datastore; 69 $this->_datastore = $datastore;
70 $this->loggedIn = $isLoggedIn; 70 $this->_loggedIn = $isLoggedIn;
71 $this->hidePublicLinks = $hidePublicLinks; 71 $this->_hidePublicLinks = $hidePublicLinks;
72 $this->checkDB(); 72 $this->_checkDB();
73 $this->readdb(); 73 $this->_readDB();
74 } 74 }
75 75
76 /** 76 /**
@@ -78,7 +78,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess
78 */ 78 */
79 public function count() 79 public function count()
80 { 80 {
81 return count($this->links); 81 return count($this->_links);
82 } 82 }
83 83
84 /** 84 /**
@@ -87,7 +87,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess
87 public function offsetSet($offset, $value) 87 public function offsetSet($offset, $value)
88 { 88 {
89 // TODO: use exceptions instead of "die" 89 // TODO: use exceptions instead of "die"
90 if (!$this->loggedIn) { 90 if (!$this->_loggedIn) {
91 die('You are not authorized to add a link.'); 91 die('You are not authorized to add a link.');
92 } 92 }
93 if (empty($value['linkdate']) || empty($value['url'])) { 93 if (empty($value['linkdate']) || empty($value['url'])) {
@@ -96,8 +96,8 @@ class LinkDB implements Iterator, Countable, ArrayAccess
96 if (empty($offset)) { 96 if (empty($offset)) {
97 die('You must specify a key.'); 97 die('You must specify a key.');
98 } 98 }
99 $this->links[$offset] = $value; 99 $this->_links[$offset] = $value;
100 $this->urls[$value['url']]=$offset; 100 $this->_urls[$value['url']]=$offset;
101 } 101 }
102 102
103 /** 103 /**
@@ -105,7 +105,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess
105 */ 105 */
106 public function offsetExists($offset) 106 public function offsetExists($offset)
107 { 107 {
108 return array_key_exists($offset, $this->links); 108 return array_key_exists($offset, $this->_links);
109 } 109 }
110 110
111 /** 111 /**
@@ -113,13 +113,13 @@ class LinkDB implements Iterator, Countable, ArrayAccess
113 */ 113 */
114 public function offsetUnset($offset) 114 public function offsetUnset($offset)
115 { 115 {
116 if (!$this->loggedIn) { 116 if (!$this->_loggedIn) {
117 // TODO: raise an exception 117 // TODO: raise an exception
118 die('You are not authorized to delete a link.'); 118 die('You are not authorized to delete a link.');
119 } 119 }
120 $url = $this->links[$offset]['url']; 120 $url = $this->_links[$offset]['url'];
121 unset($this->urls[$url]); 121 unset($this->_urls[$url]);
122 unset($this->links[$offset]); 122 unset($this->_links[$offset]);
123 } 123 }
124 124
125 /** 125 /**
@@ -127,7 +127,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess
127 */ 127 */
128 public function offsetGet($offset) 128 public function offsetGet($offset)
129 { 129 {
130 return isset($this->links[$offset]) ? $this->links[$offset] : null; 130 return isset($this->_links[$offset]) ? $this->_links[$offset] : null;
131 } 131 }
132 132
133 /** 133 /**
@@ -135,7 +135,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess
135 */ 135 */
136 function current() 136 function current()
137 { 137 {
138 return $this->links[$this->keys[$this->position]]; 138 return $this->_links[$this->_keys[$this->_position]];
139 } 139 }
140 140
141 /** 141 /**
@@ -143,7 +143,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess
143 */ 143 */
144 function key() 144 function key()
145 { 145 {
146 return $this->keys[$this->position]; 146 return $this->_keys[$this->_position];
147 } 147 }
148 148
149 /** 149 /**
@@ -151,7 +151,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess
151 */ 151 */
152 function next() 152 function next()
153 { 153 {
154 ++$this->position; 154 ++$this->_position;
155 } 155 }
156 156
157 /** 157 /**
@@ -161,9 +161,9 @@ class LinkDB implements Iterator, Countable, ArrayAccess
161 */ 161 */
162 function rewind() 162 function rewind()
163 { 163 {
164 $this->keys = array_keys($this->links); 164 $this->_keys = array_keys($this->_links);
165 rsort($this->keys); 165 rsort($this->_keys);
166 $this->position = 0; 166 $this->_position = 0;
167 } 167 }
168 168
169 /** 169 /**
@@ -171,7 +171,7 @@ class LinkDB implements Iterator, Countable, ArrayAccess
171 */ 171 */
172 function valid() 172 function valid()
173 { 173 {
174 return isset($this->keys[$this->position]); 174 return isset($this->_keys[$this->_position]);
175 } 175 }
176 176
177 /** 177 /**
@@ -179,14 +179,14 @@ class LinkDB implements Iterator, Countable, ArrayAccess
179 * 179 *
180 * If no DB file is found, creates a dummy DB. 180 * If no DB file is found, creates a dummy DB.
181 */ 181 */
182 private function checkDB() 182 private function _checkDB()
183 { 183 {
184 if (file_exists($this->datastore)) { 184 if (file_exists($this->_datastore)) {
185 return; 185 return;
186 } 186 }
187 187
188 // Create a dummy database for example 188 // Create a dummy database for example
189 $this->links = array(); 189 $this->_links = array();
190 $link = array( 190 $link = array(
191 'title'=>' Shaarli: the personal, minimalist, super-fast, no-database delicious clone', 191 'title'=>' Shaarli: the personal, minimalist, super-fast, no-database delicious clone',
192 'url'=>'https://github.com/shaarli/Shaarli/wiki', 192 'url'=>'https://github.com/shaarli/Shaarli/wiki',
@@ -199,7 +199,7 @@ You use the community supported version of the original Shaarli project, by Seba
199 'linkdate'=> date('Ymd_His'), 199 'linkdate'=> date('Ymd_His'),
200 'tags'=>'opensource software' 200 'tags'=>'opensource software'
201 ); 201 );
202 $this->links[$link['linkdate']] = $link; 202 $this->_links[$link['linkdate']] = $link;
203 203
204 $link = array( 204 $link = array(
205 'title'=>'My secret stuff... - Pastebin.com', 205 'title'=>'My secret stuff... - Pastebin.com',
@@ -209,60 +209,60 @@ You use the community supported version of the original Shaarli project, by Seba
209 'linkdate'=> date('Ymd_His', strtotime('-1 minute')), 209 'linkdate'=> date('Ymd_His', strtotime('-1 minute')),
210 'tags'=>'secretstuff' 210 'tags'=>'secretstuff'
211 ); 211 );
212 $this->links[$link['linkdate']] = $link; 212 $this->_links[$link['linkdate']] = $link;
213 213
214 // Write database to disk 214 // Write database to disk
215 // TODO: raise an exception if the file is not write-able 215 // TODO: raise an exception if the file is not write-able
216 file_put_contents( 216 file_put_contents(
217 $this->datastore, 217 $this->_datastore,
218 self::$phpPrefix.base64_encode(gzdeflate(serialize($this->links))).self::$phpSuffix 218 self::$phpPrefix.base64_encode(gzdeflate(serialize($this->_links))).self::$phpSuffix
219 ); 219 );
220 } 220 }
221 221
222 /** 222 /**
223 * Reads database from disk to memory 223 * Reads database from disk to memory
224 */ 224 */
225 private function readdb() 225 private function _readDB()
226 { 226 {
227 227
228 // Public links are hidden and user not logged in => nothing to show 228 // Public links are hidden and user not logged in => nothing to show
229 if ($this->hidePublicLinks && !$this->loggedIn) { 229 if ($this->_hidePublicLinks && !$this->_loggedIn) {
230 $this->links = array(); 230 $this->_links = array();
231 return; 231 return;
232 } 232 }
233 233
234 // Read data 234 // Read data
235 // Note that gzinflate is faster than gzuncompress. 235 // Note that gzinflate is faster than gzuncompress.
236 // See: http://www.php.net/manual/en/function.gzdeflate.php#96439 236 // See: http://www.php.net/manual/en/function.gzdeflate.php#96439
237 $this->links = array(); 237 $this->_links = array();
238 238
239 if (file_exists($this->datastore)) { 239 if (file_exists($this->_datastore)) {
240 $this->links = unserialize(gzinflate(base64_decode( 240 $this->_links = unserialize(gzinflate(base64_decode(
241 substr(file_get_contents($this->datastore), 241 substr(file_get_contents($this->_datastore),
242 strlen(self::$phpPrefix), -strlen(self::$phpSuffix))))); 242 strlen(self::$phpPrefix), -strlen(self::$phpSuffix)))));
243 } 243 }
244 244
245 // If user is not logged in, filter private links. 245 // If user is not logged in, filter private links.
246 if (!$this->loggedIn) { 246 if (!$this->_loggedIn) {
247 $toremove = array(); 247 $toremove = array();
248 foreach ($this->links as $link) { 248 foreach ($this->_links as $link) {
249 if ($link['private'] != 0) { 249 if ($link['private'] != 0) {
250 $toremove[] = $link['linkdate']; 250 $toremove[] = $link['linkdate'];
251 } 251 }
252 } 252 }
253 foreach ($toremove as $linkdate) { 253 foreach ($toremove as $linkdate) {
254 unset($this->links[$linkdate]); 254 unset($this->_links[$linkdate]);
255 } 255 }
256 } 256 }
257 257
258 // Keep the list of the mapping URLs-->linkdate up-to-date. 258 // Keep the list of the mapping URLs-->linkdate up-to-date.
259 $this->urls = array(); 259 $this->_urls = array();
260 foreach ($this->links as $link) { 260 foreach ($this->_links as $link) {
261 $this->urls[$link['url']] = $link['linkdate']; 261 $this->_urls[$link['url']] = $link['linkdate'];
262 } 262 }
263 263
264 // Escape links data 264 // Escape links data
265 foreach($this->links as &$link) { 265 foreach($this->_links as &$link) {
266 sanitizeLink($link); 266 sanitizeLink($link);
267 } 267 }
268 } 268 }
@@ -272,13 +272,13 @@ You use the community supported version of the original Shaarli project, by Seba
272 */ 272 */
273 public function savedb() 273 public function savedb()
274 { 274 {
275 if (!$this->loggedIn) { 275 if (!$this->_loggedIn) {
276 // TODO: raise an Exception instead 276 // TODO: raise an Exception instead
277 die('You are not authorized to change the database.'); 277 die('You are not authorized to change the database.');
278 } 278 }
279 file_put_contents( 279 file_put_contents(
280 $this->datastore, 280 $this->_datastore,
281 self::$phpPrefix.base64_encode(gzdeflate(serialize($this->links))).self::$phpSuffix 281 self::$phpPrefix.base64_encode(gzdeflate(serialize($this->_links))).self::$phpSuffix
282 ); 282 );
283 invalidateCaches(); 283 invalidateCaches();
284 } 284 }
@@ -288,8 +288,8 @@ You use the community supported version of the original Shaarli project, by Seba
288 */ 288 */
289 public function getLinkFromUrl($url) 289 public function getLinkFromUrl($url)
290 { 290 {
291 if (isset($this->urls[$url])) { 291 if (isset($this->_urls[$url])) {
292 return $this->links[$this->urls[$url]]; 292 return $this->_links[$this->_urls[$url]];
293 } 293 }
294 return false; 294 return false;
295 } 295 }
@@ -316,7 +316,7 @@ You use the community supported version of the original Shaarli project, by Seba
316 $search = mb_convert_case($searchterms, MB_CASE_LOWER, 'UTF-8'); 316 $search = mb_convert_case($searchterms, MB_CASE_LOWER, 'UTF-8');
317 $keys = array('title', 'description', 'url', 'tags'); 317 $keys = array('title', 'description', 'url', 'tags');
318 318
319 foreach ($this->links as $link) { 319 foreach ($this->_links as $link) {
320 $found = false; 320 $found = false;
321 321
322 foreach ($keys as $key) { 322 foreach ($keys as $key) {
@@ -352,7 +352,7 @@ You use the community supported version of the original Shaarli project, by Seba
352 $searchtags = explode(' ', $t); 352 $searchtags = explode(' ', $t);
353 $filtered = array(); 353 $filtered = array();
354 354
355 foreach ($this->links as $l) { 355 foreach ($this->_links as $l) {
356 $linktags = explode( 356 $linktags = explode(
357 ' ', 357 ' ',
358 ($casesensitive ? $l['tags']:mb_convert_case($l['tags'], MB_CASE_LOWER, 'UTF-8')) 358 ($casesensitive ? $l['tags']:mb_convert_case($l['tags'], MB_CASE_LOWER, 'UTF-8'))
@@ -375,9 +375,12 @@ You use the community supported version of the original Shaarli project, by Seba
375 */ 375 */
376 public function filterDay($day) 376 public function filterDay($day)
377 { 377 {
378 // TODO: check input format 378 if (! checkDateFormat('Ymd', $day)) {
379 throw new Exception('Invalid date format');
380 }
381
379 $filtered = array(); 382 $filtered = array();
380 foreach ($this->links as $l) { 383 foreach ($this->_links as $l) {
381 if (startsWith($l['linkdate'], $day)) { 384 if (startsWith($l['linkdate'], $day)) {
382 $filtered[$l['linkdate']] = $l; 385 $filtered[$l['linkdate']] = $l;
383 } 386 }
@@ -392,7 +395,7 @@ You use the community supported version of the original Shaarli project, by Seba
392 public function filterSmallHash($smallHash) 395 public function filterSmallHash($smallHash)
393 { 396 {
394 $filtered = array(); 397 $filtered = array();
395 foreach ($this->links as $l) { 398 foreach ($this->_links as $l) {
396 if ($smallHash == smallHash($l['linkdate'])) { 399 if ($smallHash == smallHash($l['linkdate'])) {
397 // Yes, this is ugly and slow 400 // Yes, this is ugly and slow
398 $filtered[$l['linkdate']] = $l; 401 $filtered[$l['linkdate']] = $l;
@@ -409,7 +412,7 @@ You use the community supported version of the original Shaarli project, by Seba
409 public function allTags() 412 public function allTags()
410 { 413 {
411 $tags = array(); 414 $tags = array();
412 foreach ($this->links as $link) { 415 foreach ($this->_links as $link) {
413 foreach (explode(' ', $link['tags']) as $tag) { 416 foreach (explode(' ', $link['tags']) as $tag) {
414 if (!empty($tag)) { 417 if (!empty($tag)) {
415 $tags[$tag] = (empty($tags[$tag]) ? 1 : $tags[$tag] + 1); 418 $tags[$tag] = (empty($tags[$tag]) ? 1 : $tags[$tag] + 1);
@@ -428,7 +431,7 @@ You use the community supported version of the original Shaarli project, by Seba
428 public function days() 431 public function days()
429 { 432 {
430 $linkDays = array(); 433 $linkDays = array();
431 foreach (array_keys($this->links) as $day) { 434 foreach (array_keys($this->_links) as $day) {
432 $linkDays[substr($day, 0, 8)] = 0; 435 $linkDays[substr($day, 0, 8)] = 0;
433 } 436 }
434 $linkDays = array_keys($linkDays); 437 $linkDays = array_keys($linkDays);
diff --git a/application/Utils.php b/application/Utils.php
index 82220bfc..a1e97b35 100644
--- a/application/Utils.php
+++ b/application/Utils.php
@@ -69,4 +69,19 @@ function sanitizeLink(&$link)
69 $link['description'] = escape($link['description']); 69 $link['description'] = escape($link['description']);
70 $link['tags'] = escape($link['tags']); 70 $link['tags'] = escape($link['tags']);
71} 71}
72
73/**
74 * Checks if a string represents a valid date
75 *
76 * @param string a string-formatted date
77 * @param format the expected DateTime format of the string
78 * @return whether the string is a valid date
79 * @see http://php.net/manual/en/class.datetime.php
80 * @see http://php.net/manual/en/datetime.createfromformat.php
81 */
82function checkDateFormat($format, $string)
83{
84 $date = DateTime::createFromFormat($format, $string);
85 return $date && $date->format($string) == $string;
86}
72?> 87?>