diff options
Diffstat (limited to 'inc/poche')
-rwxr-xr-x | inc/poche/Database.class.php | 182 | ||||
-rwxr-xr-x | inc/poche/Poche.class.php | 947 | ||||
-rwxr-xr-x[-rw-r--r--] | inc/poche/Tools.class.php | 93 | ||||
-rwxr-xr-x | inc/poche/config.inc.default.php | 68 | ||||
-rwxr-xr-x | inc/poche/config.inc.php.new | 63 | ||||
-rwxr-xr-x[-rw-r--r--] | inc/poche/global.inc.php | 8 | ||||
-rw-r--r-- | inc/poche/pochePictures.php | 58 |
7 files changed, 874 insertions, 545 deletions
diff --git a/inc/poche/Database.class.php b/inc/poche/Database.class.php index c998fe14..11cccb72 100755 --- a/inc/poche/Database.class.php +++ b/inc/poche/Database.class.php | |||
@@ -18,7 +18,7 @@ class Database { | |||
18 | 'default' => 'ORDER BY entries.id' | 18 | 'default' => 'ORDER BY entries.id' |
19 | ); | 19 | ); |
20 | 20 | ||
21 | function __construct() | 21 | function __construct() |
22 | { | 22 | { |
23 | switch (STORAGE) { | 23 | switch (STORAGE) { |
24 | case 'sqlite': | 24 | case 'sqlite': |
@@ -27,12 +27,14 @@ class Database { | |||
27 | break; | 27 | break; |
28 | case 'mysql': | 28 | case 'mysql': |
29 | $db_path = 'mysql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB; | 29 | $db_path = 'mysql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB; |
30 | $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD); | 30 | $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD); |
31 | break; | 31 | break; |
32 | case 'postgres': | 32 | case 'postgres': |
33 | $db_path = 'pgsql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB; | 33 | $db_path = 'pgsql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB; |
34 | $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD); | 34 | $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD); |
35 | break; | 35 | break; |
36 | default: | ||
37 | die(STORAGE . ' is not a recognised database system !'); | ||
36 | } | 38 | } |
37 | 39 | ||
38 | $this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); | 40 | $this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
@@ -51,7 +53,7 @@ class Database { | |||
51 | } | 53 | } |
52 | $hasAdmin = count($query->fetchAll()); | 54 | $hasAdmin = count($query->fetchAll()); |
53 | 55 | ||
54 | if ($hasAdmin == 0) | 56 | if ($hasAdmin == 0) |
55 | return false; | 57 | return false; |
56 | 58 | ||
57 | return true; | 59 | return true; |
@@ -77,7 +79,7 @@ class Database { | |||
77 | } | 79 | } |
78 | else { | 80 | else { |
79 | $sql = ' | 81 | $sql = ' |
80 | CREATE TABLE tags ( | 82 | CREATE TABLE IF NOT EXISTS tags ( |
81 | id bigserial primary key, | 83 | id bigserial primary key, |
82 | value varchar(255) NOT NULL | 84 | value varchar(255) NOT NULL |
83 | ); | 85 | ); |
@@ -110,7 +112,7 @@ class Database { | |||
110 | } | 112 | } |
111 | else { | 113 | else { |
112 | $sql = ' | 114 | $sql = ' |
113 | CREATE TABLE tags_entries ( | 115 | CREATE TABLE IF NOT EXISTS tags_entries ( |
114 | id bigserial primary key, | 116 | id bigserial primary key, |
115 | entry_id integer NOT NULL, | 117 | entry_id integer NOT NULL, |
116 | tag_id integer NOT NULL | 118 | tag_id integer NOT NULL |
@@ -140,7 +142,7 @@ class Database { | |||
140 | $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)'; | 142 | $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)'; |
141 | $params = array($id_user, 'language', LANG); | 143 | $params = array($id_user, 'language', LANG); |
142 | $query = $this->executeQuery($sql, $params); | 144 | $query = $this->executeQuery($sql, $params); |
143 | 145 | ||
144 | $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)'; | 146 | $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)'; |
145 | $params = array($id_user, 'theme', DEFAULT_THEME); | 147 | $params = array($id_user, 'theme', DEFAULT_THEME); |
146 | $query = $this->executeQuery($sql, $params); | 148 | $query = $this->executeQuery($sql, $params); |
@@ -153,7 +155,7 @@ class Database { | |||
153 | $query = $this->executeQuery($sql, array($id)); | 155 | $query = $this->executeQuery($sql, array($id)); |
154 | $result = $query->fetchAll(); | 156 | $result = $query->fetchAll(); |
155 | $user_config = array(); | 157 | $user_config = array(); |
156 | 158 | ||
157 | foreach ($result as $key => $value) { | 159 | foreach ($result as $key => $value) { |
158 | $user_config[$value['name']] = $value['value']; | 160 | $user_config[$value['name']] = $value['value']; |
159 | } | 161 | } |
@@ -201,10 +203,10 @@ class Database { | |||
201 | $params_update = array($password, $userId); | 203 | $params_update = array($password, $userId); |
202 | $query = $this->executeQuery($sql_update, $params_update); | 204 | $query = $this->executeQuery($sql_update, $params_update); |
203 | } | 205 | } |
204 | 206 | ||
205 | public function updateUserConfig($userId, $key, $value) { | 207 | public function updateUserConfig($userId, $key, $value) { |
206 | $config = $this->getConfigUser($userId); | 208 | $config = $this->getConfigUser($userId); |
207 | 209 | ||
208 | if (! isset($config[$key])) { | 210 | if (! isset($config[$key])) { |
209 | $sql = "INSERT INTO users_config (value, user_id, name) VALUES (?, ?, ?)"; | 211 | $sql = "INSERT INTO users_config (value, user_id, name) VALUES (?, ?, ?)"; |
210 | } | 212 | } |
@@ -229,6 +231,73 @@ class Database { | |||
229 | return FALSE; | 231 | return FALSE; |
230 | } | 232 | } |
231 | } | 233 | } |
234 | |||
235 | public function listUsers($username=null) { | ||
236 | $sql = 'SELECT count(*) FROM users'.( $username ? ' WHERE username=?' : ''); | ||
237 | $query = $this->executeQuery($sql, ( $username ? array($username) : array())); | ||
238 | list($count) = $query->fetch(); | ||
239 | return $count; | ||
240 | } | ||
241 | |||
242 | public function getUserPassword($userID) { | ||
243 | $sql = "SELECT * FROM users WHERE id=?"; | ||
244 | $query = $this->executeQuery($sql, array($userID)); | ||
245 | $password = $query->fetchAll(); | ||
246 | return isset($password[0]['password']) ? $password[0]['password'] : null; | ||
247 | } | ||
248 | |||
249 | public function deleteUserConfig($userID) { | ||
250 | $sql_action = 'DELETE from users_config WHERE user_id=?'; | ||
251 | $params_action = array($userID); | ||
252 | $query = $this->executeQuery($sql_action, $params_action); | ||
253 | return $query; | ||
254 | } | ||
255 | |||
256 | public function deleteTagsEntriesAndEntries($userID) { | ||
257 | $entries = $this->retrieveAll($userID); | ||
258 | foreach($entries as $entryid) { | ||
259 | $tags = $this->retrieveTagsByEntry($entryid); | ||
260 | foreach($tags as $tag) { | ||
261 | $this->removeTagForEntry($entryid,$tags); | ||
262 | } | ||
263 | $this->deleteById($entryid,$userID); | ||
264 | } | ||
265 | } | ||
266 | |||
267 | public function deleteUser($userID) { | ||
268 | $sql_action = 'DELETE from users WHERE id=?'; | ||
269 | $params_action = array($userID); | ||
270 | $query = $this->executeQuery($sql_action, $params_action); | ||
271 | } | ||
272 | |||
273 | public function updateContentAndTitle($id, $title, $body, $user_id) { | ||
274 | $sql_action = 'UPDATE entries SET content = ?, title = ? WHERE id=? AND user_id=?'; | ||
275 | $params_action = array($body, $title, $id, $user_id); | ||
276 | $query = $this->executeQuery($sql_action, $params_action); | ||
277 | return $query; | ||
278 | } | ||
279 | |||
280 | public function retrieveUnfetchedEntries($user_id, $limit) { | ||
281 | |||
282 | $sql_limit = "LIMIT 0,".$limit; | ||
283 | if (STORAGE == 'postgres') { | ||
284 | $sql_limit = "LIMIT ".$limit." OFFSET 0"; | ||
285 | } | ||
286 | |||
287 | $sql = "SELECT * FROM entries WHERE (content = '' OR content IS NULL) AND title LIKE 'Untitled - Import%' AND user_id=? ORDER BY id " . $sql_limit; | ||
288 | $query = $this->executeQuery($sql, array($user_id)); | ||
289 | $entries = $query->fetchAll(); | ||
290 | |||
291 | return $entries; | ||
292 | } | ||
293 | |||
294 | public function retrieveUnfetchedEntriesCount($user_id) { | ||
295 | $sql = "SELECT count(*) FROM entries WHERE (content = '' OR content IS NULL) AND title LIKE 'Untitled - Import%' AND user_id=?"; | ||
296 | $query = $this->executeQuery($sql, array($user_id)); | ||
297 | list($count) = $query->fetch(); | ||
298 | |||
299 | return $count; | ||
300 | } | ||
232 | 301 | ||
233 | public function retrieveAll($user_id) { | 302 | public function retrieveAll($user_id) { |
234 | $sql = "SELECT * FROM entries WHERE user_id=? ORDER BY id"; | 303 | $sql = "SELECT * FROM entries WHERE user_id=? ORDER BY id"; |
@@ -294,24 +363,24 @@ class Database { | |||
294 | return $entries; | 363 | return $entries; |
295 | } | 364 | } |
296 | 365 | ||
297 | public function getEntriesByViewCount($view, $user_id, $tag_id = 0) { | 366 | public function getEntriesByViewCount($view, $user_id, $tag_id = 0) { |
298 | switch ($view) { | 367 | switch ($view) { |
299 | case 'archive': | 368 | case 'archive': |
300 | $sql = "SELECT count(*) FROM entries WHERE user_id=? AND is_read=? "; | 369 | $sql = "SELECT count(*) FROM entries WHERE user_id=? AND is_read=? "; |
301 | $params = array($user_id, 1); | 370 | $params = array($user_id, 1); |
302 | break; | 371 | break; |
303 | case 'fav' : | 372 | case 'fav' : |
304 | $sql = "SELECT count(*) FROM entries WHERE user_id=? AND is_fav=? "; | 373 | $sql = "SELECT count(*) FROM entries WHERE user_id=? AND is_fav=? "; |
305 | $params = array($user_id, 1); | 374 | $params = array($user_id, 1); |
306 | break; | 375 | break; |
307 | case 'tag' : | 376 | case 'tag' : |
308 | $sql = "SELECT count(*) FROM entries | 377 | $sql = "SELECT count(*) FROM entries |
309 | LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id | 378 | LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id |
310 | WHERE entries.user_id=? AND tags_entries.tag_id = ? "; | 379 | WHERE entries.user_id=? AND tags_entries.tag_id = ? "; |
311 | $params = array($user_id, $tag_id); | 380 | $params = array($user_id, $tag_id); |
312 | break; | 381 | break; |
313 | default: | 382 | default: |
314 | $sql = "SELECT count(*) FROM entries WHERE user_id=? AND is_read=? "; | 383 | $sql = "SELECT count(*) FROM entries WHERE user_id=? AND is_read=? "; |
315 | $params = array($user_id, 0); | 384 | $params = array($user_id, 0); |
316 | break; | 385 | break; |
317 | } | 386 | } |
@@ -319,7 +388,7 @@ class Database { | |||
319 | $query = $this->executeQuery($sql, $params); | 388 | $query = $this->executeQuery($sql, $params); |
320 | list($count) = $query->fetch(); | 389 | list($count) = $query->fetch(); |
321 | 390 | ||
322 | return $count; | 391 | return $count; |
323 | } | 392 | } |
324 | 393 | ||
325 | public function updateContent($id, $content, $user_id) { | 394 | public function updateContent($id, $content, $user_id) { |
@@ -329,11 +398,25 @@ class Database { | |||
329 | return $query; | 398 | return $query; |
330 | } | 399 | } |
331 | 400 | ||
332 | public function add($url, $title, $content, $user_id) { | 401 | /** |
333 | $sql_action = 'INSERT INTO entries ( url, title, content, user_id ) VALUES (?, ?, ?, ?)'; | 402 | * |
334 | $params_action = array($url, $title, $content, $user_id); | 403 | * @param string $url |
335 | $query = $this->executeQuery($sql_action, $params_action); | 404 | * @param string $title |
336 | return $query; | 405 | * @param string $content |
406 | * @param integer $user_id | ||
407 | * @return integer $id of inserted record | ||
408 | */ | ||
409 | public function add($url, $title, $content, $user_id, $isFavorite=0, $isRead=0) { | ||
410 | $sql_action = 'INSERT INTO entries ( url, title, content, user_id, is_fav, is_read ) VALUES (?, ?, ?, ?, ?, ?)'; | ||
411 | $params_action = array($url, $title, $content, $user_id, $isFavorite, $isRead); | ||
412 | |||
413 | if ( !$this->executeQuery($sql_action, $params_action) ) { | ||
414 | $id = null; | ||
415 | } | ||
416 | else { | ||
417 | $id = intval($this->getLastId( (STORAGE == 'postgres') ? 'entries_id_seq' : '') ); | ||
418 | } | ||
419 | return $id; | ||
337 | } | 420 | } |
338 | 421 | ||
339 | public function deleteById($id, $user_id) { | 422 | public function deleteById($id, $user_id) { |
@@ -365,12 +448,24 @@ class Database { | |||
365 | return $this->getHandle()->lastInsertId($column); | 448 | return $this->getHandle()->lastInsertId($column); |
366 | } | 449 | } |
367 | 450 | ||
368 | public function retrieveAllTags($user_id) { | 451 | public function search($term, $user_id, $limit = '') { |
369 | $sql = "SELECT DISTINCT tags.* FROM tags | 452 | $search = '%'.$term.'%'; |
453 | $sql_action = "SELECT * FROM entries WHERE user_id=? AND (content LIKE ? OR title LIKE ? OR url LIKE ?) "; //searches in content, title and URL | ||
454 | $sql_action .= $this->getEntriesOrder().' ' . $limit; | ||
455 | $params_action = array($user_id, $search, $search, $search); | ||
456 | $query = $this->executeQuery($sql_action, $params_action); | ||
457 | return $query->fetchAll(); | ||
458 | } | ||
459 | |||
460 | public function retrieveAllTags($user_id, $term = null) { | ||
461 | $sql = "SELECT DISTINCT tags.*, count(entries.id) AS entriescount FROM tags | ||
370 | LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id | 462 | LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id |
371 | LEFT JOIN entries ON tags_entries.entry_id=entries.id | 463 | LEFT JOIN entries ON tags_entries.entry_id=entries.id |
372 | WHERE entries.user_id=?"; | 464 | WHERE entries.user_id=? |
373 | $query = $this->executeQuery($sql, array($user_id)); | 465 | ". (($term) ? "AND lower(tags.value) LIKE ?" : '') ." |
466 | GROUP BY tags.id, tags.value | ||
467 | ORDER BY tags.value"; | ||
468 | $query = $this->executeQuery($sql, (($term)? array($user_id, strtolower('%'.$term.'%')) : array($user_id) )); | ||
374 | $tags = $query->fetchAll(); | 469 | $tags = $query->fetchAll(); |
375 | 470 | ||
376 | return $tags; | 471 | return $tags; |
@@ -390,10 +485,10 @@ class Database { | |||
390 | } | 485 | } |
391 | 486 | ||
392 | public function retrieveEntriesByTag($tag_id, $user_id) { | 487 | public function retrieveEntriesByTag($tag_id, $user_id) { |
393 | $sql = | 488 | $sql = |
394 | "SELECT entries.* FROM entries | 489 | "SELECT entries.* FROM entries |
395 | LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id | 490 | LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id |
396 | WHERE tags_entries.tag_id = ? AND entries.user_id=?"; | 491 | WHERE tags_entries.tag_id = ? AND entries.user_id=? ORDER by entries.id DESC"; |
397 | $query = $this->executeQuery($sql, array($tag_id, $user_id)); | 492 | $query = $this->executeQuery($sql, array($tag_id, $user_id)); |
398 | $entries = $query->fetchAll(); | 493 | $entries = $query->fetchAll(); |
399 | 494 | ||
@@ -401,7 +496,7 @@ class Database { | |||
401 | } | 496 | } |
402 | 497 | ||
403 | public function retrieveTagsByEntry($entry_id) { | 498 | public function retrieveTagsByEntry($entry_id) { |
404 | $sql = | 499 | $sql = |
405 | "SELECT tags.* FROM tags | 500 | "SELECT tags.* FROM tags |
406 | LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id | 501 | LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id |
407 | WHERE tags_entries.entry_id = ?"; | 502 | WHERE tags_entries.entry_id = ?"; |
@@ -417,6 +512,25 @@ class Database { | |||
417 | $query = $this->executeQuery($sql_action, $params_action); | 512 | $query = $this->executeQuery($sql_action, $params_action); |
418 | return $query; | 513 | return $query; |
419 | } | 514 | } |
515 | |||
516 | public function cleanUnusedTag($tag_id) { | ||
517 | $sql_action = "SELECT tags.* FROM tags JOIN tags_entries ON tags_entries.tag_id=tags.id WHERE tags.id=?"; | ||
518 | $query = $this->executeQuery($sql_action,array($tag_id)); | ||
519 | $tagstokeep = $query->fetchAll(); | ||
520 | $sql_action = "SELECT tags.* FROM tags LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id WHERE tags.id=?"; | ||
521 | $query = $this->executeQuery($sql_action,array($tag_id)); | ||
522 | $alltags = $query->fetchAll(); | ||
523 | |||
524 | foreach ($alltags as $tag) { | ||
525 | if ($tag && !in_array($tag,$tagstokeep)) { | ||
526 | $sql_action = "DELETE FROM tags WHERE id=?"; | ||
527 | $params_action = array($tag[0]); | ||
528 | $this->executeQuery($sql_action, $params_action); | ||
529 | return true; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | } | ||
420 | 534 | ||
421 | public function retrieveTagByValue($value) { | 535 | public function retrieveTagByValue($value) { |
422 | $tag = NULL; | 536 | $tag = NULL; |
diff --git a/inc/poche/Poche.class.php b/inc/poche/Poche.class.php index 8a9de488..09a9f5ff 100755 --- a/inc/poche/Poche.class.php +++ b/inc/poche/Poche.class.php | |||
@@ -18,7 +18,7 @@ class Poche | |||
18 | public $tpl; | 18 | public $tpl; |
19 | public $messages; | 19 | public $messages; |
20 | public $pagination; | 20 | public $pagination; |
21 | 21 | ||
22 | private $currentTheme = ''; | 22 | private $currentTheme = ''; |
23 | private $currentLanguage = ''; | 23 | private $currentLanguage = ''; |
24 | private $notInstalledMessage = array(); | 24 | private $notInstalledMessage = array(); |
@@ -32,20 +32,21 @@ class Poche | |||
32 | 'fr_FR.utf8' => 'Français', | 32 | 'fr_FR.utf8' => 'Français', |
33 | 'it_IT.utf8' => 'Italiano', | 33 | 'it_IT.utf8' => 'Italiano', |
34 | 'pl_PL.utf8' => 'Polski', | 34 | 'pl_PL.utf8' => 'Polski', |
35 | 'pt_BR.utf8' => 'Português (Brasil)', | ||
35 | 'ru_RU.utf8' => 'Pусский', | 36 | 'ru_RU.utf8' => 'Pусский', |
36 | 'sl_SI.utf8' => 'Slovenščina', | 37 | 'sl_SI.utf8' => 'Slovenščina', |
37 | 'uk_UA.utf8' => 'Українськй', | 38 | 'uk_UA.utf8' => 'Українськ', |
38 | ); | 39 | ); |
39 | public function __construct() | 40 | public function __construct() |
40 | { | 41 | { |
41 | if ($this->configFileIsAvailable()) { | 42 | if ($this->configFileIsAvailable()) { |
42 | $this->init(); | 43 | $this->init(); |
43 | } | 44 | } |
44 | 45 | ||
45 | if ($this->themeIsInstalled()) { | 46 | if ($this->themeIsInstalled()) { |
46 | $this->initTpl(); | 47 | $this->initTpl(); |
47 | } | 48 | } |
48 | 49 | ||
49 | if ($this->systemIsInstalled()) { | 50 | if ($this->systemIsInstalled()) { |
50 | $this->store = new Database(); | 51 | $this->store = new Database(); |
51 | $this->messages = new Messages(); | 52 | $this->messages = new Messages(); |
@@ -56,12 +57,10 @@ class Poche | |||
56 | $this->store->checkTags(); | 57 | $this->store->checkTags(); |
57 | } | 58 | } |
58 | } | 59 | } |
59 | 60 | ||
60 | private function init() | 61 | private function init() |
61 | { | 62 | { |
62 | Tools::initPhp(); | 63 | Tools::initPhp(); |
63 | Session::$sessionName = 'poche'; | ||
64 | Session::init(); | ||
65 | 64 | ||
66 | if (isset($_SESSION['poche_user']) && $_SESSION['poche_user'] != array()) { | 65 | if (isset($_SESSION['poche_user']) && $_SESSION['poche_user'] != array()) { |
67 | $this->user = $_SESSION['poche_user']; | 66 | $this->user = $_SESSION['poche_user']; |
@@ -73,43 +72,43 @@ class Poche | |||
73 | 72 | ||
74 | # l10n | 73 | # l10n |
75 | $language = $this->user->getConfigValue('language'); | 74 | $language = $this->user->getConfigValue('language'); |
76 | putenv('LC_ALL=' . $language); | 75 | @putenv('LC_ALL=' . $language); |
77 | setlocale(LC_ALL, $language); | 76 | setlocale(LC_ALL, $language); |
78 | bindtextdomain($language, LOCALE); | 77 | bindtextdomain($language, LOCALE); |
79 | textdomain($language); | 78 | textdomain($language); |
80 | 79 | ||
81 | # Pagination | 80 | # Pagination |
82 | $this->pagination = new Paginator($this->user->getConfigValue('pager'), 'p'); | 81 | $this->pagination = new Paginator($this->user->getConfigValue('pager'), 'p'); |
83 | 82 | ||
84 | # Set up theme | 83 | # Set up theme |
85 | $themeDirectory = $this->user->getConfigValue('theme'); | 84 | $themeDirectory = $this->user->getConfigValue('theme'); |
86 | 85 | ||
87 | if ($themeDirectory === false) { | 86 | if ($themeDirectory === false) { |
88 | $themeDirectory = DEFAULT_THEME; | 87 | $themeDirectory = DEFAULT_THEME; |
89 | } | 88 | } |
90 | 89 | ||
91 | $this->currentTheme = $themeDirectory; | 90 | $this->currentTheme = $themeDirectory; |
92 | 91 | ||
93 | # Set up language | 92 | # Set up language |
94 | $languageDirectory = $this->user->getConfigValue('language'); | 93 | $languageDirectory = $this->user->getConfigValue('language'); |
95 | 94 | ||
96 | if ($languageDirectory === false) { | 95 | if ($languageDirectory === false) { |
97 | $languageDirectory = DEFAULT_THEME; | 96 | $languageDirectory = DEFAULT_THEME; |
98 | } | 97 | } |
99 | 98 | ||
100 | $this->currentLanguage = $languageDirectory; | 99 | $this->currentLanguage = $languageDirectory; |
101 | } | 100 | } |
102 | 101 | ||
103 | public function configFileIsAvailable() { | 102 | public function configFileIsAvailable() { |
104 | if (! self::$configFileAvailable) { | 103 | if (! self::$configFileAvailable) { |
105 | $this->notInstalledMessage[] = 'You have to rename inc/poche/config.inc.php.new to inc/poche/config.inc.php.'; | 104 | $this->notInstalledMessage[] = 'You have to copy (don\'t just rename!) inc/poche/config.inc.default.php to inc/poche/config.inc.php.'; |
106 | 105 | ||
107 | return false; | 106 | return false; |
108 | } | 107 | } |
109 | 108 | ||
110 | return true; | 109 | return true; |
111 | } | 110 | } |
112 | 111 | ||
113 | public function themeIsInstalled() { | 112 | public function themeIsInstalled() { |
114 | $passTheme = TRUE; | 113 | $passTheme = TRUE; |
115 | # Twig is an absolute requirement for Poche to function. Abort immediately if the Composer installer hasn't been run yet | 114 | # Twig is an absolute requirement for Poche to function. Abort immediately if the Composer installer hasn't been run yet |
@@ -124,27 +123,27 @@ class Poche | |||
124 | self::$canRenderTemplates = false; | 123 | self::$canRenderTemplates = false; |
125 | 124 | ||
126 | $passTheme = FALSE; | 125 | $passTheme = FALSE; |
127 | } | 126 | } |
128 | 127 | ||
129 | # Check if the selected theme and its requirements are present | 128 | # Check if the selected theme and its requirements are present |
130 | $theme = $this->getTheme(); | 129 | $theme = $this->getTheme(); |
131 | 130 | ||
132 | if ($theme != '' && ! is_dir(THEME . '/' . $theme)) { | 131 | if ($theme != '' && ! is_dir(THEME . '/' . $theme)) { |
133 | $this->notInstalledMessage[] = 'The currently selected theme (' . $theme . ') does not seem to be properly installed (Missing directory: ' . THEME . '/' . $theme . ')'; | 132 | $this->notInstalledMessage[] = 'The currently selected theme (' . $theme . ') does not seem to be properly installed (Missing directory: ' . THEME . '/' . $theme . ')'; |
134 | 133 | ||
135 | self::$canRenderTemplates = false; | 134 | self::$canRenderTemplates = false; |
136 | 135 | ||
137 | $passTheme = FALSE; | 136 | $passTheme = FALSE; |
138 | } | 137 | } |
139 | 138 | ||
140 | $themeInfo = $this->getThemeInfo($theme); | 139 | $themeInfo = $this->getThemeInfo($theme); |
141 | if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) { | 140 | if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) { |
142 | foreach ($themeInfo['requirements'] as $requiredTheme) { | 141 | foreach ($themeInfo['requirements'] as $requiredTheme) { |
143 | if (! is_dir(THEME . '/' . $requiredTheme)) { | 142 | if (! is_dir(THEME . '/' . $requiredTheme)) { |
144 | $this->notInstalledMessage[] = 'The required "' . $requiredTheme . '" theme is missing for the current theme (' . $theme . ')'; | 143 | $this->notInstalledMessage[] = 'The required "' . $requiredTheme . '" theme is missing for the current theme (' . $theme . ')'; |
145 | 144 | ||
146 | self::$canRenderTemplates = false; | 145 | self::$canRenderTemplates = false; |
147 | 146 | ||
148 | $passTheme = FALSE; | 147 | $passTheme = FALSE; |
149 | } | 148 | } |
150 | } | 149 | } |
@@ -154,21 +153,21 @@ class Poche | |||
154 | return FALSE; | 153 | return FALSE; |
155 | } | 154 | } |
156 | 155 | ||
157 | 156 | ||
158 | return true; | 157 | return true; |
159 | } | 158 | } |
160 | 159 | ||
161 | /** | 160 | /** |
162 | * all checks before installation. | 161 | * all checks before installation. |
163 | * @todo move HTML to template | 162 | * @todo move HTML to template |
164 | * @return boolean | 163 | * @return boolean |
165 | */ | 164 | */ |
166 | public function systemIsInstalled() | 165 | public function systemIsInstalled() |
167 | { | 166 | { |
168 | $msg = TRUE; | 167 | $msg = TRUE; |
169 | 168 | ||
170 | $configSalt = defined('SALT') ? constant('SALT') : ''; | 169 | $configSalt = defined('SALT') ? constant('SALT') : ''; |
171 | 170 | ||
172 | if (empty($configSalt)) { | 171 | if (empty($configSalt)) { |
173 | $this->notInstalledMessage[] = 'You have not yet filled in the SALT value in the config.inc.php file.'; | 172 | $this->notInstalledMessage[] = 'You have not yet filled in the SALT value in the config.inc.php file.'; |
174 | $msg = FALSE; | 173 | $msg = FALSE; |
@@ -194,7 +193,7 @@ class Poche | |||
194 | 193 | ||
195 | return true; | 194 | return true; |
196 | } | 195 | } |
197 | 196 | ||
198 | public function getNotInstalledMessage() { | 197 | public function getNotInstalledMessage() { |
199 | return $this->notInstalledMessage; | 198 | return $this->notInstalledMessage; |
200 | } | 199 | } |
@@ -203,7 +202,7 @@ class Poche | |||
203 | { | 202 | { |
204 | $loaderChain = new Twig_Loader_Chain(); | 203 | $loaderChain = new Twig_Loader_Chain(); |
205 | $theme = $this->getTheme(); | 204 | $theme = $this->getTheme(); |
206 | 205 | ||
207 | # add the current theme as first to the loader chain so Twig will look there first for overridden template files | 206 | # add the current theme as first to the loader chain so Twig will look there first for overridden template files |
208 | try { | 207 | try { |
209 | $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . $theme)); | 208 | $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . $theme)); |
@@ -211,7 +210,7 @@ class Poche | |||
211 | # @todo isInstalled() should catch this, inject Twig later | 210 | # @todo isInstalled() should catch this, inject Twig later |
212 | die('The currently selected theme (' . $theme . ') does not seem to be properly installed (' . THEME . '/' . $theme .' is missing)'); | 211 | die('The currently selected theme (' . $theme . ') does not seem to be properly installed (' . THEME . '/' . $theme .' is missing)'); |
213 | } | 212 | } |
214 | 213 | ||
215 | # add all required themes to the loader chain | 214 | # add all required themes to the loader chain |
216 | $themeInfo = $this->getThemeInfo($theme); | 215 | $themeInfo = $this->getThemeInfo($theme); |
217 | if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) { | 216 | if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) { |
@@ -224,16 +223,16 @@ class Poche | |||
224 | } | 223 | } |
225 | } | 224 | } |
226 | } | 225 | } |
227 | 226 | ||
228 | if (DEBUG_POCHE) { | 227 | if (DEBUG_POCHE) { |
229 | $twigParams = array(); | 228 | $twigParams = array(); |
230 | } else { | 229 | } else { |
231 | $twigParams = array('cache' => CACHE); | 230 | $twigParams = array('cache' => CACHE); |
232 | } | 231 | } |
233 | 232 | ||
234 | $this->tpl = new Twig_Environment($loaderChain, $twigParams); | 233 | $this->tpl = new Twig_Environment($loaderChain, $twigParams); |
235 | $this->tpl->addExtension(new Twig_Extensions_Extension_I18n()); | 234 | $this->tpl->addExtension(new Twig_Extensions_Extension_I18n()); |
236 | 235 | ||
237 | # filter to display domain name of an url | 236 | # filter to display domain name of an url |
238 | $filter = new Twig_SimpleFilter('getDomain', 'Tools::getDomain'); | 237 | $filter = new Twig_SimpleFilter('getDomain', 'Tools::getDomain'); |
239 | $this->tpl->addFilter($filter); | 238 | $this->tpl->addFilter($filter); |
@@ -243,6 +242,58 @@ class Poche | |||
243 | $this->tpl->addFilter($filter); | 242 | $this->tpl->addFilter($filter); |
244 | } | 243 | } |
245 | 244 | ||
245 | public function createNewUser() { | ||
246 | if (isset($_GET['newuser'])){ | ||
247 | if ($_POST['newusername'] != "" && $_POST['password4newuser'] != ""){ | ||
248 | $newusername = filter_var($_POST['newusername'], FILTER_SANITIZE_STRING); | ||
249 | if (!$this->store->userExists($newusername)){ | ||
250 | if ($this->store->install($newusername, Tools::encodeString($_POST['password4newuser'] . $newusername))) { | ||
251 | Tools::logm('The new user '.$newusername.' has been installed'); | ||
252 | $this->messages->add('s', sprintf(_('The new user %s has been installed. Do you want to <a href="?logout">logout ?</a>'),$newusername)); | ||
253 | Tools::redirect(); | ||
254 | } | ||
255 | else { | ||
256 | Tools::logm('error during adding new user'); | ||
257 | Tools::redirect(); | ||
258 | } | ||
259 | } | ||
260 | else { | ||
261 | $this->messages->add('e', sprintf(_('Error : An user with the name %s already exists !'),$newusername)); | ||
262 | Tools::logm('An user with the name '.$newusername.' already exists !'); | ||
263 | Tools::redirect(); | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | } | ||
268 | |||
269 | public function deleteUser(){ | ||
270 | if (isset($_GET['deluser'])){ | ||
271 | if ($this->store->listUsers() > 1) { | ||
272 | if (Tools::encodeString($_POST['password4deletinguser'].$this->user->getUsername()) == $this->store->getUserPassword($this->user->getId())) { | ||
273 | $username = $this->user->getUsername(); | ||
274 | $this->store->deleteUserConfig($this->user->getId()); | ||
275 | Tools::logm('The configuration for user '. $username .' has been deleted !'); | ||
276 | $this->store->deleteTagsEntriesAndEntries($this->user->getId()); | ||
277 | Tools::logm('The entries for user '. $username .' has been deleted !'); | ||
278 | $this->store->deleteUser($this->user->getId()); | ||
279 | Tools::logm('User '. $username .' has been completely deleted !'); | ||
280 | Session::logout(); | ||
281 | Tools::logm('logout'); | ||
282 | Tools::redirect(); | ||
283 | $this->messages->add('s', sprintf(_('User %s has been successfully deleted !'),$newusername)); | ||
284 | } | ||
285 | else { | ||
286 | Tools::logm('Bad password !'); | ||
287 | $this->messages->add('e', _('Error : The password is wrong !')); | ||
288 | } | ||
289 | } | ||
290 | else { | ||
291 | Tools::logm('Only user !'); | ||
292 | $this->messages->add('e', _('Error : You are the only user, you cannot delete your account !')); | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | |||
246 | private function install() | 297 | private function install() |
247 | { | 298 | { |
248 | Tools::logm('poche still not installed'); | 299 | Tools::logm('poche still not installed'); |
@@ -252,7 +303,7 @@ class Poche | |||
252 | 'poche_url' => Tools::getPocheUrl() | 303 | 'poche_url' => Tools::getPocheUrl() |
253 | )); | 304 | )); |
254 | if (isset($_GET['install'])) { | 305 | if (isset($_GET['install'])) { |
255 | if (($_POST['password'] == $_POST['password_repeat']) | 306 | if (($_POST['password'] == $_POST['password_repeat']) |
256 | && $_POST['password'] != "" && $_POST['login'] != "") { | 307 | && $_POST['password'] != "" && $_POST['login'] != "") { |
257 | # let's rock, install poche baby ! | 308 | # let's rock, install poche baby ! |
258 | if ($this->store->install($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login']))) | 309 | if ($this->store->install($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login']))) |
@@ -269,7 +320,7 @@ class Poche | |||
269 | } | 320 | } |
270 | exit(); | 321 | exit(); |
271 | } | 322 | } |
272 | 323 | ||
273 | public function getTheme() { | 324 | public function getTheme() { |
274 | return $this->currentTheme; | 325 | return $this->currentTheme; |
275 | } | 326 | } |
@@ -294,7 +345,7 @@ class Poche | |||
294 | if (is_file($themeIniFile) && is_readable($themeIniFile)) { | 345 | if (is_file($themeIniFile) && is_readable($themeIniFile)) { |
295 | $themeInfo = parse_ini_file($themeIniFile); | 346 | $themeInfo = parse_ini_file($themeIniFile); |
296 | } | 347 | } |
297 | 348 | ||
298 | if ($themeInfo === false) { | 349 | if ($themeInfo === false) { |
299 | $themeInfo = array(); | 350 | $themeInfo = array(); |
300 | } | 351 | } |
@@ -305,7 +356,7 @@ class Poche | |||
305 | 356 | ||
306 | return $themeInfo; | 357 | return $themeInfo; |
307 | } | 358 | } |
308 | 359 | ||
309 | public function getInstalledThemes() { | 360 | public function getInstalledThemes() { |
310 | $handle = opendir(THEME); | 361 | $handle = opendir(THEME); |
311 | $themes = array(); | 362 | $themes = array(); |
@@ -332,28 +383,28 @@ class Poche | |||
332 | public function getInstalledLanguages() { | 383 | public function getInstalledLanguages() { |
333 | $handle = opendir(LOCALE); | 384 | $handle = opendir(LOCALE); |
334 | $languages = array(); | 385 | $languages = array(); |
335 | 386 | ||
336 | while (($language = readdir($handle)) !== false) { | 387 | while (($language = readdir($handle)) !== false) { |
337 | # Languages are stored in a directory, so all directory names are languages | 388 | # Languages are stored in a directory, so all directory names are languages |
338 | # @todo move language installation data to database | 389 | # @todo move language installation data to database |
339 | if (! is_dir(LOCALE . '/' . $language) || in_array($language, array('..', '.'))) { | 390 | if (! is_dir(LOCALE . '/' . $language) || in_array($language, array('..', '.', 'tools'))) { |
340 | continue; | 391 | continue; |
341 | } | 392 | } |
342 | 393 | ||
343 | $current = false; | 394 | $current = false; |
344 | 395 | ||
345 | if ($language === $this->getLanguage()) { | 396 | if ($language === $this->getLanguage()) { |
346 | $current = true; | 397 | $current = true; |
347 | } | 398 | } |
348 | 399 | ||
349 | $languages[] = array('name' => $this->language_names[$language], 'value' => $language, 'current' => $current); | 400 | $languages[] = array('name' => (isset($this->language_names[$language]) ? $this->language_names[$language] : $language), 'value' => $language, 'current' => $current); |
350 | } | 401 | } |
351 | 402 | ||
352 | return $languages; | 403 | return $languages; |
353 | } | 404 | } |
354 | 405 | ||
355 | public function getDefaultConfig() | 406 | public function getDefaultConfig() |
356 | { | 407 | { |
357 | return array( | 408 | return array( |
358 | 'pager' => PAGINATION, | 409 | 'pager' => PAGINATION, |
359 | 'language' => LANG, | 410 | 'language' => LANG, |
@@ -361,60 +412,6 @@ class Poche | |||
361 | ); | 412 | ); |
362 | } | 413 | } |
363 | 414 | ||
364 | protected function getPageContent(Url $url) | ||
365 | { | ||
366 | // Saving and clearing context | ||
367 | $REAL = array(); | ||
368 | foreach( $GLOBALS as $key => $value ) { | ||
369 | if( $key != "GLOBALS" && $key != "_SESSION" ) { | ||
370 | $GLOBALS[$key] = array(); | ||
371 | $REAL[$key] = $value; | ||
372 | } | ||
373 | } | ||
374 | // Saving and clearing session | ||
375 | $REAL_SESSION = array(); | ||
376 | foreach( $_SESSION as $key => $value ) { | ||
377 | $REAL_SESSION[$key] = $value; | ||
378 | unset($_SESSION[$key]); | ||
379 | } | ||
380 | |||
381 | // Running code in different context | ||
382 | $scope = function() { | ||
383 | extract( func_get_arg(1) ); | ||
384 | $_GET = $_REQUEST = array( | ||
385 | "url" => $url->getUrl(), | ||
386 | "max" => 5, | ||
387 | "links" => "preserve", | ||
388 | "exc" => "", | ||
389 | "format" => "json", | ||
390 | "submit" => "Create Feed" | ||
391 | ); | ||
392 | ob_start(); | ||
393 | require func_get_arg(0); | ||
394 | $json = ob_get_flush(); | ||
395 | return $json; | ||
396 | }; | ||
397 | $json = $scope( "inc/3rdparty/makefulltextfeed.php", array("url" => $url) ); | ||
398 | |||
399 | // Clearing and restoring context | ||
400 | foreach( $GLOBALS as $key => $value ) { | ||
401 | if( $key != "GLOBALS" && $key != "_SESSION" ) { | ||
402 | unset($GLOBALS[$key]); | ||
403 | } | ||
404 | } | ||
405 | foreach( $REAL as $key => $value ) { | ||
406 | $GLOBALS[$key] = $value; | ||
407 | } | ||
408 | // Clearing and restoring session | ||
409 | foreach( $_SESSION as $key => $value ) { | ||
410 | unset($_SESSION[$key]); | ||
411 | } | ||
412 | foreach( $REAL_SESSION as $key => $value ) { | ||
413 | $_SESSION[$key] = $value; | ||
414 | } | ||
415 | return json_decode($json, true); | ||
416 | } | ||
417 | |||
418 | /** | 415 | /** |
419 | * Call action (mark as fav, archive, delete, etc.) | 416 | * Call action (mark as fav, archive, delete, etc.) |
420 | */ | 417 | */ |
@@ -423,28 +420,22 @@ class Poche | |||
423 | switch ($action) | 420 | switch ($action) |
424 | { | 421 | { |
425 | case 'add': | 422 | case 'add': |
426 | $content = $this->getPageContent($url); | 423 | $content = Tools::getPageContent($url); |
427 | $title = ($content['rss']['channel']['item']['title'] != '') ? $content['rss']['channel']['item']['title'] : _('Untitled'); | 424 | $title = ($content['rss']['channel']['item']['title'] != '') ? $content['rss']['channel']['item']['title'] : _('Untitled'); |
428 | $body = $content['rss']['channel']['item']['description']; | 425 | $body = $content['rss']['channel']['item']['description']; |
429 | 426 | ||
430 | // clean content from prevent xss attack | 427 | // clean content from prevent xss attack |
431 | $config = HTMLPurifier_Config::createDefault(); | 428 | $purifier = $this->getPurifier(); |
432 | $purifier = new HTMLPurifier($config); | ||
433 | $title = $purifier->purify($title); | 429 | $title = $purifier->purify($title); |
434 | $body = $purifier->purify($body); | 430 | $body = $purifier->purify($body); |
435 | 431 | ||
436 | //search for possible duplicate if not in import mode | 432 | //search for possible duplicate |
437 | if (!$import) { | 433 | $duplicate = NULL; |
438 | $duplicate = $this->store->retrieveOneByURL($url->getUrl(), $this->user->getId()); | 434 | $duplicate = $this->store->retrieveOneByURL($url->getUrl(), $this->user->getId()); |
439 | } | ||
440 | 435 | ||
441 | if ($this->store->add($url->getUrl(), $title, $body, $this->user->getId())) { | 436 | $last_id = $this->store->add($url->getUrl(), $title, $body, $this->user->getId()); |
437 | if ( $last_id ) { | ||
442 | Tools::logm('add link ' . $url->getUrl()); | 438 | Tools::logm('add link ' . $url->getUrl()); |
443 | $sequence = ''; | ||
444 | if (STORAGE == 'postgres') { | ||
445 | $sequence = 'entries_id_seq'; | ||
446 | } | ||
447 | $last_id = $this->store->getLastId($sequence); | ||
448 | if (DOWNLOAD_PICTURES) { | 439 | if (DOWNLOAD_PICTURES) { |
449 | $content = filtre_picture($body, $url->getUrl(), $last_id); | 440 | $content = filtre_picture($body, $url->getUrl(), $last_id); |
450 | Tools::logm('updating content article'); | 441 | Tools::logm('updating content article'); |
@@ -464,23 +455,17 @@ class Poche | |||
464 | } | 455 | } |
465 | } | 456 | } |
466 | 457 | ||
467 | if (!$import) { | 458 | $this->messages->add('s', _('the link has been added successfully')); |
468 | $this->messages->add('s', _('the link has been added successfully')); | ||
469 | } | ||
470 | } | 459 | } |
471 | else { | 460 | else { |
472 | if (!$import) { | 461 | $this->messages->add('e', _('error during insertion : the link wasn\'t added')); |
473 | $this->messages->add('e', _('error during insertion : the link wasn\'t added')); | 462 | Tools::logm('error during insertion : the link wasn\'t added ' . $url->getUrl()); |
474 | Tools::logm('error during insertion : the link wasn\'t added ' . $url->getUrl()); | ||
475 | } | ||
476 | } | 463 | } |
477 | 464 | ||
478 | if (!$import) { | 465 | if ($autoclose == TRUE) { |
479 | if ($autoclose == TRUE) { | 466 | Tools::redirect('?view=home'); |
480 | Tools::redirect('?view=home'); | 467 | } else { |
481 | } else { | 468 | Tools::redirect('?view=home&closewin=true'); |
482 | Tools::redirect('?view=home&closewin=true'); | ||
483 | } | ||
484 | } | 469 | } |
485 | break; | 470 | break; |
486 | case 'delete': | 471 | case 'delete': |
@@ -501,62 +486,81 @@ class Poche | |||
501 | case 'toggle_fav' : | 486 | case 'toggle_fav' : |
502 | $this->store->favoriteById($id, $this->user->getId()); | 487 | $this->store->favoriteById($id, $this->user->getId()); |
503 | Tools::logm('mark as favorite link #' . $id); | 488 | Tools::logm('mark as favorite link #' . $id); |
504 | if (!$import) { | 489 | if ( Tools::isAjaxRequest() ) { |
505 | Tools::redirect(); | 490 | echo 1; |
491 | exit; | ||
492 | } | ||
493 | else { | ||
494 | Tools::redirect(); | ||
506 | } | 495 | } |
507 | break; | 496 | break; |
508 | case 'toggle_archive' : | 497 | case 'toggle_archive' : |
509 | $this->store->archiveById($id, $this->user->getId()); | 498 | $this->store->archiveById($id, $this->user->getId()); |
510 | Tools::logm('archive link #' . $id); | 499 | Tools::logm('archive link #' . $id); |
511 | if (!$import) { | 500 | if ( Tools::isAjaxRequest() ) { |
512 | Tools::redirect(); | 501 | echo 1; |
502 | exit; | ||
503 | } | ||
504 | else { | ||
505 | Tools::redirect(); | ||
513 | } | 506 | } |
514 | break; | 507 | break; |
515 | case 'archive_all' : | 508 | case 'archive_all' : |
516 | $this->store->archiveAll($this->user->getId()); | 509 | $this->store->archiveAll($this->user->getId()); |
517 | Tools::logm('archive all links'); | 510 | Tools::logm('archive all links'); |
518 | if (!$import) { | 511 | Tools::redirect(); |
519 | Tools::redirect(); | ||
520 | } | ||
521 | break; | 512 | break; |
522 | case 'add_tag' : | 513 | case 'add_tag' : |
523 | if($import){ | 514 | if (isset($_GET['search'])) { |
524 | $entry_id = $id; | 515 | //when we want to apply a tag to a search |
525 | $tags = explode(',', $tags); | 516 | $tags = array($_GET['search']); |
526 | } | 517 | $allentry_ids = $this->store->search($tags[0], $this->user->getId()); |
527 | else{ | 518 | $entry_ids = array(); |
519 | foreach ($allentry_ids as $eachentry) { | ||
520 | $entry_ids[] = $eachentry[0]; | ||
521 | } | ||
522 | } else { //add a tag to a single article | ||
528 | $tags = explode(',', $_POST['value']); | 523 | $tags = explode(',', $_POST['value']); |
529 | $entry_id = $_POST['entry_id']; | 524 | $entry_ids = array($_POST['entry_id']); |
530 | } | 525 | } |
531 | $entry = $this->store->retrieveOneById($entry_id, $this->user->getId()); | 526 | foreach($entry_ids as $entry_id) { |
532 | if (!$entry) { | 527 | $entry = $this->store->retrieveOneById($entry_id, $this->user->getId()); |
533 | $this->messages->add('e', _('Article not found!')); | 528 | if (!$entry) { |
534 | Tools::logm('error : article not found'); | 529 | $this->messages->add('e', _('Article not found!')); |
535 | Tools::redirect(); | 530 | Tools::logm('error : article not found'); |
536 | } | 531 | Tools::redirect(); |
537 | foreach($tags as $key => $tag_value) { | ||
538 | $value = trim($tag_value); | ||
539 | $tag = $this->store->retrieveTagByValue($value); | ||
540 | |||
541 | if (is_null($tag)) { | ||
542 | # we create the tag | ||
543 | $tag = $this->store->createTag($value); | ||
544 | $sequence = ''; | ||
545 | if (STORAGE == 'postgres') { | ||
546 | $sequence = 'tags_id_seq'; | ||
547 | } | ||
548 | $tag_id = $this->store->getLastId($sequence); | ||
549 | } | 532 | } |
550 | else { | 533 | //get all already set tags to preven duplicates |
551 | $tag_id = $tag['id']; | 534 | $already_set_tags = array(); |
535 | $entry_tags = $this->store->retrieveTagsByEntry($entry_id); | ||
536 | foreach ($entry_tags as $tag) { | ||
537 | $already_set_tags[] = $tag['value']; | ||
538 | } | ||
539 | foreach($tags as $key => $tag_value) { | ||
540 | $value = trim($tag_value); | ||
541 | if ($value && !in_array($value, $already_set_tags)) { | ||
542 | $tag = $this->store->retrieveTagByValue($value); | ||
543 | if (is_null($tag)) { | ||
544 | # we create the tag | ||
545 | $tag = $this->store->createTag($value); | ||
546 | $sequence = ''; | ||
547 | if (STORAGE == 'postgres') { | ||
548 | $sequence = 'tags_id_seq'; | ||
549 | } | ||
550 | $tag_id = $this->store->getLastId($sequence); | ||
551 | } | ||
552 | else { | ||
553 | $tag_id = $tag['id']; | ||
554 | } | ||
555 | |||
556 | # we assign the tag to the article | ||
557 | $this->store->setTagToEntry($tag_id, $entry_id); | ||
558 | } | ||
552 | } | 559 | } |
553 | |||
554 | # we assign the tag to the article | ||
555 | $this->store->setTagToEntry($tag_id, $entry_id); | ||
556 | } | ||
557 | if(!$import) { | ||
558 | Tools::redirect(); | ||
559 | } | 560 | } |
561 | $this->messages->add('s', _('The tag has been applied successfully')); | ||
562 | Tools::logm('The tag has been applied successfully'); | ||
563 | Tools::redirect(); | ||
560 | break; | 564 | break; |
561 | case 'remove_tag' : | 565 | case 'remove_tag' : |
562 | $tag_id = $_GET['tag_id']; | 566 | $tag_id = $_GET['tag_id']; |
@@ -567,6 +571,11 @@ class Poche | |||
567 | Tools::redirect(); | 571 | Tools::redirect(); |
568 | } | 572 | } |
569 | $this->store->removeTagForEntry($id, $tag_id); | 573 | $this->store->removeTagForEntry($id, $tag_id); |
574 | Tools::logm('tag entry deleted'); | ||
575 | if ($this->store->cleanUnusedTag($tag_id)) { | ||
576 | Tools::logm('tag deleted'); | ||
577 | } | ||
578 | $this->messages->add('s', _('The tag has been successfully deleted')); | ||
570 | Tools::redirect(); | 579 | Tools::redirect(); |
571 | break; | 580 | break; |
572 | default: | 581 | default: |
@@ -581,24 +590,32 @@ class Poche | |||
581 | switch ($view) | 590 | switch ($view) |
582 | { | 591 | { |
583 | case 'config': | 592 | case 'config': |
584 | $dev = trim($this->getPocheVersion('dev')); | 593 | $dev_infos = $this->getPocheVersion('dev'); |
585 | $prod = trim($this->getPocheVersion('prod')); | 594 | $dev = trim($dev_infos[0]); |
595 | $check_time_dev = date('d-M-Y H:i', $dev_infos[1]); | ||
596 | $prod_infos = $this->getPocheVersion('prod'); | ||
597 | $prod = trim($prod_infos[0]); | ||
598 | $check_time_prod = date('d-M-Y H:i', $prod_infos[1]); | ||
586 | $compare_dev = version_compare(POCHE, $dev); | 599 | $compare_dev = version_compare(POCHE, $dev); |
587 | $compare_prod = version_compare(POCHE, $prod); | 600 | $compare_prod = version_compare(POCHE, $prod); |
588 | $themes = $this->getInstalledThemes(); | 601 | $themes = $this->getInstalledThemes(); |
589 | $languages = $this->getInstalledLanguages(); | 602 | $languages = $this->getInstalledLanguages(); |
590 | $token = $this->user->getConfigValue('token'); | 603 | $token = $this->user->getConfigValue('token'); |
591 | $http_auth = (isset($_SERVER['PHP_AUTH_USER']) || isset($_SERVER['REMOTE_USER'])) ? true : false; | 604 | $http_auth = (isset($_SERVER['PHP_AUTH_USER']) || isset($_SERVER['REMOTE_USER'])) ? true : false; |
605 | $only_user = ($this->store->listUsers() > 1) ? false : true; | ||
592 | $tpl_vars = array( | 606 | $tpl_vars = array( |
593 | 'themes' => $themes, | 607 | 'themes' => $themes, |
594 | 'languages' => $languages, | 608 | 'languages' => $languages, |
595 | 'dev' => $dev, | 609 | 'dev' => $dev, |
596 | 'prod' => $prod, | 610 | 'prod' => $prod, |
611 | 'check_time_dev' => $check_time_dev, | ||
612 | 'check_time_prod' => $check_time_prod, | ||
597 | 'compare_dev' => $compare_dev, | 613 | 'compare_dev' => $compare_dev, |
598 | 'compare_prod' => $compare_prod, | 614 | 'compare_prod' => $compare_prod, |
599 | 'token' => $token, | 615 | 'token' => $token, |
600 | 'user_id' => $this->user->getId(), | 616 | 'user_id' => $this->user->getId(), |
601 | 'http_auth' => $http_auth, | 617 | 'http_auth' => $http_auth, |
618 | 'only_user' => $only_user | ||
602 | ); | 619 | ); |
603 | Tools::logm('config view'); | 620 | Tools::logm('config view'); |
604 | break; | 621 | break; |
@@ -619,13 +636,36 @@ class Poche | |||
619 | break; | 636 | break; |
620 | case 'tags': | 637 | case 'tags': |
621 | $token = $this->user->getConfigValue('token'); | 638 | $token = $this->user->getConfigValue('token'); |
622 | $tags = $this->store->retrieveAllTags($this->user->getId()); | 639 | //if term is set - search tags for this term |
640 | $term = Tools::checkVar('term'); | ||
641 | $tags = $this->store->retrieveAllTags($this->user->getId(), $term); | ||
642 | if (Tools::isAjaxRequest()) { | ||
643 | $result = array(); | ||
644 | foreach ($tags as $tag) { | ||
645 | $result[] = $tag['value']; | ||
646 | } | ||
647 | echo json_encode($result); | ||
648 | exit; | ||
649 | } | ||
623 | $tpl_vars = array( | 650 | $tpl_vars = array( |
624 | 'token' => $token, | 651 | 'token' => $token, |
625 | 'user_id' => $this->user->getId(), | 652 | 'user_id' => $this->user->getId(), |
626 | 'tags' => $tags, | 653 | 'tags' => $tags, |
627 | ); | 654 | ); |
628 | break; | 655 | break; |
656 | case 'search': | ||
657 | if (isset($_GET['search'])) { | ||
658 | $search = filter_var($_GET['search'], FILTER_SANITIZE_STRING); | ||
659 | $tpl_vars['entries'] = $this->store->search($search, $this->user->getId()); | ||
660 | $count = count($tpl_vars['entries']); | ||
661 | $this->pagination->set_total($count); | ||
662 | $page_links = str_replace(array('previous', 'next'), array(_('previous'), _('next')), | ||
663 | $this->pagination->page_links('?view=' . $view . '?search=' . $search . '&sort=' . $_SESSION['sort'] . '&' )); | ||
664 | $tpl_vars['page_links'] = $page_links; | ||
665 | $tpl_vars['nb_results'] = $count; | ||
666 | $tpl_vars['search_term'] = $search; | ||
667 | } | ||
668 | break; | ||
629 | case 'view': | 669 | case 'view': |
630 | $entry = $this->store->retrieveOneById($id, $this->user->getId()); | 670 | $entry = $this->store->retrieveOneById($id, $this->user->getId()); |
631 | if ($entry != NULL) { | 671 | if ($entry != NULL) { |
@@ -660,8 +700,9 @@ class Poche | |||
660 | 'entries' => '', | 700 | 'entries' => '', |
661 | 'page_links' => '', | 701 | 'page_links' => '', |
662 | 'nb_results' => '', | 702 | 'nb_results' => '', |
703 | 'listmode' => (isset($_COOKIE['listmode']) ? true : false), | ||
663 | ); | 704 | ); |
664 | 705 | ||
665 | //if id is given - we retrive entries by tag: id is tag id | 706 | //if id is given - we retrive entries by tag: id is tag id |
666 | if ($id) { | 707 | if ($id) { |
667 | $tpl_vars['tag'] = $this->store->retrieveTag($id, $this->user->getId()); | 708 | $tpl_vars['tag'] = $this->store->retrieveTag($id, $this->user->getId()); |
@@ -686,8 +727,8 @@ class Poche | |||
686 | } | 727 | } |
687 | 728 | ||
688 | /** | 729 | /** |
689 | * update the password of the current user. | 730 | * update the password of the current user. |
690 | * if MODE_DEMO is TRUE, the password can't be updated. | 731 | * if MODE_DEMO is TRUE, the password can't be updated. |
691 | * @todo add the return value | 732 | * @todo add the return value |
692 | * @todo set the new password in function header like this updatePassword($newPassword) | 733 | * @todo set the new password in function header like this updatePassword($newPassword) |
693 | * @return boolean | 734 | * @return boolean |
@@ -715,42 +756,44 @@ class Poche | |||
715 | } | 756 | } |
716 | } | 757 | } |
717 | } | 758 | } |
718 | 759 | ||
719 | public function updateTheme() | 760 | public function updateTheme() |
720 | { | 761 | { |
721 | # no data | 762 | # no data |
722 | if (empty($_POST['theme'])) { | 763 | if (empty($_POST['theme'])) { |
723 | } | 764 | } |
724 | 765 | ||
725 | # we are not going to change it to the current theme... | 766 | # we are not going to change it to the current theme... |
726 | if ($_POST['theme'] == $this->getTheme()) { | 767 | if ($_POST['theme'] == $this->getTheme()) { |
727 | $this->messages->add('w', _('still using the "' . $this->getTheme() . '" theme!')); | 768 | $this->messages->add('w', _('still using the "' . $this->getTheme() . '" theme!')); |
728 | Tools::redirect('?view=config'); | 769 | Tools::redirect('?view=config'); |
729 | } | 770 | } |
730 | 771 | ||
731 | $themes = $this->getInstalledThemes(); | 772 | $themes = $this->getInstalledThemes(); |
732 | $actualTheme = false; | 773 | $actualTheme = false; |
733 | 774 | ||
734 | foreach (array_keys($themes) as $theme) { | 775 | foreach (array_keys($themes) as $theme) { |
735 | if ($theme == $_POST['theme']) { | 776 | if ($theme == $_POST['theme']) { |
736 | $actualTheme = true; | 777 | $actualTheme = true; |
737 | break; | 778 | break; |
738 | } | 779 | } |
739 | } | 780 | } |
740 | 781 | ||
741 | if (! $actualTheme) { | 782 | if (! $actualTheme) { |
742 | $this->messages->add('e', _('that theme does not seem to be installed')); | 783 | $this->messages->add('e', _('that theme does not seem to be installed')); |
743 | Tools::redirect('?view=config'); | 784 | Tools::redirect('?view=config'); |
744 | } | 785 | } |
745 | 786 | ||
746 | $this->store->updateUserConfig($this->user->getId(), 'theme', $_POST['theme']); | 787 | $this->store->updateUserConfig($this->user->getId(), 'theme', $_POST['theme']); |
747 | $this->messages->add('s', _('you have changed your theme preferences')); | 788 | $this->messages->add('s', _('you have changed your theme preferences')); |
748 | 789 | ||
749 | $currentConfig = $_SESSION['poche_user']->config; | 790 | $currentConfig = $_SESSION['poche_user']->config; |
750 | $currentConfig['theme'] = $_POST['theme']; | 791 | $currentConfig['theme'] = $_POST['theme']; |
751 | 792 | ||
752 | $_SESSION['poche_user']->setConfig($currentConfig); | 793 | $_SESSION['poche_user']->setConfig($currentConfig); |
753 | 794 | ||
795 | $this->emptyCache(); | ||
796 | |||
754 | Tools::redirect('?view=config'); | 797 | Tools::redirect('?view=config'); |
755 | } | 798 | } |
756 | 799 | ||
@@ -759,39 +802,40 @@ class Poche | |||
759 | # no data | 802 | # no data |
760 | if (empty($_POST['language'])) { | 803 | if (empty($_POST['language'])) { |
761 | } | 804 | } |
762 | 805 | ||
763 | # we are not going to change it to the current language... | 806 | # we are not going to change it to the current language... |
764 | if ($_POST['language'] == $this->getLanguage()) { | 807 | if ($_POST['language'] == $this->getLanguage()) { |
765 | $this->messages->add('w', _('still using the "' . $this->getLanguage() . '" language!')); | 808 | $this->messages->add('w', _('still using the "' . $this->getLanguage() . '" language!')); |
766 | Tools::redirect('?view=config'); | 809 | Tools::redirect('?view=config'); |
767 | } | 810 | } |
768 | 811 | ||
769 | $languages = $this->getInstalledLanguages(); | 812 | $languages = $this->getInstalledLanguages(); |
770 | $actualLanguage = false; | 813 | $actualLanguage = false; |
771 | 814 | ||
772 | foreach ($languages as $language) { | 815 | foreach ($languages as $language) { |
773 | if ($language['value'] == $_POST['language']) { | 816 | if ($language['value'] == $_POST['language']) { |
774 | $actualLanguage = true; | 817 | $actualLanguage = true; |
775 | break; | 818 | break; |
776 | } | 819 | } |
777 | } | 820 | } |
778 | 821 | ||
779 | if (! $actualLanguage) { | 822 | if (! $actualLanguage) { |
780 | $this->messages->add('e', _('that language does not seem to be installed')); | 823 | $this->messages->add('e', _('that language does not seem to be installed')); |
781 | Tools::redirect('?view=config'); | 824 | Tools::redirect('?view=config'); |
782 | } | 825 | } |
783 | 826 | ||
784 | $this->store->updateUserConfig($this->user->getId(), 'language', $_POST['language']); | 827 | $this->store->updateUserConfig($this->user->getId(), 'language', $_POST['language']); |
785 | $this->messages->add('s', _('you have changed your language preferences')); | 828 | $this->messages->add('s', _('you have changed your language preferences')); |
786 | 829 | ||
787 | $currentConfig = $_SESSION['poche_user']->config; | 830 | $currentConfig = $_SESSION['poche_user']->config; |
788 | $currentConfig['language'] = $_POST['language']; | 831 | $currentConfig['language'] = $_POST['language']; |
789 | 832 | ||
790 | $_SESSION['poche_user']->setConfig($currentConfig); | 833 | $_SESSION['poche_user']->setConfig($currentConfig); |
791 | 834 | ||
835 | $this->emptyCache(); | ||
836 | |||
792 | Tools::redirect('?view=config'); | 837 | Tools::redirect('?view=config'); |
793 | } | 838 | } |
794 | |||
795 | /** | 839 | /** |
796 | * get credentials from differents sources | 840 | * get credentials from differents sources |
797 | * it redirects the user to the $referer link | 841 | * it redirects the user to the $referer link |
@@ -846,7 +890,7 @@ class Poche | |||
846 | /** | 890 | /** |
847 | * log out the poche user. It cleans the session. | 891 | * log out the poche user. It cleans the session. |
848 | * @todo add the return value | 892 | * @todo add the return value |
849 | * @return boolean | 893 | * @return boolean |
850 | */ | 894 | */ |
851 | public function logout() | 895 | public function logout() |
852 | { | 896 | { |
@@ -857,238 +901,137 @@ class Poche | |||
857 | } | 901 | } |
858 | 902 | ||
859 | /** | 903 | /** |
860 | * import from Instapaper. poche needs a ./instapaper-export.html file | 904 | * import datas into your poche |
861 | * @todo add the return value | ||
862 | * @param string $targetFile the file used for importing | ||
863 | * @return boolean | 905 | * @return boolean |
864 | */ | 906 | */ |
865 | private function importFromInstapaper($targetFile) | 907 | public function import() { |
866 | { | 908 | |
867 | # TODO gestion des articles favs | 909 | if ( isset($_FILES['file']) ) { |
868 | $html = new simple_html_dom(); | 910 | Tools::logm('Import stated: parsing file'); |
869 | $html->load_file($targetFile); | 911 | |
870 | Tools::logm('starting import from instapaper'); | 912 | // assume, that file is in json format |
871 | 913 | $str_data = file_get_contents($_FILES['file']['tmp_name']); | |
872 | $read = 0; | 914 | $data = json_decode($str_data, true); |
873 | $errors = array(); | 915 | |
874 | foreach($html->find('ol') as $ul) | 916 | if ( $data === null ) { |
875 | { | 917 | //not json - assume html |
876 | foreach($ul->find('li') as $li) | 918 | $html = new simple_html_dom(); |
877 | { | 919 | $html->load_file($_FILES['file']['tmp_name']); |
878 | $a = $li->find('a'); | 920 | $data = array(); |
879 | $url = new Url(base64_encode($a[0]->href)); | 921 | $read = 0; |
880 | $this->action('add', $url, 0, TRUE); | 922 | foreach (array('ol','ul') as $list) { |
881 | if ($read == '1') { | 923 | foreach ($html->find($list) as $ul) { |
882 | $sequence = ''; | 924 | foreach ($ul->find('li') as $li) { |
883 | if (STORAGE == 'postgres') { | 925 | $tmpEntry = array(); |
884 | $sequence = 'entries_id_seq'; | 926 | $a = $li->find('a'); |
885 | } | 927 | $tmpEntry['url'] = $a[0]->href; |
886 | $last_id = $this->store->getLastId($sequence); | 928 | $tmpEntry['tags'] = $a[0]->tags; |
887 | $this->action('toggle_archive', $url, $last_id, TRUE); | 929 | $tmpEntry['is_read'] = $read; |
888 | } | 930 | if ($tmpEntry['url']) { |
931 | $data[] = $tmpEntry; | ||
932 | } | ||
933 | } | ||
934 | # the second <ol/ul> is for read links | ||
935 | $read = ((sizeof($data) && $read)?0:1); | ||
889 | } | 936 | } |
890 | 937 | } | |
891 | # the second <ol> is for read links | ||
892 | $read = 1; | ||
893 | } | 938 | } |
894 | $this->messages->add('s', _('import from instapaper completed')); | ||
895 | Tools::logm('import from instapaper completed'); | ||
896 | Tools::redirect(); | ||
897 | } | ||
898 | 939 | ||
899 | /** | 940 | //for readability structure |
900 | * import from Pocket. poche needs a ./ril_export.html file | 941 | foreach ($data as $record) { |
901 | * @todo add the return value | 942 | if (is_array($record)) { |
902 | * @param string $targetFile the file used for importing | 943 | $data[] = $record; |
903 | * @return boolean | 944 | foreach ($record as $record2) { |
904 | */ | 945 | if (is_array($record2)) { |
905 | private function importFromPocket($targetFile) | 946 | $data[] = $record2; |
906 | { | 947 | } |
907 | # TODO gestion des articles favs | 948 | } |
908 | $html = new simple_html_dom(); | 949 | } |
909 | $html->load_file($targetFile); | 950 | } |
910 | Tools::logm('starting import from pocket'); | 951 | |
911 | 952 | $urlsInserted = array(); //urls of articles inserted | |
912 | $read = 0; | 953 | foreach ($data as $record) { |
913 | $errors = array(); | 954 | $url = trim( isset($record['article__url']) ? $record['article__url'] : (isset($record['url']) ? $record['url'] : '') ); |
914 | foreach($html->find('ul') as $ul) | 955 | if ( $url and !in_array($url, $urlsInserted) ) { |
915 | { | 956 | $title = (isset($record['title']) ? $record['title'] : _('Untitled - Import - ').'</a> <a href="./?import">'._('click to finish import').'</a><a>'); |
916 | foreach($ul->find('li') as $li) | 957 | $body = (isset($record['content']) ? $record['content'] : ''); |
917 | { | 958 | $isRead = (isset($record['is_read']) ? intval($record['is_read']) : (isset($record['archive'])?intval($record['archive']):0)); |
918 | $a = $li->find('a'); | 959 | $isFavorite = (isset($record['is_fav']) ? intval($record['is_fav']) : (isset($record['favorite'])?intval($record['favorite']):0) ); |
919 | $url = new Url(base64_encode($a[0]->href)); | 960 | //insert new record |
920 | $this->action('add', $url, 0, TRUE); | 961 | $id = $this->store->add($url, $title, $body, $this->user->getId(), $isFavorite, $isRead); |
921 | $sequence = ''; | 962 | if ( $id ) { |
922 | if (STORAGE == 'postgres') { | 963 | $urlsInserted[] = $url; //add |
923 | $sequence = 'entries_id_seq'; | 964 | |
924 | } | 965 | if ( isset($record['tags']) && trim($record['tags']) ) { |
925 | $last_id = $this->store->getLastId($sequence); | 966 | //@TODO: set tags |
926 | if ($read == '1') { | 967 | |
927 | $this->action('toggle_archive', $url, $last_id, TRUE); | 968 | } |
928 | } | ||
929 | $tags = $a[0]->tags; | ||
930 | if(!empty($tags)) { | ||
931 | $this->action('add_tag',$url,$last_id,true,false,$tags); | ||
932 | } | ||
933 | } | 969 | } |
934 | 970 | } | |
935 | # the second <ul> is for read links | ||
936 | $read = 1; | ||
937 | } | 971 | } |
938 | $this->messages->add('s', _('import from pocket completed')); | ||
939 | Tools::logm('import from pocket completed'); | ||
940 | Tools::redirect(); | ||
941 | } | ||
942 | |||
943 | /** | ||
944 | * import from Readability. poche needs a ./readability file | ||
945 | * @todo add the return value | ||
946 | * @param string $targetFile the file used for importing | ||
947 | * @return boolean | ||
948 | */ | ||
949 | private function importFromReadability($targetFile) | ||
950 | { | ||
951 | # TODO gestion des articles lus / favs | ||
952 | $str_data = file_get_contents($targetFile); | ||
953 | $data = json_decode($str_data,true); | ||
954 | Tools::logm('starting import from Readability'); | ||
955 | $count = 0; | ||
956 | foreach ($data as $key => $value) { | ||
957 | $url = NULL; | ||
958 | $favorite = FALSE; | ||
959 | $archive = FALSE; | ||
960 | foreach ($value as $item) { | ||
961 | foreach ($item as $attr => $value) { | ||
962 | if ($attr == 'article__url') { | ||
963 | $url = new Url(base64_encode($value)); | ||
964 | } | ||
965 | $sequence = ''; | ||
966 | if (STORAGE == 'postgres') { | ||
967 | $sequence = 'entries_id_seq'; | ||
968 | } | ||
969 | if ($value == 'true') { | ||
970 | if ($attr == 'favorite') { | ||
971 | $favorite = TRUE; | ||
972 | } | ||
973 | if ($attr == 'archive') { | ||
974 | $archive = TRUE; | ||
975 | } | ||
976 | } | ||
977 | } | ||
978 | 972 | ||
979 | # we can add the url | 973 | $i = sizeof($urlsInserted); |
980 | if (!is_null($url) && $url->isCorrect()) { | 974 | if ( $i > 0 ) { |
981 | $this->action('add', $url, 0, TRUE); | 975 | $this->messages->add('s', _('Articles inserted: ').$i._('. Please note, that some may be marked as "read".')); |
982 | $count++; | ||
983 | if ($favorite) { | ||
984 | $last_id = $this->store->getLastId($sequence); | ||
985 | $this->action('toggle_fav', $url, $last_id, TRUE); | ||
986 | } | ||
987 | if ($archive) { | ||
988 | $last_id = $this->store->getLastId($sequence); | ||
989 | $this->action('toggle_archive', $url, $last_id, TRUE); | ||
990 | } | ||
991 | } | ||
992 | } | ||
993 | } | 976 | } |
994 | $this->messages->add('s', _('import from Readability completed. ' . $count . ' new links.')); | 977 | Tools::logm('Import of articles finished: '.$i.' articles added (w/o content if not provided).'); |
995 | Tools::logm('import from Readability completed'); | 978 | } |
979 | //file parsing finished here | ||
980 | |||
981 | //now download article contents if any | ||
982 | |||
983 | //check if we need to download any content | ||
984 | $recordsDownloadRequired = $this->store->retrieveUnfetchedEntriesCount($this->user->getId()); | ||
985 | if ( $recordsDownloadRequired == 0 ) { | ||
986 | //nothing to download | ||
987 | $this->messages->add('s', _('Import finished.')); | ||
988 | Tools::logm('Import finished completely'); | ||
996 | Tools::redirect(); | 989 | Tools::redirect(); |
997 | } | 990 | } |
991 | else { | ||
992 | //if just inserted - don't download anything, download will start in next reload | ||
993 | if ( !isset($_FILES['file']) ) { | ||
994 | //download next batch | ||
995 | Tools::logm('Fetching next batch of articles...'); | ||
996 | $items = $this->store->retrieveUnfetchedEntries($this->user->getId(), IMPORT_LIMIT); | ||
998 | 997 | ||
999 | /** | 998 | $purifier = $this->getPurifier(); |
1000 | * import from Poche exported file | ||
1001 | * @param string $targetFile the file used for importing | ||
1002 | * @return boolean | ||
1003 | */ | ||
1004 | private function importFromPoche($targetFile) | ||
1005 | { | ||
1006 | $str_data = file_get_contents($targetFile); | ||
1007 | $data = json_decode($str_data,true); | ||
1008 | Tools::logm('starting import from Poche'); | ||
1009 | 999 | ||
1000 | foreach ($items as $item) { | ||
1001 | $url = new Url(base64_encode($item['url'])); | ||
1002 | Tools::logm('Fetching article '.$item['id']); | ||
1003 | $content = Tools::getPageContent($url); | ||
1010 | 1004 | ||
1011 | $sequence = ''; | 1005 | $title = (($content['rss']['channel']['item']['title'] != '') ? $content['rss']['channel']['item']['title'] : _('Untitled')); |
1012 | if (STORAGE == 'postgres') { | 1006 | $body = (($content['rss']['channel']['item']['description'] != '') ? $content['rss']['channel']['item']['description'] : _('Undefined')); |
1013 | $sequence = 'entries_id_seq'; | ||
1014 | } | ||
1015 | 1007 | ||
1016 | $count = 0; | 1008 | //clean content to prevent xss attack |
1017 | foreach ($data as $value) { | 1009 | $title = $purifier->purify($title); |
1018 | 1010 | $body = $purifier->purify($body); | |
1019 | $url = new Url(base64_encode($value['url'])); | 1011 | |
1020 | $favorite = ($value['is_fav'] == -1); | 1012 | $this->store->updateContentAndTitle($item['id'], $title, $body, $this->user->getId()); |
1021 | $archive = ($value['is_read'] == -1); | 1013 | Tools::logm('Article '.$item['id'].' updated.'); |
1022 | 1014 | } | |
1023 | # we can add the url | ||
1024 | if (!is_null($url) && $url->isCorrect()) { | ||
1025 | |||
1026 | $this->action('add', $url, 0, TRUE); | ||
1027 | |||
1028 | $count++; | ||
1029 | if ($favorite) { | ||
1030 | $last_id = $this->store->getLastId($sequence); | ||
1031 | $this->action('toggle_fav', $url, $last_id, TRUE); | ||
1032 | } | ||
1033 | if ($archive) { | ||
1034 | $last_id = $this->store->getLastId($sequence); | ||
1035 | $this->action('toggle_archive', $url, $last_id, TRUE); | ||
1036 | } | ||
1037 | } | ||
1038 | |||
1039 | } | ||
1040 | $this->messages->add('s', _('import from Poche completed. ' . $count . ' new links.')); | ||
1041 | Tools::logm('import from Poche completed'); | ||
1042 | Tools::redirect(); | ||
1043 | } | ||
1044 | 1015 | ||
1045 | /** | ||
1046 | * import datas into your poche | ||
1047 | * @param string $from name of the service to import : pocket, instapaper or readability | ||
1048 | * @todo add the return value | ||
1049 | * @return boolean | ||
1050 | */ | ||
1051 | public function import($from) | ||
1052 | { | ||
1053 | $providers = array( | ||
1054 | 'pocket' => 'importFromPocket', | ||
1055 | 'readability' => 'importFromReadability', | ||
1056 | 'instapaper' => 'importFromInstapaper', | ||
1057 | 'poche' => 'importFromPoche', | ||
1058 | ); | ||
1059 | |||
1060 | if (! isset($providers[$from])) { | ||
1061 | $this->messages->add('e', _('Unknown import provider.')); | ||
1062 | Tools::redirect(); | ||
1063 | } | ||
1064 | |||
1065 | $targetDefinition = 'IMPORT_' . strtoupper($from) . '_FILE'; | ||
1066 | $targetFile = constant($targetDefinition); | ||
1067 | |||
1068 | if (! defined($targetDefinition)) { | ||
1069 | $this->messages->add('e', _('Incomplete inc/poche/define.inc.php file, please define "' . $targetDefinition . '".')); | ||
1070 | Tools::redirect(); | ||
1071 | } | ||
1072 | |||
1073 | if (! file_exists($targetFile)) { | ||
1074 | $this->messages->add('e', _('Could not find required "' . $targetFile . '" import file.')); | ||
1075 | Tools::redirect(); | ||
1076 | } | 1016 | } |
1077 | 1017 | } | |
1078 | $this->$providers[$from]($targetFile); | 1018 | |
1019 | return array('includeImport'=>true, 'import'=>array('recordsDownloadRequired'=>$recordsDownloadRequired, 'recordsUnderDownload'=> IMPORT_LIMIT, 'delay'=> IMPORT_DELAY * 1000) ); | ||
1079 | } | 1020 | } |
1080 | 1021 | ||
1081 | /** | 1022 | /** |
1082 | * export poche entries in json | 1023 | * export poche entries in json |
1083 | * @return json all poche entries | 1024 | * @return json all poche entries |
1084 | */ | 1025 | */ |
1085 | public function export() | 1026 | public function export() { |
1086 | { | 1027 | $filename = "wallabag-export-".$this->user->getId()."-".date("Y-m-d").".json"; |
1087 | $entries = $this->store->retrieveAll($this->user->getId()); | 1028 | header('Content-Disposition: attachment; filename='.$filename); |
1088 | echo $this->tpl->render('export.twig', array( | 1029 | |
1089 | 'export' => Tools::renderJson($entries), | 1030 | $entries = $this->store->retrieveAll($this->user->getId()); |
1090 | )); | 1031 | echo $this->tpl->render('export.twig', array( |
1091 | Tools::logm('export view'); | 1032 | 'export' => Tools::renderJson($entries), |
1033 | )); | ||
1034 | Tools::logm('export view'); | ||
1092 | } | 1035 | } |
1093 | 1036 | ||
1094 | /** | 1037 | /** |
@@ -1096,35 +1039,42 @@ class Poche | |||
1096 | * @param string $which 'prod' or 'dev' | 1039 | * @param string $which 'prod' or 'dev' |
1097 | * @return string latest $which version | 1040 | * @return string latest $which version |
1098 | */ | 1041 | */ |
1099 | private function getPocheVersion($which = 'prod') | 1042 | private function getPocheVersion($which = 'prod') { |
1100 | { | 1043 | $cache_file = CACHE . '/' . $which; |
1101 | $cache_file = CACHE . '/' . $which; | 1044 | $check_time = time(); |
1102 | 1045 | ||
1103 | # checks if the cached version file exists | 1046 | # checks if the cached version file exists |
1104 | if (file_exists($cache_file) && (filemtime($cache_file) > (time() - 86400 ))) { | 1047 | if (file_exists($cache_file) && (filemtime($cache_file) > (time() - 86400 ))) { |
1105 | $version = file_get_contents($cache_file); | 1048 | $version = file_get_contents($cache_file); |
1106 | } else { | 1049 | $check_time = filemtime($cache_file); |
1107 | $version = file_get_contents('http://static.wallabag.org/versions/' . $which); | 1050 | } else { |
1108 | file_put_contents($cache_file, $version, LOCK_EX); | 1051 | $version = file_get_contents('http://static.wallabag.org/versions/' . $which); |
1109 | } | 1052 | file_put_contents($cache_file, $version, LOCK_EX); |
1110 | return $version; | 1053 | } |
1054 | return array($version, $check_time); | ||
1111 | } | 1055 | } |
1112 | 1056 | ||
1113 | public function generateToken() | 1057 | public function generateToken() |
1114 | { | 1058 | { |
1115 | if (ini_get('open_basedir') === '') { | 1059 | if (ini_get('open_basedir') === '') { |
1116 | $token = substr(base64_encode(file_get_contents('/dev/urandom', false, null, 0, 20)), 0, 15); | 1060 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { |
1117 | } | 1061 | echo 'This is a server using Windows!'; |
1118 | else { | 1062 | // alternative to /dev/urandom for Windows |
1119 | $token = substr(base64_encode(uniqid(mt_rand(), true)), 0, 20); | 1063 | $token = substr(base64_encode(uniqid(mt_rand(), true)), 0, 20); |
1120 | } | 1064 | } else { |
1121 | 1065 | $token = substr(base64_encode(file_get_contents('/dev/urandom', false, null, 0, 20)), 0, 15); | |
1122 | $token = str_replace('+', '', $token); | 1066 | } |
1123 | $this->store->updateUserConfig($this->user->getId(), 'token', $token); | 1067 | } |
1124 | $currentConfig = $_SESSION['poche_user']->config; | 1068 | else { |
1125 | $currentConfig['token'] = $token; | 1069 | $token = substr(base64_encode(uniqid(mt_rand(), true)), 0, 20); |
1126 | $_SESSION['poche_user']->setConfig($currentConfig); | 1070 | } |
1127 | Tools::redirect(); | 1071 | |
1072 | $token = str_replace('+', '', $token); | ||
1073 | $this->store->updateUserConfig($this->user->getId(), 'token', $token); | ||
1074 | $currentConfig = $_SESSION['poche_user']->config; | ||
1075 | $currentConfig['token'] = $token; | ||
1076 | $_SESSION['poche_user']->setConfig($currentConfig); | ||
1077 | Tools::redirect(); | ||
1128 | } | 1078 | } |
1129 | 1079 | ||
1130 | public function generateFeeds($token, $user_id, $tag_id, $type = 'home') | 1080 | public function generateFeeds($token, $user_id, $tag_id, $type = 'home') |
@@ -1132,8 +1082,11 @@ class Poche | |||
1132 | $allowed_types = array('home', 'fav', 'archive', 'tag'); | 1082 | $allowed_types = array('home', 'fav', 'archive', 'tag'); |
1133 | $config = $this->store->getConfigUser($user_id); | 1083 | $config = $this->store->getConfigUser($user_id); |
1134 | 1084 | ||
1135 | if (!in_array($type, $allowed_types) || | 1085 | if ($config == null) { |
1136 | $token != $config['token']) { | 1086 | die(sprintf(_('User with this id (%d) does not exist.'), $user_id)); |
1087 | } | ||
1088 | |||
1089 | if (!in_array($type, $allowed_types) || $token != $config['token']) { | ||
1137 | die(_('Uh, there is a problem while generating feeds.')); | 1090 | die(_('Uh, there is a problem while generating feeds.')); |
1138 | } | 1091 | } |
1139 | // Check the token | 1092 | // Check the token |
@@ -1141,8 +1094,9 @@ class Poche | |||
1141 | $feed = new FeedWriter(RSS2); | 1094 | $feed = new FeedWriter(RSS2); |
1142 | $feed->setTitle('wallabag — ' . $type . ' feed'); | 1095 | $feed->setTitle('wallabag — ' . $type . ' feed'); |
1143 | $feed->setLink(Tools::getPocheUrl()); | 1096 | $feed->setLink(Tools::getPocheUrl()); |
1144 | $feed->setChannelElement('updated', date(DATE_RSS , time())); | 1097 | $feed->setChannelElement('pubDate', date(DATE_RSS , time())); |
1145 | $feed->setChannelElement('author', 'wallabag'); | 1098 | $feed->setChannelElement('generator', 'wallabag'); |
1099 | $feed->setDescription('wallabag ' . $type . ' elements'); | ||
1146 | 1100 | ||
1147 | if ($type == 'tag') { | 1101 | if ($type == 'tag') { |
1148 | $entries = $this->store->retrieveEntriesByTag($tag_id, $user_id); | 1102 | $entries = $this->store->retrieveEntriesByTag($tag_id, $user_id); |
@@ -1155,7 +1109,8 @@ class Poche | |||
1155 | foreach ($entries as $entry) { | 1109 | foreach ($entries as $entry) { |
1156 | $newItem = $feed->createNewItem(); | 1110 | $newItem = $feed->createNewItem(); |
1157 | $newItem->setTitle($entry['title']); | 1111 | $newItem->setTitle($entry['title']); |
1158 | $newItem->setLink(Tools::getPocheUrl() . '?view=view&id=' . $entry['id']); | 1112 | $newItem->setSource(Tools::getPocheUrl() . '?view=view&id=' . $entry['id']); |
1113 | $newItem->setLink($entry['url']); | ||
1159 | $newItem->setDate(time()); | 1114 | $newItem->setDate(time()); |
1160 | $newItem->setDescription($entry['content']); | 1115 | $newItem->setDescription($entry['content']); |
1161 | $feed->addItem($newItem); | 1116 | $feed->addItem($newItem); |
@@ -1181,4 +1136,132 @@ class Poche | |||
1181 | $this->messages->add('s', _('Cache deleted.')); | 1136 | $this->messages->add('s', _('Cache deleted.')); |
1182 | Tools::redirect(); | 1137 | Tools::redirect(); |
1183 | } | 1138 | } |
1139 | |||
1140 | /** | ||
1141 | * return new purifier object with actual config | ||
1142 | */ | ||
1143 | protected function getPurifier() { | ||
1144 | $config = HTMLPurifier_Config::createDefault(); | ||
1145 | $config->set('Cache.SerializerPath', CACHE); | ||
1146 | $config->set('HTML.SafeIframe', true); | ||
1147 | |||
1148 | //allow YouTube, Vimeo and dailymotion videos | ||
1149 | $config->set('URI.SafeIframeRegexp', '%^(https?:)?//(www\.youtube(?:-nocookie)?\.com/embed/|player\.vimeo\.com/video/|www\.dailymotion\.com/embed/video/)%'); | ||
1150 | |||
1151 | return new HTMLPurifier($config); | ||
1152 | } | ||
1153 | |||
1154 | /** | ||
1155 | * handle epub | ||
1156 | */ | ||
1157 | public function createEpub() { | ||
1158 | |||
1159 | switch ($_GET['method']) { | ||
1160 | case 'id': | ||
1161 | $entryID = filter_var($_GET['id'],FILTER_SANITIZE_NUMBER_INT); | ||
1162 | $entry = $this->store->retrieveOneById($entryID, $this->user->getId()); | ||
1163 | $entries = array($entry); | ||
1164 | $bookTitle = $entry['title']; | ||
1165 | $bookFileName = substr($bookTitle, 0, 200); | ||
1166 | break; | ||
1167 | case 'all': | ||
1168 | $entries = $this->store->retrieveAll($this->user->getId()); | ||
1169 | $bookTitle = sprintf(_('All my articles on '), date(_('d.m.y'))); #translatable because each country has it's own date format system | ||
1170 | $bookFileName = _('Allarticles') . date(_('dmY')); | ||
1171 | break; | ||
1172 | case 'tag': | ||
1173 | $tag = filter_var($_GET['tag'],FILTER_SANITIZE_STRING); | ||
1174 | $tags_id = $this->store->retrieveAllTags($this->user->getId(),$tag); | ||
1175 | $tag_id = $tags_id[0]["id"]; // we take the first result, which is supposed to match perfectly. There must be a workaround. | ||
1176 | $entries = $this->store->retrieveEntriesByTag($tag_id,$this->user->getId()); | ||
1177 | $bookTitle = sprintf(_('Articles tagged %s'),$tag); | ||
1178 | $bookFileName = substr(sprintf(_('Tag %s'),$tag), 0, 200); | ||
1179 | break; | ||
1180 | case 'category': | ||
1181 | $category = filter_var($_GET['category'],FILTER_SANITIZE_STRING); | ||
1182 | $entries = $this->store->getEntriesByView($category,$this->user->getId()); | ||
1183 | $bookTitle = sprintf(_('All articles in category %s'), $category); | ||
1184 | $bookFileName = substr(sprintf(_('Category %s'),$category), 0, 200); | ||
1185 | break; | ||
1186 | case 'search': | ||
1187 | $search = filter_var($_GET['search'],FILTER_SANITIZE_STRING); | ||
1188 | $entries = $this->store->search($search,$this->user->getId()); | ||
1189 | $bookTitle = sprintf(_('All articles for search %s'), $search); | ||
1190 | $bookFileName = substr(sprintf(_('Search %s'), $search), 0, 200); | ||
1191 | break; | ||
1192 | case 'default': | ||
1193 | die(_('Uh, there is a problem while generating epub.')); | ||
1194 | |||
1195 | } | ||
1196 | |||
1197 | $content_start = | ||
1198 | "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" | ||
1199 | . "<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n" | ||
1200 | . "<head>" | ||
1201 | . "<meta http-equiv=\"Default-Style\" content=\"text/html; charset=utf-8\" />\n" | ||
1202 | . "<title>wallabag articles book</title>\n" | ||
1203 | . "</head>\n" | ||
1204 | . "<body>\n"; | ||
1205 | |||
1206 | $bookEnd = "</body>\n</html>\n"; | ||
1207 | |||
1208 | $log = new Logger("wallabag", TRUE); | ||
1209 | $fileDir = CACHE; | ||
1210 | |||
1211 | $book = new EPub(EPub::BOOK_VERSION_EPUB3, DEBUG_POCHE); | ||
1212 | $log->logLine("new EPub()"); | ||
1213 | $log->logLine("EPub class version: " . EPub::VERSION); | ||
1214 | $log->logLine("EPub Req. Zip version: " . EPub::REQ_ZIP_VERSION); | ||
1215 | $log->logLine("Zip version: " . Zip::VERSION); | ||
1216 | $log->logLine("getCurrentServerURL: " . $book->getCurrentServerURL()); | ||
1217 | $log->logLine("getCurrentPageURL..: " . $book->getCurrentPageURL()); | ||
1218 | |||
1219 | $book->setTitle(_('wallabag\'s articles')); | ||
1220 | $book->setIdentifier("http://$_SERVER[HTTP_HOST]", EPub::IDENTIFIER_URI); // Could also be the ISBN number, prefered for published books, or a UUID. | ||
1221 | //$book->setLanguage("en"); // Not needed, but included for the example, Language is mandatory, but EPub defaults to "en". Use RFC3066 Language codes, such as "en", "da", "fr" etc. | ||
1222 | $book->setDescription(_("Some articles saved on my wallabag")); | ||
1223 | $book->setAuthor("wallabag","wallabag"); | ||
1224 | $book->setPublisher("wallabag","wallabag"); // I hope this is a non existant address :) | ||
1225 | $book->setDate(time()); // Strictly not needed as the book date defaults to time(). | ||
1226 | //$book->setRights("Copyright and licence information specific for the book."); // As this is generated, this _could_ contain the name or licence information of the user who purchased the book, if needed. If this is used that way, the identifier must also be made unique for the book. | ||
1227 | $book->setSourceURL("http://$_SERVER[HTTP_HOST]"); | ||
1228 | |||
1229 | $book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, "PHP"); | ||
1230 | $book->addDublinCoreMetadata(DublinCore::CONTRIBUTOR, "wallabag"); | ||
1231 | |||
1232 | $cssData = "body {\n margin-left: .5em;\n margin-right: .5em;\n text-align: justify;\n}\n\np {\n font-family: serif;\n font-size: 10pt;\n text-align: justify;\n text-indent: 1em;\n margin-top: 0px;\n margin-bottom: 1ex;\n}\n\nh1, h2 {\n font-family: sans-serif;\n font-style: italic;\n text-align: center;\n background-color: #6b879c;\n color: white;\n width: 100%;\n}\n\nh1 {\n margin-bottom: 2px;\n}\n\nh2 {\n margin-top: -2px;\n margin-bottom: 2px;\n}\n"; | ||
1233 | |||
1234 | $log->logLine("Add Cover"); | ||
1235 | |||
1236 | $fullTitle = "<h1> " . $bookTitle . "</h1>\n"; | ||
1237 | |||
1238 | $book->setCoverImage("Cover.png", file_get_contents("themes/baggy/img/apple-touch-icon-152.png"), "image/png", $fullTitle); | ||
1239 | |||
1240 | $cover = $content_start . '<div style="text-align:center;"><p>' . _('Produced by wallabag with PHPePub') . '</p><p>'. _('Please open <a href="https://github.com/wallabag/wallabag/issues" >an issue</a> if you have trouble with the display of this E-Book on your device.') . '</p></div>' . $bookEnd; | ||
1241 | |||
1242 | //$book->addChapter("Table of Contents", "TOC.xhtml", NULL, false, EPub::EXTERNAL_REF_IGNORE); | ||
1243 | $book->addChapter("Notices", "Cover2.html", $cover); | ||
1244 | |||
1245 | $book->buildTOC(); | ||
1246 | |||
1247 | foreach ($entries as $entry) { //set tags as subjects | ||
1248 | $tags = $this->store->retrieveTagsByEntry($entry['id']); | ||
1249 | foreach ($tags as $tag) { | ||
1250 | $book->setSubject($tag['value']); | ||
1251 | } | ||
1252 | |||
1253 | $log->logLine("Set up parameters"); | ||
1254 | |||
1255 | $chapter = $content_start . $entry['content'] . $bookEnd; | ||
1256 | $book->addChapter($entry['title'], htmlspecialchars($entry['title']) . ".html", $chapter, true, EPub::EXTERNAL_REF_ADD); | ||
1257 | $log->logLine("Added chapter " . $entry['title']); | ||
1258 | } | ||
1259 | |||
1260 | if (DEBUG_POCHE) { | ||
1261 | $epuplog = $book->getLog(); | ||
1262 | $book->addChapter("Log", "Log.html", $content_start . $log->getLog() . "\n</pre>" . $bookEnd); // log generation | ||
1263 | } | ||
1264 | $book->finalize(); | ||
1265 | $zipData = $book->sendBook($bookFileName); | ||
1266 | } | ||
1184 | } | 1267 | } |
diff --git a/inc/poche/Tools.class.php b/inc/poche/Tools.class.php index 4ed28ed1..cc01f403 100644..100755 --- a/inc/poche/Tools.class.php +++ b/inc/poche/Tools.class.php | |||
@@ -7,7 +7,7 @@ | |||
7 | * @copyright 2013 | 7 | * @copyright 2013 |
8 | * @license http://www.wtfpl.net/ see COPYING file | 8 | * @license http://www.wtfpl.net/ see COPYING file |
9 | */ | 9 | */ |
10 | 10 | ||
11 | class Tools | 11 | class Tools |
12 | { | 12 | { |
13 | public static function initPhp() | 13 | public static function initPhp() |
@@ -18,8 +18,6 @@ class Tools | |||
18 | die(_('Oops, it seems you don\'t have PHP 5.')); | 18 | die(_('Oops, it seems you don\'t have PHP 5.')); |
19 | } | 19 | } |
20 | 20 | ||
21 | error_reporting(E_ALL); | ||
22 | |||
23 | function stripslashesDeep($value) { | 21 | function stripslashesDeep($value) { |
24 | return is_array($value) | 22 | return is_array($value) |
25 | ? array_map('stripslashesDeep', $value) | 23 | ? array_map('stripslashesDeep', $value) |
@@ -42,7 +40,7 @@ class Tools | |||
42 | && (strtolower($_SERVER['HTTPS']) == 'on')) | 40 | && (strtolower($_SERVER['HTTPS']) == 'on')) |
43 | || (isset($_SERVER["SERVER_PORT"]) | 41 | || (isset($_SERVER["SERVER_PORT"]) |
44 | && $_SERVER["SERVER_PORT"] == '443') // HTTPS detection. | 42 | && $_SERVER["SERVER_PORT"] == '443') // HTTPS detection. |
45 | || (isset($_SERVER["SERVER_PORT"]) //Custom HTTPS port detection | 43 | || (isset($_SERVER["SERVER_PORT"]) //Custom HTTPS port detection |
46 | && $_SERVER["SERVER_PORT"] == SSL_PORT) | 44 | && $_SERVER["SERVER_PORT"] == SSL_PORT) |
47 | || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) | 45 | || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) |
48 | && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'); | 46 | && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'); |
@@ -59,8 +57,14 @@ class Tools | |||
59 | return $scriptname; | 57 | return $scriptname; |
60 | } | 58 | } |
61 | 59 | ||
60 | $host = (isset($_SERVER['HTTP_X_FORWARDED_HOST']) ? $_SERVER['HTTP_X_FORWARDED_HOST'] : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'])); | ||
61 | |||
62 | if (strpos($host, ':') !== false) { | ||
63 | $serverport = ''; | ||
64 | } | ||
65 | |||
62 | return 'http' . ($https ? 's' : '') . '://' | 66 | return 'http' . ($https ? 's' : '') . '://' |
63 | . $_SERVER["HTTP_HOST"] . $serverport . $scriptname; | 67 | . $host . $serverport . $scriptname; |
64 | } | 68 | } |
65 | 69 | ||
66 | public static function redirect($url = '') | 70 | public static function redirect($url = '') |
@@ -148,7 +152,7 @@ class Tools | |||
148 | ); | 152 | ); |
149 | 153 | ||
150 | # only download page lesser than 4MB | 154 | # only download page lesser than 4MB |
151 | $data = @file_get_contents($url, false, $context, -1, 4000000); | 155 | $data = @file_get_contents($url, false, $context, -1, 4000000); |
152 | 156 | ||
153 | if (isset($http_response_header) and isset($http_response_header[0])) { | 157 | if (isset($http_response_header) and isset($http_response_header[0])) { |
154 | $httpcodeOK = isset($http_response_header) and isset($http_response_header[0]) and ((strpos($http_response_header[0], '200 OK') !== FALSE) or (strpos($http_response_header[0], '301 Moved Permanently') !== FALSE)); | 158 | $httpcodeOK = isset($http_response_header) and isset($http_response_header[0]) and ((strpos($http_response_header[0], '200 OK') !== FALSE) or (strpos($http_response_header[0], '301 Moved Permanently') !== FALSE)); |
@@ -193,14 +197,14 @@ class Tools | |||
193 | 197 | ||
194 | public static function logm($message) | 198 | public static function logm($message) |
195 | { | 199 | { |
196 | if (DEBUG_POCHE) { | 200 | if (DEBUG_POCHE && php_sapi_name() != 'cli') { |
197 | $t = strval(date('Y/m/d_H:i:s')) . ' - ' . $_SERVER["REMOTE_ADDR"] . ' - ' . strval($message) . "\n"; | 201 | $t = strval(date('Y/m/d_H:i:s')) . ' - ' . $_SERVER["REMOTE_ADDR"] . ' - ' . strval($message) . "\n"; |
198 | file_put_contents(CACHE . '/log.txt', $t, FILE_APPEND); | 202 | file_put_contents(CACHE . '/log.txt', $t, FILE_APPEND); |
199 | error_log('DEBUG POCHE : ' . $message); | 203 | error_log('DEBUG POCHE : ' . $message); |
200 | } | 204 | } |
201 | } | 205 | } |
202 | 206 | ||
203 | public static function encodeString($string) | 207 | public static function encodeString($string) |
204 | { | 208 | { |
205 | return sha1($string . SALT); | 209 | return sha1($string . SALT); |
206 | } | 210 | } |
@@ -212,7 +216,7 @@ class Tools | |||
212 | 216 | ||
213 | public static function getDomain($url) | 217 | public static function getDomain($url) |
214 | { | 218 | { |
215 | return parse_url($url, PHP_URL_HOST); | 219 | return parse_url($url, PHP_URL_HOST); |
216 | } | 220 | } |
217 | 221 | ||
218 | public static function getReadingTime($text) { | 222 | public static function getReadingTime($text) { |
@@ -241,7 +245,6 @@ class Tools | |||
241 | } | 245 | } |
242 | } | 246 | } |
243 | 247 | ||
244 | |||
245 | public static function download_db() { | 248 | public static function download_db() { |
246 | header('Content-Disposition: attachment; filename="poche.sqlite.gz"'); | 249 | header('Content-Disposition: attachment; filename="poche.sqlite.gz"'); |
247 | self::status(200); | 250 | self::status(200); |
@@ -252,4 +255,74 @@ class Tools | |||
252 | 255 | ||
253 | exit; | 256 | exit; |
254 | } | 257 | } |
258 | |||
259 | public static function getPageContent(Url $url) | ||
260 | { | ||
261 | // Saving and clearing context | ||
262 | $REAL = array(); | ||
263 | foreach( $GLOBALS as $key => $value ) { | ||
264 | if( $key != 'GLOBALS' && $key != '_SESSION' && $key != 'HTTP_SESSION_VARS' ) { | ||
265 | $GLOBALS[$key] = array(); | ||
266 | $REAL[$key] = $value; | ||
267 | } | ||
268 | } | ||
269 | // Saving and clearing session | ||
270 | if ( isset($_SESSION) ) { | ||
271 | $REAL_SESSION = array(); | ||
272 | foreach( $_SESSION as $key => $value ) { | ||
273 | $REAL_SESSION[$key] = $value; | ||
274 | unset($_SESSION[$key]); | ||
275 | } | ||
276 | } | ||
277 | |||
278 | // Running code in different context | ||
279 | $scope = function() { | ||
280 | extract( func_get_arg(1) ); | ||
281 | $_GET = $_REQUEST = array( | ||
282 | "url" => $url->getUrl(), | ||
283 | "max" => 5, | ||
284 | "links" => "preserve", | ||
285 | "exc" => "", | ||
286 | "format" => "json", | ||
287 | "submit" => "Create Feed" | ||
288 | ); | ||
289 | ob_start(); | ||
290 | require func_get_arg(0); | ||
291 | $json = ob_get_contents(); | ||
292 | ob_end_clean(); | ||
293 | return $json; | ||
294 | }; | ||
295 | $json = $scope( "inc/3rdparty/makefulltextfeed.php", array("url" => $url) ); | ||
296 | |||
297 | // Clearing and restoring context | ||
298 | foreach( $GLOBALS as $key => $value ) { | ||
299 | if( $key != "GLOBALS" && $key != "_SESSION" ) { | ||
300 | unset($GLOBALS[$key]); | ||
301 | } | ||
302 | } | ||
303 | foreach( $REAL as $key => $value ) { | ||
304 | $GLOBALS[$key] = $value; | ||
305 | } | ||
306 | // Clearing and restoring session | ||
307 | if ( isset($REAL_SESSION) ) { | ||
308 | foreach( $_SESSION as $key => $value ) { | ||
309 | unset($_SESSION[$key]); | ||
310 | } | ||
311 | foreach( $REAL_SESSION as $key => $value ) { | ||
312 | $_SESSION[$key] = $value; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | return json_decode($json, true); | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * Returns whether we handle an AJAX (XMLHttpRequest) request. | ||
321 | * @return boolean whether we handle an AJAX (XMLHttpRequest) request. | ||
322 | */ | ||
323 | public static function isAjaxRequest() | ||
324 | { | ||
325 | return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest'; | ||
326 | } | ||
327 | |||
255 | } | 328 | } |
diff --git a/inc/poche/config.inc.default.php b/inc/poche/config.inc.default.php new file mode 100755 index 00000000..95f727c6 --- /dev/null +++ b/inc/poche/config.inc.default.php | |||
@@ -0,0 +1,68 @@ | |||
1 | <?php | ||
2 | /** | ||
3 | * wallabag, self hostable application allowing you to not miss any content anymore | ||
4 | * | ||
5 | * @category wallabag | ||
6 | * @author Nicolas Lœuillet <nicolas@loeuillet.org> | ||
7 | * @copyright 2013 | ||
8 | * @license http://www.wtfpl.net/ see COPYING file | ||
9 | */ | ||
10 | |||
11 | @define ('SALT', ''); # put a strong string here | ||
12 | @define ('LANG', 'en_EN.utf8'); | ||
13 | |||
14 | @define ('STORAGE', 'sqlite'); # postgres, mysql or sqlite | ||
15 | |||
16 | @define ('STORAGE_SQLITE', ROOT . '/db/poche.sqlite'); # if you are using sqlite, where the database file is located | ||
17 | |||
18 | # only for postgres & mysql | ||
19 | @define ('STORAGE_SERVER', 'localhost'); | ||
20 | @define ('STORAGE_DB', 'poche'); | ||
21 | @define ('STORAGE_USER', 'poche'); | ||
22 | @define ('STORAGE_PASSWORD', 'poche'); | ||
23 | |||
24 | ################################################################################# | ||
25 | # Do not trespass unless you know what you are doing | ||
26 | ################################################################################# | ||
27 | |||
28 | // Change this if not using the standart port for SSL - i.e you server is behind sslh | ||
29 | @define ('SSL_PORT', 443); | ||
30 | |||
31 | @define ('MODE_DEMO', FALSE); | ||
32 | @define ('DEBUG_POCHE', FALSE); | ||
33 | |||
34 | //default level of error reporting in application. Developers should override it in their config.inc.php: set to E_ALL. | ||
35 | @define ('ERROR_REPORTING', E_ALL & ~E_NOTICE); | ||
36 | |||
37 | @define ('DOWNLOAD_PICTURES', FALSE); # This can slow down the process of adding articles | ||
38 | @define ('REGENERATE_PICTURES_QUALITY', 75); | ||
39 | @define ('CONVERT_LINKS_FOOTNOTES', FALSE); | ||
40 | @define ('REVERT_FORCED_PARAGRAPH_ELEMENTS', FALSE); | ||
41 | @define ('SHARE_TWITTER', TRUE); | ||
42 | @define ('SHARE_MAIL', TRUE); | ||
43 | @define ('SHARE_SHAARLI', FALSE); | ||
44 | @define ('SHAARLI_URL', 'http://myshaarliurl.com'); | ||
45 | @define ('FLATTR', TRUE); | ||
46 | @define ('FLATTR_API', 'https://api.flattr.com/rest/v2/things/lookup/?url='); | ||
47 | @define ('NOT_FLATTRABLE', '0'); | ||
48 | @define ('FLATTRABLE', '1'); | ||
49 | @define ('FLATTRED', '2'); | ||
50 | // display or not print link in article view | ||
51 | @define ('SHOW_PRINTLINK', '1'); | ||
52 | // display or not percent of read in article view. Affects only default theme. | ||
53 | @define ('SHOW_READPERCENT', '1'); | ||
54 | @define ('ABS_PATH', 'assets/'); | ||
55 | |||
56 | @define ('DEFAULT_THEME', 'baggy'); | ||
57 | |||
58 | @define ('THEME', ROOT . '/themes'); | ||
59 | @define ('LOCALE', ROOT . '/locale'); | ||
60 | @define ('CACHE', ROOT . '/cache'); | ||
61 | |||
62 | @define ('PAGINATION', '10'); | ||
63 | |||
64 | //limit for download of articles during import | ||
65 | @define ('IMPORT_LIMIT', 5); | ||
66 | //delay between downloads (in sec) | ||
67 | @define ('IMPORT_DELAY', 5); | ||
68 | |||
diff --git a/inc/poche/config.inc.php.new b/inc/poche/config.inc.php.new deleted file mode 100755 index 8d52497b..00000000 --- a/inc/poche/config.inc.php.new +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
1 | <?php | ||
2 | /** | ||
3 | * wallabag, self hostable application allowing you to not miss any content anymore | ||
4 | * | ||
5 | * @category wallabag | ||
6 | * @author Nicolas Lœuillet <nicolas@loeuillet.org> | ||
7 | * @copyright 2013 | ||
8 | * @license http://www.wtfpl.net/ see COPYING file | ||
9 | */ | ||
10 | |||
11 | define ('SALT', ''); # put a strong string here | ||
12 | define ('LANG', 'en_EN.utf8'); | ||
13 | |||
14 | define ('STORAGE', 'sqlite'); # postgres, mysql or sqlite | ||
15 | |||
16 | define ('STORAGE_SQLITE', ROOT . '/db/poche.sqlite'); # if you are using sqlite, where the database file is located | ||
17 | |||
18 | # only for postgres & mysql | ||
19 | define ('STORAGE_SERVER', 'localhost'); | ||
20 | define ('STORAGE_DB', 'poche'); | ||
21 | define ('STORAGE_USER', 'poche'); | ||
22 | define ('STORAGE_PASSWORD', 'poche'); | ||
23 | |||
24 | ################################################################################# | ||
25 | # Do not trespass unless you know what you are doing | ||
26 | ################################################################################# | ||
27 | |||
28 | // Change this if not using the standart port for SSL - i.e you server is behind sslh | ||
29 | define ('SSL_PORT', 443); | ||
30 | |||
31 | define ('MODE_DEMO', FALSE); | ||
32 | define ('DEBUG_POCHE', FALSE); | ||
33 | define ('DOWNLOAD_PICTURES', FALSE); | ||
34 | define ('CONVERT_LINKS_FOOTNOTES', FALSE); | ||
35 | define ('REVERT_FORCED_PARAGRAPH_ELEMENTS', FALSE); | ||
36 | define ('SHARE_TWITTER', TRUE); | ||
37 | define ('SHARE_MAIL', TRUE); | ||
38 | define ('SHARE_SHAARLI', FALSE); | ||
39 | define ('SHAARLI_URL', 'http://myshaarliurl.com'); | ||
40 | define ('FLATTR', TRUE); | ||
41 | define ('FLATTR_API', 'https://api.flattr.com/rest/v2/things/lookup/?url='); | ||
42 | define ('NOT_FLATTRABLE', '0'); | ||
43 | define ('FLATTRABLE', '1'); | ||
44 | define ('FLATTRED', '2'); | ||
45 | define ('ABS_PATH', 'assets/'); | ||
46 | |||
47 | define ('DEFAULT_THEME', 'baggy'); | ||
48 | |||
49 | define ('THEME', ROOT . '/themes'); | ||
50 | define ('LOCALE', ROOT . '/locale'); | ||
51 | define ('CACHE', ROOT . '/cache'); | ||
52 | |||
53 | define ('PAGINATION', '10'); | ||
54 | |||
55 | define ('POCKET_FILE', '/ril_export.html'); | ||
56 | define ('READABILITY_FILE', '/readability'); | ||
57 | define ('INSTAPAPER_FILE', '/instapaper-export.html'); | ||
58 | define ('POCHE_FILE', '/poche-export'); | ||
59 | |||
60 | define ('IMPORT_POCKET_FILE', ROOT . POCKET_FILE); | ||
61 | define ('IMPORT_READABILITY_FILE', ROOT . READABILITY_FILE); | ||
62 | define ('IMPORT_INSTAPAPER_FILE', ROOT . INSTAPAPER_FILE); | ||
63 | define ('IMPORT_POCHE_FILE', ROOT . POCHE_FILE); \ No newline at end of file | ||
diff --git a/inc/poche/global.inc.php b/inc/poche/global.inc.php index d22b0588..8cf86d03 100644..100755 --- a/inc/poche/global.inc.php +++ b/inc/poche/global.inc.php | |||
@@ -31,6 +31,11 @@ require_once INCLUDES . '/3rdparty/FlattrItem.class.php'; | |||
31 | 31 | ||
32 | require_once INCLUDES . '/3rdparty/htmlpurifier/HTMLPurifier.auto.php'; | 32 | require_once INCLUDES . '/3rdparty/htmlpurifier/HTMLPurifier.auto.php'; |
33 | 33 | ||
34 | # epub library | ||
35 | require_once INCLUDES . '/3rdparty/libraries/PHPePub/Logger.php'; | ||
36 | require_once INCLUDES . '/3rdparty/libraries/PHPePub/EPub.php'; | ||
37 | require_once INCLUDES . '/3rdparty/libraries/PHPePub/EPubChapterSplitter.php'; | ||
38 | |||
34 | # Composer its autoloader for automatically loading Twig | 39 | # Composer its autoloader for automatically loading Twig |
35 | if (! file_exists(ROOT . '/vendor/autoload.php')) { | 40 | if (! file_exists(ROOT . '/vendor/autoload.php')) { |
36 | Poche::$canRenderTemplates = false; | 41 | Poche::$canRenderTemplates = false; |
@@ -38,11 +43,12 @@ if (! file_exists(ROOT . '/vendor/autoload.php')) { | |||
38 | require_once ROOT . '/vendor/autoload.php'; | 43 | require_once ROOT . '/vendor/autoload.php'; |
39 | } | 44 | } |
40 | 45 | ||
41 | # system configuration; database credentials et cetera | 46 | # system configuration; database credentials et caetera |
42 | if (! file_exists(INCLUDES . '/poche/config.inc.php')) { | 47 | if (! file_exists(INCLUDES . '/poche/config.inc.php')) { |
43 | Poche::$configFileAvailable = false; | 48 | Poche::$configFileAvailable = false; |
44 | } else { | 49 | } else { |
45 | require_once INCLUDES . '/poche/config.inc.php'; | 50 | require_once INCLUDES . '/poche/config.inc.php'; |
51 | require_once INCLUDES . '/poche/config.inc.default.php'; | ||
46 | } | 52 | } |
47 | 53 | ||
48 | if (Poche::$configFileAvailable && DOWNLOAD_PICTURES) { | 54 | if (Poche::$configFileAvailable && DOWNLOAD_PICTURES) { |
diff --git a/inc/poche/pochePictures.php b/inc/poche/pochePictures.php index e4b0b160..7c319a85 100644 --- a/inc/poche/pochePictures.php +++ b/inc/poche/pochePictures.php | |||
@@ -14,6 +14,7 @@ | |||
14 | function filtre_picture($content, $url, $id) | 14 | function filtre_picture($content, $url, $id) |
15 | { | 15 | { |
16 | $matches = array(); | 16 | $matches = array(); |
17 | $processing_pictures = array(); // list of processing image to avoid processing the same pictures twice | ||
17 | preg_match_all('#<\s*(img)[^>]+src="([^"]*)"[^>]*>#Si', $content, $matches, PREG_SET_ORDER); | 18 | preg_match_all('#<\s*(img)[^>]+src="([^"]*)"[^>]*>#Si', $content, $matches, PREG_SET_ORDER); |
18 | foreach($matches as $i => $link) { | 19 | foreach($matches as $i => $link) { |
19 | $link[1] = trim($link[1]); | 20 | $link[1] = trim($link[1]); |
@@ -22,8 +23,17 @@ function filtre_picture($content, $url, $id) | |||
22 | $filename = basename(parse_url($absolute_path, PHP_URL_PATH)); | 23 | $filename = basename(parse_url($absolute_path, PHP_URL_PATH)); |
23 | $directory = create_assets_directory($id); | 24 | $directory = create_assets_directory($id); |
24 | $fullpath = $directory . '/' . $filename; | 25 | $fullpath = $directory . '/' . $filename; |
25 | download_pictures($absolute_path, $fullpath); | 26 | |
26 | $content = str_replace($matches[$i][2], $fullpath, $content); | 27 | if (in_array($absolute_path, $processing_pictures) === true) { |
28 | // replace picture's URL only if processing is OK : already processing -> go to next picture | ||
29 | continue; | ||
30 | } | ||
31 | |||
32 | if (download_pictures($absolute_path, $fullpath) === true) { | ||
33 | $content = str_replace($matches[$i][2], $fullpath, $content); | ||
34 | } | ||
35 | |||
36 | $processing_pictures[] = $absolute_path; | ||
27 | } | 37 | } |
28 | 38 | ||
29 | } | 39 | } |
@@ -64,17 +74,55 @@ function get_absolute_link($relative_link, $url) { | |||
64 | 74 | ||
65 | /** | 75 | /** |
66 | * Téléchargement des images | 76 | * Téléchargement des images |
77 | * | ||
78 | * @return bool true if the download and processing is OK, false else | ||
67 | */ | 79 | */ |
68 | function download_pictures($absolute_path, $fullpath) | 80 | function download_pictures($absolute_path, $fullpath) |
69 | { | 81 | { |
70 | $rawdata = Tools::getFile($absolute_path); | 82 | $rawdata = Tools::getFile($absolute_path); |
83 | $fullpath = urldecode($fullpath); | ||
71 | 84 | ||
72 | if(file_exists($fullpath)) { | 85 | if(file_exists($fullpath)) { |
73 | unlink($fullpath); | 86 | unlink($fullpath); |
74 | } | 87 | } |
75 | $fp = fopen($fullpath, 'x'); | 88 | |
76 | fwrite($fp, $rawdata); | 89 | // check extension |
77 | fclose($fp); | 90 | $file_ext = strrchr($fullpath, '.'); |
91 | $whitelist = array(".jpg",".jpeg",".gif",".png"); | ||
92 | if (!(in_array($file_ext, $whitelist))) { | ||
93 | Tools::logm('processed image with not allowed extension. Skipping ' . $fullpath); | ||
94 | return false; | ||
95 | } | ||
96 | |||
97 | // check headers | ||
98 | $imageinfo = getimagesize($absolute_path); | ||
99 | if ($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg'&& $imageinfo['mime'] != 'image/jpg'&& $imageinfo['mime'] != 'image/png') { | ||
100 | Tools::logm('processed image with bad header. Skipping ' . $fullpath); | ||
101 | return false; | ||
102 | } | ||
103 | |||
104 | // regenerate image | ||
105 | $im = imagecreatefromstring($rawdata); | ||
106 | if ($im === false) { | ||
107 | Tools::logm('error while regenerating image ' . $fullpath); | ||
108 | return false; | ||
109 | } | ||
110 | |||
111 | switch ($imageinfo['mime']) { | ||
112 | case 'image/gif': | ||
113 | $result = imagegif($im, $fullpath); | ||
114 | break; | ||
115 | case 'image/jpeg': | ||
116 | case 'image/jpg': | ||
117 | $result = imagejpeg($im, $fullpath, REGENERATE_PICTURES_QUALITY); | ||
118 | break; | ||
119 | case 'image/png': | ||
120 | $result = imagepng($im, $fullpath, ceil(REGENERATE_PICTURES_QUALITY / 100 * 9)); | ||
121 | break; | ||
122 | } | ||
123 | imagedestroy($im); | ||
124 | |||
125 | return $result; | ||
78 | } | 126 | } |
79 | 127 | ||
80 | /** | 128 | /** |