aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNicolas Lœuillet <nicolas@loeuillet.org>2014-07-11 16:03:59 +0200
committerNicolas Lœuillet <nicolas@loeuillet.org>2014-07-11 16:03:59 +0200
commit3602405ec0dbc576fce09ff9e865ba2404622080 (patch)
tree45f9de611f4936091b0ed29a6a21fa4fef9b330b
parent6400371ff93782d25cdbd50aa224c70145b3890a (diff)
downloadwallabag-3602405ec0dbc576fce09ff9e865ba2404622080.tar.gz
wallabag-3602405ec0dbc576fce09ff9e865ba2404622080.tar.zst
wallabag-3602405ec0dbc576fce09ff9e865ba2404622080.zip
WHAT. A. BIG. REFACTOR. + new license (we moved to MIT one)
-rw-r--r--COPYING.md27
-rw-r--r--CREDITS.md3
-rw-r--r--README.md5
-rw-r--r--check_setup.php14
-rw-r--r--inc/3rdparty/FlattrItem.class.php26
-rw-r--r--inc/3rdparty/Session.class.php34
-rwxr-xr-xinc/poche/Database.class.php19
-rw-r--r--inc/poche/Language.class.php114
-rwxr-xr-xinc/poche/Poche.class.php453
-rw-r--r--inc/poche/Routing.class.php149
-rw-r--r--inc/poche/Template.class.php236
-rwxr-xr-xinc/poche/Tools.class.php156
-rw-r--r--inc/poche/Url.class.php2
-rw-r--r--inc/poche/User.class.php11
-rwxr-xr-xinc/poche/config.inc.default.php2
-rwxr-xr-xinc/poche/global.inc.php23
-rw-r--r--inc/poche/pochePictures.php267
-rwxr-xr-xindex.php132
-rwxr-xr-xinstall/index.php9
-rw-r--r--wallabag_compatibility_test.php9
20 files changed, 925 insertions, 766 deletions
diff --git a/COPYING.md b/COPYING.md
index ee7d6a54..c43f619a 100644
--- a/COPYING.md
+++ b/COPYING.md
@@ -1,14 +1,19 @@
1 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 1Copyright (c) 2013-2014 Nicolas Lœuillet
2 Version 2, December 2004
3 2
4 Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> 3Permission is hereby granted, free of charge, to any person obtaining a copy
4of this software and associated documentation files (the "Software"), to deal
5in the Software without restriction, including without limitation the rights
6to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7copies of the Software, and to permit persons to whom the Software is furnished
8to do so, subject to the following conditions:
5 9
6 Everyone is permitted to copy and distribute verbatim or modified 10The above copyright notice and this permission notice shall be included in all
7 copies of this license document, and changing it is allowed as long 11copies or substantial portions of the Software.
8 as the name is changed.
9
10 DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
13 0. You just DO WHAT THE FUCK YOU WANT TO.
14 12
13THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19THE SOFTWARE. \ No newline at end of file
diff --git a/CREDITS.md b/CREDITS.md
index c892336d..7ec3cbb7 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -1,7 +1,6 @@
1wallabag is based on : 1wallabag is based on :
2* PHP Readability https://bitbucket.org/fivefilters/php-readability 2* PHP Readability https://bitbucket.org/fivefilters/php-readability
3* Full Text RSS http://code.fivefilters.org/full-text-rss/src 3* Full Text RSS http://code.fivefilters.org/full-text-rss/src
4* Encoding https://github.com/neitanod/forceutf8
5* logo by Maylis Agniel https://github.com/wallabag/logo 4* logo by Maylis Agniel https://github.com/wallabag/logo
6* icons http://icomoon.io 5* icons http://icomoon.io
7* PHP Simple HTML DOM Parser (for Pocket import) http://simplehtmldom.sourceforge.net/ 6* PHP Simple HTML DOM Parser (for Pocket import) http://simplehtmldom.sourceforge.net/
@@ -10,6 +9,6 @@ wallabag is based on :
10* Flash messages https://github.com/plasticbrain/PHP-Flash-Messages 9* Flash messages https://github.com/plasticbrain/PHP-Flash-Messages
11* Pagination https://github.com/daveismyname/pagination 10* Pagination https://github.com/daveismyname/pagination
12 11
13wallabag is developed by Nicolas Lœuillet under the Do What the Fuck You Want to Public License 12wallabag is mainly developed by Nicolas Lœuillet under the MIT License
14 13
15Contributors : https://github.com/wallabag/wallabag/graphs/contributors \ No newline at end of file 14Contributors : https://github.com/wallabag/wallabag/graphs/contributors \ No newline at end of file
diff --git a/README.md b/README.md
index 0b54dff4..38866f7a 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,6 @@ wallabag is a self hostable application allowing you to not miss any content any
4More informations on our website: [wallabag.org](http://wallabag.org) 4More informations on our website: [wallabag.org](http://wallabag.org)
5 5
6## License 6## License
7Copyright © 2010-2014 Nicolas Lœuillet <nicolas@loeuillet.org> 7Copyright © 2013-2014 Nicolas Lœuillet <nicolas@loeuillet.org>
8This work is free. You can redistribute it and/or modify it under the 8This work is free. You can redistribute it and/or modify it under the
9terms of the Do What The Fuck You Want To Public License, Version 2, 9terms of the MIT License. See the COPYING file for more details.
10as published by Sam Hocevar. See the COPYING file for more details.
diff --git a/check_setup.php b/check_setup.php
index 2b84a744..eee5d24a 100644
--- a/check_setup.php
+++ b/check_setup.php
@@ -1,5 +1,4 @@
1<?php 1<?php
2
3// PHP 5.3 minimum 2// PHP 5.3 minimum
4if (version_compare(PHP_VERSION, '5.3.3', '<')) { 3if (version_compare(PHP_VERSION, '5.3.3', '<')) {
5 die('This software require PHP 5.3.3 minimum'); 4 die('This software require PHP 5.3.3 minimum');
@@ -13,14 +12,11 @@ if (version_compare(PHP_VERSION, '5.4.0', '<')) {
13 } 12 }
14} 13}
15 14
16// Check if /cache is writeable 15$writableFolders = array('cache', 'db');
17if (! is_writable('cache')) { 16foreach ($writableFolders as $folder) {
18 die('The directory "cache" must be writeable by your web server user'); 17 if (! is_writable($folder)) {
19} 18 die('The directory "' . $folder . '" must be writeable by your web server user');
20 19 }
21// Check if /db is writeable
22if (! is_writable('db')) {
23 die('The directory "db" must be writeable by your web server user');
24} 20}
25 21
26// install folder still present, need to install wallabag 22// install folder still present, need to install wallabag
diff --git a/inc/3rdparty/FlattrItem.class.php b/inc/3rdparty/FlattrItem.class.php
index 711b4ee0..5cf9e5fc 100644
--- a/inc/3rdparty/FlattrItem.class.php
+++ b/inc/3rdparty/FlattrItem.class.php
@@ -1,25 +1,32 @@
1<?php 1<?php
2/* 2/**
3* Class for Flattr querying 3 * wallabag, self hostable application allowing you to not miss any content anymore
4*/ 4 *
5class FlattrItem { 5 * @category wallabag
6 * @author Nicolas Lœuillet <nicolas@loeuillet.org>
7 * @copyright 2013
8 * @license http://opensource.org/licenses/MIT see COPYING file
9 */
6 10
11class FlattrItem
12{
7 public $status; 13 public $status;
8 public $urltoflattr; 14 public $urltoflattr;
9 public $flattrItemURL; 15 public $flattrItemURL;
10 public $numflattrs; 16 public $numflattrs;
11 17
12 public function checkItem($urltoflattr,$id) { 18 public function checkItem($urltoflattr, $id)
13 $this->cacheflattrfile($urltoflattr, $id); 19 {
20 $this->_cacheflattrfile($urltoflattr, $id);
14 $flattrResponse = file_get_contents(CACHE . "/flattr/".$id.".cache"); 21 $flattrResponse = file_get_contents(CACHE . "/flattr/".$id.".cache");
15 if($flattrResponse != FALSE) { 22 if($flattrResponse != FALSE) {
16 $result = json_decode($flattrResponse); 23 $result = json_decode($flattrResponse);
17 if (isset($result->message)){ 24 if (isset($result->message)) {
18 if ($result->message == "flattrable") { 25 if ($result->message == "flattrable") {
19 $this->status = FLATTRABLE; 26 $this->status = FLATTRABLE;
20 } 27 }
21 } 28 }
22 elseif (is_object($result) && $result->link) { 29 elseif (is_object($result) && $result->link) {
23 $this->status = FLATTRED; 30 $this->status = FLATTRED;
24 $this->flattrItemURL = $result->link; 31 $this->flattrItemURL = $result->link;
25 $this->numflattrs = $result->flattrs; 32 $this->numflattrs = $result->flattrs;
@@ -33,7 +40,8 @@ class FlattrItem {
33 } 40 }
34 } 41 }
35 42
36 private function cacheflattrfile($urltoflattr, $id) { 43 private function _cacheflattrfile($urltoflattr, $id)
44 {
37 if (!is_dir(CACHE . '/flattr')) { 45 if (!is_dir(CACHE . '/flattr')) {
38 mkdir(CACHE . '/flattr', 0777); 46 mkdir(CACHE . '/flattr', 0777);
39 } 47 }
diff --git a/inc/3rdparty/Session.class.php b/inc/3rdparty/Session.class.php
index 59dfbe67..b56e4c54 100644
--- a/inc/3rdparty/Session.class.php
+++ b/inc/3rdparty/Session.class.php
@@ -309,4 +309,38 @@ class Session
309 309
310 return true; // User is not banned. 310 return true; // User is not banned.
311 } 311 }
312
313
314 /**
315 * Tells if a param exists in session
316 *
317 * @param $name name of the param to test
318 * @return bool
319 */
320 public static function isInSession($name)
321 {
322 return (isset($_SESSION[$name]) ? : FALSE);
323 }
324
325 /**
326 * Returns param in session
327 *
328 * @param $name name of the param to return
329 * @return mixed param or null
330 */
331 public static function getParam($name)
332 {
333 return (self::isInSession($name) ? $_SESSION[$name] : NULL);
334 }
335
336 /**
337 * Store value in session
338 *
339 * @param $name name of the variable to store
340 * @param $value value to store
341 */
342 public static function setParam($name, $value)
343 {
344 $_SESSION[$name] = $value;
345 }
312} 346}
diff --git a/inc/poche/Database.class.php b/inc/poche/Database.class.php
index 11cccb72..9c1c0286 100755
--- a/inc/poche/Database.class.php
+++ b/inc/poche/Database.class.php
@@ -5,7 +5,7 @@
5 * @category wallabag 5 * @category wallabag
6 * @author Nicolas Lœuillet <nicolas@loeuillet.org> 6 * @author Nicolas Lœuillet <nicolas@loeuillet.org>
7 * @copyright 2013 7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file 8 * @license http://opensource.org/licenses/MIT see COPYING file
9 */ 9 */
10 10
11class Database { 11class Database {
@@ -38,6 +38,7 @@ class Database {
38 } 38 }
39 39
40 $this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 40 $this->handle->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
41 $this->_checkTags();
41 Tools::logm('storage type ' . STORAGE); 42 Tools::logm('storage type ' . STORAGE);
42 } 43 }
43 44
@@ -45,21 +46,7 @@ class Database {
45 return $this->handle; 46 return $this->handle;
46 } 47 }
47 48
48 public function isInstalled() { 49 private function _checkTags() {
49 $sql = "SELECT username FROM users";
50 $query = $this->executeQuery($sql, array());
51 if ($query == false) {
52 die(STORAGE . ' database looks empty. You have to create it (you can find database structure in install folder).');
53 }
54 $hasAdmin = count($query->fetchAll());
55
56 if ($hasAdmin == 0)
57 return false;
58
59 return true;
60 }
61
62 public function checkTags() {
63 50
64 if (STORAGE == 'sqlite') { 51 if (STORAGE == 'sqlite') {
65 $sql = ' 52 $sql = '
diff --git a/inc/poche/Language.class.php b/inc/poche/Language.class.php
new file mode 100644
index 00000000..790cc197
--- /dev/null
+++ b/inc/poche/Language.class.php
@@ -0,0 +1,114 @@
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://opensource.org/licenses/MIT see COPYING file
9 */
10
11class Language
12{
13 protected $wallabag;
14
15 private $currentLanguage;
16
17 private $languageNames = array(
18 'cs_CZ.utf8' => 'čeština',
19 'de_DE.utf8' => 'German',
20 'en_EN.utf8' => 'English',
21 'es_ES.utf8' => 'Español',
22 'fa_IR.utf8' => 'فارسی',
23 'fr_FR.utf8' => 'Français',
24 'it_IT.utf8' => 'Italiano',
25 'pl_PL.utf8' => 'Polski',
26 'pt_BR.utf8' => 'Português (Brasil)',
27 'ru_RU.utf8' => 'Pусский',
28 'sl_SI.utf8' => 'Slovenščina',
29 'uk_UA.utf8' => 'Українська',
30 );
31
32 public function __construct(Poche $wallabag)
33 {
34 $this->wallabag = $wallabag;
35 $pocheUser = Session::getParam('poche_user');
36 $language = (is_null($pocheUser) ? LANG : $pocheUser->getConfigValue('language'));
37
38 @putenv('LC_ALL=' . $language);
39 setlocale(LC_ALL, $language);
40 bindtextdomain($language, LOCALE);
41 textdomain($language);
42
43 $this->currentLanguage = $language;
44 }
45
46 public function getLanguage() {
47 return $this->currentLanguage;
48 }
49
50 public function getInstalledLanguages() {
51 $handle = opendir(LOCALE);
52 $languages = array();
53
54 while (($language = readdir($handle)) !== false) {
55 # Languages are stored in a directory, so all directory names are languages
56 # @todo move language installation data to database
57 if (! is_dir(LOCALE . '/' . $language) || in_array($language, array('..', '.', 'tools'))) {
58 continue;
59 }
60
61 $current = false;
62
63 if ($language === $this->getLanguage()) {
64 $current = true;
65 }
66
67 $languages[] = array('name' => (isset($this->languageNames[$language]) ? $this->languageNames[$language] : $language), 'value' => $language, 'current' => $current);
68 }
69
70 return $languages;
71 }
72
73
74 /**
75 * Update language for current user
76 *
77 * @param $newLanguage
78 */
79 public function updateLanguage($newLanguage)
80 {
81 # we are not going to change it to the current language
82 if ($newLanguage == $this->getLanguage()) {
83 $this->wallabag->messages->add('w', _('still using the "' . $this->getLanguage() . '" language!'));
84 Tools::redirect('?view=config');
85 }
86
87 $languages = $this->getInstalledLanguages();
88 $actualLanguage = false;
89
90 foreach ($languages as $language) {
91 if ($language['value'] == $newLanguage) {
92 $actualLanguage = true;
93 break;
94 }
95 }
96
97 if (!$actualLanguage) {
98 $this->wallabag->messages->add('e', _('that language does not seem to be installed'));
99 Tools::redirect('?view=config');
100 }
101
102 $this->wallabag->store->updateUserConfig($this->wallabag->user->getId(), 'language', $newLanguage);
103 $this->wallabag->messages->add('s', _('you have changed your language preferences'));
104
105 $currentConfig = $_SESSION['poche_user']->config;
106 $currentConfig['language'] = $newLanguage;
107
108 $_SESSION['poche_user']->setConfig($currentConfig);
109
110 $this->wallabag->emptyCache();
111
112 Tools::redirect('?view=config');
113 }
114} \ No newline at end of file
diff --git a/inc/poche/Poche.class.php b/inc/poche/Poche.class.php
index 09a9f5ff..bc4320b8 100755
--- a/inc/poche/Poche.class.php
+++ b/inc/poche/Poche.class.php
@@ -5,244 +5,77 @@
5 * @category wallabag 5 * @category wallabag
6 * @author Nicolas Lœuillet <nicolas@loeuillet.org> 6 * @author Nicolas Lœuillet <nicolas@loeuillet.org>
7 * @copyright 2013 7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file 8 * @license http://opensource.org/licenses/MIT see COPYING file
9 */ 9 */
10 10
11class Poche 11class Poche
12{ 12{
13 public static $canRenderTemplates = true; 13 /**
14 public static $configFileAvailable = true; 14 * @var User
15 15 */
16 public $user; 16 public $user;
17 /**
18 * @var Database
19 */
17 public $store; 20 public $store;
21 /**
22 * @var Template
23 */
18 public $tpl; 24 public $tpl;
25 /**
26 * @var Language
27 */
28 public $language;
29 /**
30 * @var Routing
31 */
32 public $routing;
33 /**
34 * @var Messages
35 */
19 public $messages; 36 public $messages;
37 /**
38 * @var Paginator
39 */
20 public $pagination; 40 public $pagination;
21 41
22 private $currentTheme = '';
23 private $currentLanguage = '';
24 private $notInstalledMessage = array();
25
26 private $language_names = array(
27 'cs_CZ.utf8' => 'čeština',
28 'de_DE.utf8' => 'German',
29 'en_EN.utf8' => 'English',
30 'es_ES.utf8' => 'Español',
31 'fa_IR.utf8' => 'فارسی',
32 'fr_FR.utf8' => 'Français',
33 'it_IT.utf8' => 'Italiano',
34 'pl_PL.utf8' => 'Polski',
35 'pt_BR.utf8' => 'Português (Brasil)',
36 'ru_RU.utf8' => 'Pусский',
37 'sl_SI.utf8' => 'Slovenščina',
38 'uk_UA.utf8' => 'Українська',
39 );
40 public function __construct() 42 public function __construct()
41 { 43 {
42 if ($this->configFileIsAvailable()) { 44 $this->init();
43 $this->init();
44 }
45
46 if ($this->themeIsInstalled()) {
47 $this->initTpl();
48 }
49
50 if ($this->systemIsInstalled()) {
51 $this->store = new Database();
52 $this->messages = new Messages();
53 # installation
54 if (! $this->store->isInstalled()) {
55 $this->install();
56 }
57 $this->store->checkTags();
58 }
59 } 45 }
60 46
61 private function init() 47 private function init()
62 { 48 {
63 Tools::initPhp(); 49 Tools::initPhp();
64 50
65 if (isset($_SESSION['poche_user']) && $_SESSION['poche_user'] != array()) { 51 $pocheUser = Session::getParam('poche_user');
66 $this->user = $_SESSION['poche_user']; 52
53 if ($pocheUser && $pocheUser != array()) {
54 $this->user = $pocheUser;
67 } else { 55 } else {
68 # fake user, just for install & login screens 56 // fake user, just for install & login screens
69 $this->user = new User(); 57 $this->user = new User();
70 $this->user->setConfig($this->getDefaultConfig()); 58 $this->user->setConfig($this->getDefaultConfig());
71 } 59 }
72 60
73 # l10n 61 $this->pagination = new Paginator($this->user->getConfigValue('pager'), 'p');
74 $language = $this->user->getConfigValue('language'); 62 $this->language = new Language($this);
75 @putenv('LC_ALL=' . $language); 63 $this->tpl = new Template($this);
76 setlocale(LC_ALL, $language); 64 $this->store = new Database();
77 bindtextdomain($language, LOCALE); 65 $this->messages = new Messages();
78 textdomain($language); 66 $this->routing = new Routing($this);
79
80 # Pagination
81 $this->pagination = new Paginator($this->user->getConfigValue('pager'), 'p');
82
83 # Set up theme
84 $themeDirectory = $this->user->getConfigValue('theme');
85
86 if ($themeDirectory === false) {
87 $themeDirectory = DEFAULT_THEME;
88 }
89
90 $this->currentTheme = $themeDirectory;
91
92 # Set up language
93 $languageDirectory = $this->user->getConfigValue('language');
94
95 if ($languageDirectory === false) {
96 $languageDirectory = DEFAULT_THEME;
97 }
98
99 $this->currentLanguage = $languageDirectory;
100 }
101
102 public function configFileIsAvailable() {
103 if (! self::$configFileAvailable) {
104 $this->notInstalledMessage[] = 'You have to copy (don\'t just rename!) inc/poche/config.inc.default.php to inc/poche/config.inc.php.';
105
106 return false;
107 }
108
109 return true;
110 } 67 }
111 68
112 public function themeIsInstalled() { 69 public function run()
113 $passTheme = TRUE; 70 {
114 # Twig is an absolute requirement for Poche to function. Abort immediately if the Composer installer hasn't been run yet 71 $this->routing->run();
115 if (! self::$canRenderTemplates) {
116 $this->notInstalledMessage[] = 'Twig does not seem to be installed. Please initialize the Composer installation to automatically fetch dependencies. You can also download <a href="http://wllbg.org/vendor">vendor.zip</a> and extract it in your wallabag folder.';
117 $passTheme = FALSE;
118 }
119
120 if (! is_writable(CACHE)) {
121 $this->notInstalledMessage[] = 'You don\'t have write access on cache directory.';
122
123 self::$canRenderTemplates = false;
124
125 $passTheme = FALSE;
126 }
127
128 # Check if the selected theme and its requirements are present
129 $theme = $this->getTheme();
130
131 if ($theme != '' && ! is_dir(THEME . '/' . $theme)) {
132 $this->notInstalledMessage[] = 'The currently selected theme (' . $theme . ') does not seem to be properly installed (Missing directory: ' . THEME . '/' . $theme . ')';
133
134 self::$canRenderTemplates = false;
135
136 $passTheme = FALSE;
137 }
138
139 $themeInfo = $this->getThemeInfo($theme);
140 if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) {
141 foreach ($themeInfo['requirements'] as $requiredTheme) {
142 if (! is_dir(THEME . '/' . $requiredTheme)) {
143 $this->notInstalledMessage[] = 'The required "' . $requiredTheme . '" theme is missing for the current theme (' . $theme . ')';
144
145 self::$canRenderTemplates = false;
146
147 $passTheme = FALSE;
148 }
149 }
150 }
151
152 if (!$passTheme) {
153 return FALSE;
154 }
155
156
157 return true;
158 } 72 }
159 73
160 /** 74 /**
161 * all checks before installation. 75 * Creates a new user
162 * @todo move HTML to template
163 * @return boolean
164 */ 76 */
165 public function systemIsInstalled() 77 public function createNewUser()
166 { 78 {
167 $msg = TRUE;
168
169 $configSalt = defined('SALT') ? constant('SALT') : '';
170
171 if (empty($configSalt)) {
172 $this->notInstalledMessage[] = 'You have not yet filled in the SALT value in the config.inc.php file.';
173 $msg = FALSE;
174 }
175 if (STORAGE == 'sqlite' && ! file_exists(STORAGE_SQLITE)) {
176 Tools::logm('sqlite file doesn\'t exist');
177 $this->notInstalledMessage[] = 'sqlite file doesn\'t exist, you can find it in install folder. Copy it in /db folder.';
178 $msg = FALSE;
179 }
180 if (is_dir(ROOT . '/install') && ! DEBUG_POCHE) {
181 $this->notInstalledMessage[] = 'you have to delete the /install folder before using poche.';
182 $msg = FALSE;
183 }
184 if (STORAGE == 'sqlite' && ! is_writable(STORAGE_SQLITE)) {
185 Tools::logm('you don\'t have write access on sqlite file');
186 $this->notInstalledMessage[] = 'You don\'t have write access on sqlite file.';
187 $msg = FALSE;
188 }
189
190 if (! $msg) {
191 return false;
192 }
193
194 return true;
195 }
196
197 public function getNotInstalledMessage() {
198 return $this->notInstalledMessage;
199 }
200
201 private function initTpl()
202 {
203 $loaderChain = new Twig_Loader_Chain();
204 $theme = $this->getTheme();
205
206 # add the current theme as first to the loader chain so Twig will look there first for overridden template files
207 try {
208 $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . $theme));
209 } catch (Twig_Error_Loader $e) {
210 # @todo isInstalled() should catch this, inject Twig later
211 die('The currently selected theme (' . $theme . ') does not seem to be properly installed (' . THEME . '/' . $theme .' is missing)');
212 }
213
214 # add all required themes to the loader chain
215 $themeInfo = $this->getThemeInfo($theme);
216 if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) {
217 foreach ($themeInfo['requirements'] as $requiredTheme) {
218 try {
219 $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . $requiredTheme));
220 } catch (Twig_Error_Loader $e) {
221 # @todo isInstalled() should catch this, inject Twig later
222 die('The required "' . $requiredTheme . '" theme is missing for the current theme (' . $theme . ')');
223 }
224 }
225 }
226
227 if (DEBUG_POCHE) {
228 $twigParams = array();
229 } else {
230 $twigParams = array('cache' => CACHE);
231 }
232
233 $this->tpl = new Twig_Environment($loaderChain, $twigParams);
234 $this->tpl->addExtension(new Twig_Extensions_Extension_I18n());
235
236 # filter to display domain name of an url
237 $filter = new Twig_SimpleFilter('getDomain', 'Tools::getDomain');
238 $this->tpl->addFilter($filter);
239
240 # filter for reading time
241 $filter = new Twig_SimpleFilter('getReadingTime', 'Tools::getReadingTime');
242 $this->tpl->addFilter($filter);
243 }
244
245 public function createNewUser() {
246 if (isset($_GET['newuser'])){ 79 if (isset($_GET['newuser'])){
247 if ($_POST['newusername'] != "" && $_POST['password4newuser'] != ""){ 80 if ($_POST['newusername'] != "" && $_POST['password4newuser'] != ""){
248 $newusername = filter_var($_POST['newusername'], FILTER_SANITIZE_STRING); 81 $newusername = filter_var($_POST['newusername'], FILTER_SANITIZE_STRING);
@@ -266,7 +99,11 @@ class Poche
266 } 99 }
267 } 100 }
268 101
269 public function deleteUser(){ 102 /**
103 * Delete an existing user
104 */
105 public function deleteUser()
106 {
270 if (isset($_GET['deluser'])){ 107 if (isset($_GET['deluser'])){
271 if ($this->store->listUsers() > 1) { 108 if ($this->store->listUsers() > 1) {
272 if (Tools::encodeString($_POST['password4deletinguser'].$this->user->getUsername()) == $this->store->getUserPassword($this->user->getId())) { 109 if (Tools::encodeString($_POST['password4deletinguser'].$this->user->getUsername()) == $this->store->getUserPassword($this->user->getId())) {
@@ -294,115 +131,6 @@ class Poche
294 } 131 }
295 } 132 }
296 133
297 private function install()
298 {
299 Tools::logm('poche still not installed');
300 echo $this->tpl->render('install.twig', array(
301 'token' => Session::getToken(),
302 'theme' => $this->getTheme(),
303 'poche_url' => Tools::getPocheUrl()
304 ));
305 if (isset($_GET['install'])) {
306 if (($_POST['password'] == $_POST['password_repeat'])
307 && $_POST['password'] != "" && $_POST['login'] != "") {
308 # let's rock, install poche baby !
309 if ($this->store->install($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login'])))
310 {
311 Session::logout();
312 Tools::logm('poche is now installed');
313 Tools::redirect();
314 }
315 }
316 else {
317 Tools::logm('error during installation');
318 Tools::redirect();
319 }
320 }
321 exit();
322 }
323
324 public function getTheme() {
325 return $this->currentTheme;
326 }
327
328 /**
329 * Provides theme information by parsing theme.ini file if present in the theme's root directory.
330 * In all cases, the following data will be returned:
331 * - name: theme's name, or key if the theme is unnamed,
332 * - current: boolean informing if the theme is the current user theme.
333 *
334 * @param string $theme Theme key (directory name)
335 * @return array|boolean Theme information, or false if the theme doesn't exist.
336 */
337 public function getThemeInfo($theme) {
338 if (!is_dir(THEME . '/' . $theme)) {
339 return false;
340 }
341
342 $themeIniFile = THEME . '/' . $theme . '/theme.ini';
343 $themeInfo = array();
344
345 if (is_file($themeIniFile) && is_readable($themeIniFile)) {
346 $themeInfo = parse_ini_file($themeIniFile);
347 }
348
349 if ($themeInfo === false) {
350 $themeInfo = array();
351 }
352 if (!isset($themeInfo['name'])) {
353 $themeInfo['name'] = $theme;
354 }
355 $themeInfo['current'] = ($theme === $this->getTheme());
356
357 return $themeInfo;
358 }
359
360 public function getInstalledThemes() {
361 $handle = opendir(THEME);
362 $themes = array();
363
364 while (($theme = readdir($handle)) !== false) {
365 # Themes are stored in a directory, so all directory names are themes
366 # @todo move theme installation data to database
367 if (!is_dir(THEME . '/' . $theme) || in_array($theme, array('.', '..'))) {
368 continue;
369 }
370
371 $themes[$theme] = $this->getThemeInfo($theme);
372 }
373
374 ksort($themes);
375
376 return $themes;
377 }
378
379 public function getLanguage() {
380 return $this->currentLanguage;
381 }
382
383 public function getInstalledLanguages() {
384 $handle = opendir(LOCALE);
385 $languages = array();
386
387 while (($language = readdir($handle)) !== false) {
388 # Languages are stored in a directory, so all directory names are languages
389 # @todo move language installation data to database
390 if (! is_dir(LOCALE . '/' . $language) || in_array($language, array('..', '.', 'tools'))) {
391 continue;
392 }
393
394 $current = false;
395
396 if ($language === $this->getLanguage()) {
397 $current = true;
398 }
399
400 $languages[] = array('name' => (isset($this->language_names[$language]) ? $this->language_names[$language] : $language), 'value' => $language, 'current' => $current);
401 }
402
403 return $languages;
404 }
405
406 public function getDefaultConfig() 134 public function getDefaultConfig()
407 { 135 {
408 return array( 136 return array(
@@ -437,7 +165,7 @@ class Poche
437 if ( $last_id ) { 165 if ( $last_id ) {
438 Tools::logm('add link ' . $url->getUrl()); 166 Tools::logm('add link ' . $url->getUrl());
439 if (DOWNLOAD_PICTURES) { 167 if (DOWNLOAD_PICTURES) {
440 $content = filtre_picture($body, $url->getUrl(), $last_id); 168 $content = Picture::filterPicture($body, $url->getUrl(), $last_id);
441 Tools::logm('updating content article'); 169 Tools::logm('updating content article');
442 $this->store->updateContent($last_id, $content, $this->user->getId()); 170 $this->store->updateContent($last_id, $content, $this->user->getId());
443 } 171 }
@@ -472,7 +200,7 @@ class Poche
472 $msg = 'delete link #' . $id; 200 $msg = 'delete link #' . $id;
473 if ($this->store->deleteById($id, $this->user->getId())) { 201 if ($this->store->deleteById($id, $this->user->getId())) {
474 if (DOWNLOAD_PICTURES) { 202 if (DOWNLOAD_PICTURES) {
475 remove_directory(ABS_PATH . $id); 203 Picture::removeDirectory(ABS_PATH . $id);
476 } 204 }
477 $this->messages->add('s', _('the link has been deleted successfully')); 205 $this->messages->add('s', _('the link has been deleted successfully'));
478 } 206 }
@@ -598,8 +326,8 @@ class Poche
598 $check_time_prod = date('d-M-Y H:i', $prod_infos[1]); 326 $check_time_prod = date('d-M-Y H:i', $prod_infos[1]);
599 $compare_dev = version_compare(POCHE, $dev); 327 $compare_dev = version_compare(POCHE, $dev);
600 $compare_prod = version_compare(POCHE, $prod); 328 $compare_prod = version_compare(POCHE, $prod);
601 $themes = $this->getInstalledThemes(); 329 $themes = $this->tpl->getInstalledThemes();
602 $languages = $this->getInstalledLanguages(); 330 $languages = $this->language->getInstalledLanguages();
603 $token = $this->user->getConfigValue('token'); 331 $token = $this->user->getConfigValue('token');
604 $http_auth = (isset($_SERVER['PHP_AUTH_USER']) || isset($_SERVER['REMOTE_USER'])) ? true : false; 332 $http_auth = (isset($_SERVER['PHP_AUTH_USER']) || isset($_SERVER['REMOTE_USER'])) ? true : false;
605 $only_user = ($this->store->listUsers() > 1) ? false : true; 333 $only_user = ($this->store->listUsers() > 1) ? false : true;
@@ -703,7 +431,7 @@ class Poche
703 'listmode' => (isset($_COOKIE['listmode']) ? true : false), 431 'listmode' => (isset($_COOKIE['listmode']) ? true : false),
704 ); 432 );
705 433
706 //if id is given - we retrive entries by tag: id is tag id 434 //if id is given - we retrieve entries by tag: id is tag id
707 if ($id) { 435 if ($id) {
708 $tpl_vars['tag'] = $this->store->retrieveTag($id, $this->user->getId()); 436 $tpl_vars['tag'] = $this->store->retrieveTag($id, $this->user->getId());
709 $tpl_vars['id'] = intval($id); 437 $tpl_vars['id'] = intval($id);
@@ -757,85 +485,6 @@ class Poche
757 } 485 }
758 } 486 }
759 487
760 public function updateTheme()
761 {
762 # no data
763 if (empty($_POST['theme'])) {
764 }
765
766 # we are not going to change it to the current theme...
767 if ($_POST['theme'] == $this->getTheme()) {
768 $this->messages->add('w', _('still using the "' . $this->getTheme() . '" theme!'));
769 Tools::redirect('?view=config');
770 }
771
772 $themes = $this->getInstalledThemes();
773 $actualTheme = false;
774
775 foreach (array_keys($themes) as $theme) {
776 if ($theme == $_POST['theme']) {
777 $actualTheme = true;
778 break;
779 }
780 }
781
782 if (! $actualTheme) {
783 $this->messages->add('e', _('that theme does not seem to be installed'));
784 Tools::redirect('?view=config');
785 }
786
787 $this->store->updateUserConfig($this->user->getId(), 'theme', $_POST['theme']);
788 $this->messages->add('s', _('you have changed your theme preferences'));
789
790 $currentConfig = $_SESSION['poche_user']->config;
791 $currentConfig['theme'] = $_POST['theme'];
792
793 $_SESSION['poche_user']->setConfig($currentConfig);
794
795 $this->emptyCache();
796
797 Tools::redirect('?view=config');
798 }
799
800 public function updateLanguage()
801 {
802 # no data
803 if (empty($_POST['language'])) {
804 }
805
806 # we are not going to change it to the current language...
807 if ($_POST['language'] == $this->getLanguage()) {
808 $this->messages->add('w', _('still using the "' . $this->getLanguage() . '" language!'));
809 Tools::redirect('?view=config');
810 }
811
812 $languages = $this->getInstalledLanguages();
813 $actualLanguage = false;
814
815 foreach ($languages as $language) {
816 if ($language['value'] == $_POST['language']) {
817 $actualLanguage = true;
818 break;
819 }
820 }
821
822 if (! $actualLanguage) {
823 $this->messages->add('e', _('that language does not seem to be installed'));
824 Tools::redirect('?view=config');
825 }
826
827 $this->store->updateUserConfig($this->user->getId(), 'language', $_POST['language']);
828 $this->messages->add('s', _('you have changed your language preferences'));
829
830 $currentConfig = $_SESSION['poche_user']->config;
831 $currentConfig['language'] = $_POST['language'];
832
833 $_SESSION['poche_user']->setConfig($currentConfig);
834
835 $this->emptyCache();
836
837 Tools::redirect('?view=config');
838 }
839 /** 488 /**
840 * get credentials from differents sources 489 * get credentials from differents sources
841 * it redirects the user to the $referer link 490 * it redirects the user to the $referer link
diff --git a/inc/poche/Routing.class.php b/inc/poche/Routing.class.php
new file mode 100644
index 00000000..7e259c24
--- /dev/null
+++ b/inc/poche/Routing.class.php
@@ -0,0 +1,149 @@
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://opensource.org/licenses/MIT see COPYING file
9 */
10
11class Routing
12{
13 protected $wallabag;
14 protected $referer;
15 protected $view;
16 protected $action;
17 protected $id;
18 protected $url;
19 protected $file;
20 protected $defaultVars = array();
21 protected $vars = array();
22
23 public function __construct(Poche $wallabag)
24 {
25 $this->wallabag = $wallabag;
26 $this->_init();
27 }
28
29 private function _init()
30 {
31 # Parse GET & REFERER vars
32 $this->referer = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'];
33 $this->view = Tools::checkVar('view', 'home');
34 $this->action = Tools::checkVar('action');
35 $this->id = Tools::checkVar('id');
36 $_SESSION['sort'] = Tools::checkVar('sort', 'id');
37 $this->url = new Url((isset ($_GET['url'])) ? $_GET['url'] : '');
38 }
39
40 public function run()
41 {
42 # vars to _always_ send to templates
43 $this->defaultVars = array(
44 'referer' => $this->referer,
45 'view' => $this->view,
46 'poche_url' => Tools::getPocheUrl(),
47 'title' => _('wallabag, a read it later open source system'),
48 'token' => \Session::getToken(),
49 'theme' => $this->wallabag->tpl->getTheme()
50 );
51
52 $this->_launchAction();
53 $this->_defineTplInformation();
54
55 # because messages can be added in $poche->action(), we have to add this entry now (we can add it before)
56 $this->vars = array_merge($this->vars, array('messages' => $this->wallabag->messages->display('all', FALSE)));
57
58 $this->_render($this->file, $this->vars);
59 }
60
61 private function _defineTplInformation()
62 {
63 $tplFile = array();
64 $tplVars = array();
65
66 if (\Session::isLogged()) {
67 $this->wallabag->action($this->action, $this->url, $this->id);
68 $tplFile = Tools::getTplFile($this->view);
69 $tplVars = array_merge($this->vars, $this->wallabag->displayView($this->view, $this->id));
70 } elseif(isset($_SERVER['PHP_AUTH_USER'])) {
71 if($this->wallabag->store->userExists($_SERVER['PHP_AUTH_USER'])) {
72 $this->wallabag->login($this->referer);
73 } else {
74 $this->wallabag->messages->add('e', _('login failed: user doesn\'t exist'));
75 Tools::logm('user doesn\'t exist');
76 $tplFile = Tools::getTplFile('login');
77 $tplVars['http_auth'] = 1;
78 }
79 } elseif(isset($_SERVER['REMOTE_USER'])) {
80 if($this->wallabag->store->userExists($_SERVER['REMOTE_USER'])) {
81 $this->wallabag->login($this->referer);
82 } else {
83 $this->wallabag->messages->add('e', _('login failed: user doesn\'t exist'));
84 Tools::logm('user doesn\'t exist');
85 $tplFile = Tools::getTplFile('login');
86 $tplVars['http_auth'] = 1;
87 }
88 } else {
89 $tplFile = Tools::getTplFile('login');
90 $tplVars['http_auth'] = 0;
91 \Session::logout();
92 }
93
94 $this->file = $tplFile;
95 $this->vars = array_merge($this->defaultVars, $tplVars);
96 }
97
98 private function _launchAction()
99 {
100 if (isset($_GET['login'])) {
101 // hello you
102 $this->wallabag->login($this->referer);
103 } elseif (isset($_GET['logout'])) {
104 // see you soon !
105 $this->wallabag->logout();
106 } elseif (isset($_GET['config'])) {
107 // update password
108 $this->wallabag->updatePassword();
109 } elseif (isset($_GET['newuser'])) {
110 $this->wallabag->createNewUser();
111 } elseif (isset($_GET['deluser'])) {
112 $this->wallabag->deleteUser();
113 } elseif (isset($_GET['epub'])) {
114 $this->wallabag->createEpub();
115 } elseif (isset($_GET['import'])) {
116 $import = $this->wallabag->import();
117 $tplVars = array_merge($this->vars, $import);
118 } elseif (isset($_GET['download'])) {
119 Tools::downloadDb();
120 } elseif (isset($_GET['empty-cache'])) {
121 $this->wallabag->emptyCache();
122 } elseif (isset($_GET['export'])) {
123 $this->wallabag->export();
124 } elseif (isset($_GET['updatetheme'])) {
125 $this->wallabag->tpl->updateTheme($_POST['theme']);
126 } elseif (isset($_GET['updatelanguage'])) {
127 $this->wallabag->language->updateLanguage($_POST['language']);
128 } elseif (isset($_GET['uploadfile'])) {
129 $this->wallabag->uploadFile();
130 } elseif (isset($_GET['feed'])) {
131 if (isset($_GET['action']) && $_GET['action'] == 'generate') {
132 $this->wallabag->generateToken();
133 }
134 else {
135 $tag_id = (isset($_GET['tag_id']) ? intval($_GET['tag_id']) : 0);
136 $this->wallabag->generateFeeds($_GET['token'], filter_var($_GET['user_id'],FILTER_SANITIZE_NUMBER_INT), $tag_id, $_GET['type']);
137 }
138 }
139 elseif (isset($_GET['plainurl']) && !empty($_GET['plainurl'])) {
140 $plainUrl = new Url(base64_encode($_GET['plainurl']));
141 $this->wallabag->action('add', $plainUrl);
142 }
143 }
144
145 private function _render($file, $vars)
146 {
147 echo $this->wallabag->tpl->render($file, $vars);
148 }
149} \ No newline at end of file
diff --git a/inc/poche/Template.class.php b/inc/poche/Template.class.php
new file mode 100644
index 00000000..0e09ad64
--- /dev/null
+++ b/inc/poche/Template.class.php
@@ -0,0 +1,236 @@
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://opensource.org/licenses/MIT see COPYING file
9 */
10
11class Template extends Twig_Environment
12{
13 protected $wallabag;
14
15 private $canRenderTemplates = TRUE;
16 private $currentTheme = '';
17
18 public function __construct(Poche $wallabag)
19 {
20 $this->wallabag = $wallabag;
21
22 // Set up theme
23 $pocheUser = Session::getParam('poche_user');
24
25 $themeDirectory = (is_null($pocheUser) ? DEFAULT_THEME : $pocheUser->getConfigValue('theme'));
26
27 if ($themeDirectory === false) {
28 $themeDirectory = DEFAULT_THEME;
29 }
30
31 $this->currentTheme = $themeDirectory;
32
33 if ($this->_themeIsInstalled() === array()) {
34 $this->_init();
35 }
36 }
37
38 /**
39 * Returns true if selected theme is installed
40 *
41 * @return bool
42 */
43 private function _themeIsInstalled()
44 {
45 $errors = array();
46
47 // Twig is an absolute requirement for wallabag to function.
48 // Abort immediately if the Composer installer hasn't been run yet
49 if (!$this->canRenderTemplates) {
50 $errors[] = 'Twig does not seem to be installed. Please initialize the Composer installation to automatically fetch dependencies. You can also download <a href="http://wllbg.org/vendor">vendor.zip</a> and extract it in your wallabag folder.';
51 }
52
53 // Check if the selected theme and its requirements are present
54 $theme = $this->getTheme();
55 if ($theme != '' && !is_dir(THEME . '/' . $theme)) {
56 $errors[] = 'The currently selected theme (' . $theme . ') does not seem to be properly installed (Missing directory: ' . THEME . '/' . $theme . ')';
57 $this->canRenderTemplates = FALSE;
58 }
59
60 $themeInfo = $this->getThemeInfo($theme);
61 if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) {
62 foreach ($themeInfo['requirements'] as $requiredTheme) {
63 if (! is_dir(THEME . '/' . $requiredTheme)) {
64 $errors[] = 'The required "' . $requiredTheme . '" theme is missing for the current theme (' . $theme . ')';
65 $this->canRenderTemplates = FALSE;
66 }
67 }
68 }
69
70 $currentErrors = (is_null(Session::getParam('errors'))? array() : Session::getParam('errors'));
71 Session::setParam('errors', array_merge($errors, $currentErrors));
72
73 return $errors;
74 }
75
76 /**
77 * Initialization for templates
78 */
79 private function _init()
80 {
81 $loaderChain = new Twig_Loader_Chain();
82 $theme = $this->getTheme();
83
84 // add the current theme as first to the loader chain
85 // so Twig will look there first for overridden template files
86 try {
87 $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . $theme));
88 } catch (Twig_Error_Loader $e) {
89 # @todo isInstalled() should catch this, inject Twig later
90 die('The currently selected theme (' . $theme . ') does not seem to be properly installed (' . THEME . '/' . $theme .' is missing)');
91 }
92
93 // add all required themes to the loader chain
94 $themeInfo = $this->getThemeInfo($theme);
95 if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) {
96 foreach ($themeInfo['requirements'] as $requiredTheme) {
97 try {
98 $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . $requiredTheme));
99 } catch (Twig_Error_Loader $e) {
100 # @todo isInstalled() should catch this, inject Twig later
101 die('The required "' . $requiredTheme . '" theme is missing for the current theme (' . $theme . ')');
102 }
103 }
104 }
105
106 if (DEBUG_POCHE) {
107 $twigParams = array();
108 } else {
109 $twigParams = array('cache' => CACHE);
110 }
111
112 parent::__construct($loaderChain, $twigParams);
113
114 //$tpl = new Twig_Environment($loaderChain, $twigParams);
115 $this->addExtension(new Twig_Extensions_Extension_I18n());
116
117 # filter to display domain name of an url
118 $filter = new Twig_SimpleFilter('getDomain', 'Tools::getDomain');
119 $this->addFilter($filter);
120
121 # filter for reading time
122 $filter = new Twig_SimpleFilter('getReadingTime', 'Tools::getReadingTime');
123 $this->addFilter($filter);
124 }
125
126 /**
127 * Returns current theme
128 *
129 * @return string
130 */
131 public function getTheme()
132 {
133 return $this->currentTheme;
134 }
135
136 /**
137 * Provides theme information by parsing theme.ini file if present in the theme's root directory.
138 * In all cases, the following data will be returned:
139 * - name: theme's name, or key if the theme is unnamed,
140 * - current: boolean informing if the theme is the current user theme.
141 *
142 * @param string $theme Theme key (directory name)
143 * @return array|boolean Theme information, or false if the theme doesn't exist.
144 */
145 public function getThemeInfo($theme)
146 {
147 if (!is_dir(THEME . '/' . $theme)) {
148 return false;
149 }
150
151 $themeIniFile = THEME . '/' . $theme . '/theme.ini';
152 $themeInfo = array();
153
154 if (is_file($themeIniFile) && is_readable($themeIniFile)) {
155 $themeInfo = parse_ini_file($themeIniFile);
156 }
157
158 if ($themeInfo === false) {
159 $themeInfo = array();
160 }
161
162 if (!isset($themeInfo['name'])) {
163 $themeInfo['name'] = $theme;
164 }
165
166 $themeInfo['current'] = ($theme === $this->getTheme());
167
168 return $themeInfo;
169 }
170
171 /**
172 * Returns an array with installed themes
173 *
174 * @return array
175 */
176 public function getInstalledThemes()
177 {
178 $handle = opendir(THEME);
179 $themes = array();
180
181 while (($theme = readdir($handle)) !== false) {
182 # Themes are stored in a directory, so all directory names are themes
183 # @todo move theme installation data to database
184 if (!is_dir(THEME . '/' . $theme) || in_array($theme, array('.', '..'))) {
185 continue;
186 }
187
188 $themes[$theme] = $this->getThemeInfo($theme);
189 }
190
191 ksort($themes);
192
193 return $themes;
194 }
195
196 /**
197 * Update theme for the current user
198 *
199 * @param $newTheme
200 */
201 public function updateTheme($newTheme)
202 {
203 # we are not going to change it to the current theme...
204 if ($newTheme == $this->getTheme()) {
205 $this->wallabag->messages->add('w', _('still using the "' . $this->getTheme() . '" theme!'));
206 Tools::redirect('?view=config');
207 }
208
209 $themes = $this->getInstalledThemes();
210 $actualTheme = false;
211
212 foreach (array_keys($themes) as $theme) {
213 if ($theme == $newTheme) {
214 $actualTheme = true;
215 break;
216 }
217 }
218
219 if (!$actualTheme) {
220 $this->wallabag->messages->add('e', _('that theme does not seem to be installed'));
221 Tools::redirect('?view=config');
222 }
223
224 $this->wallabag->store->updateUserConfig($this->wallabag->user->getId(), 'theme', $newTheme);
225 $this->wallabag->messages->add('s', _('you have changed your theme preferences'));
226
227 $currentConfig = $_SESSION['poche_user']->config;
228 $currentConfig['theme'] = $newTheme;
229
230 $_SESSION['poche_user']->setConfig($currentConfig);
231
232 $this->wallabag->emptyCache();
233
234 Tools::redirect('?view=config');
235 }
236} \ No newline at end of file
diff --git a/inc/poche/Tools.class.php b/inc/poche/Tools.class.php
index cc01f403..762e4446 100755
--- a/inc/poche/Tools.class.php
+++ b/inc/poche/Tools.class.php
@@ -5,19 +5,23 @@
5 * @category wallabag 5 * @category wallabag
6 * @author Nicolas Lœuillet <nicolas@loeuillet.org> 6 * @author Nicolas Lœuillet <nicolas@loeuillet.org>
7 * @copyright 2013 7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file 8 * @license http://opensource.org/licenses/MIT see COPYING file
9 */ 9 */
10 10
11class Tools 11final class Tools
12{ 12{
13 private function __construct()
14 {
15
16 }
17
18 /**
19 * Initialize PHP environment
20 */
13 public static function initPhp() 21 public static function initPhp()
14 { 22 {
15 define('START_TIME', microtime(true)); 23 define('START_TIME', microtime(true));
16 24
17 if (phpversion() < 5) {
18 die(_('Oops, it seems you don\'t have PHP 5.'));
19 }
20
21 function stripslashesDeep($value) { 25 function stripslashesDeep($value) {
22 return is_array($value) 26 return is_array($value)
23 ? array_map('stripslashesDeep', $value) 27 ? array_map('stripslashesDeep', $value)
@@ -34,6 +38,11 @@ class Tools
34 register_shutdown_function('ob_end_flush'); 38 register_shutdown_function('ob_end_flush');
35 } 39 }
36 40
41 /**
42 * Get wallabag instance URL
43 *
44 * @return string
45 */
37 public static function getPocheUrl() 46 public static function getPocheUrl()
38 { 47 {
39 $https = (!empty($_SERVER['HTTPS']) 48 $https = (!empty($_SERVER['HTTPS'])
@@ -67,6 +76,11 @@ class Tools
67 . $host . $serverport . $scriptname; 76 . $host . $serverport . $scriptname;
68 } 77 }
69 78
79 /**
80 * Redirects to a URL
81 *
82 * @param string $url
83 */
70 public static function redirect($url = '') 84 public static function redirect($url = '')
71 { 85 {
72 if ($url === '') { 86 if ($url === '') {
@@ -87,11 +101,18 @@ class Tools
87 $url = $ref; 101 $url = $ref;
88 } 102 }
89 } 103 }
104
90 self::logm('redirect to ' . $url); 105 self::logm('redirect to ' . $url);
91 header('Location: '.$url); 106 header('Location: '.$url);
92 exit(); 107 exit();
93 } 108 }
94 109
110 /**
111 * Returns name of the template file to display
112 *
113 * @param $view
114 * @return string
115 */
95 public static function getTplFile($view) 116 public static function getTplFile($view)
96 { 117 {
97 $views = array( 118 $views = array(
@@ -99,13 +120,15 @@ class Tools
99 'edit-tags', 'view', 'login', 'error' 120 'edit-tags', 'view', 'login', 'error'
100 ); 121 );
101 122
102 if (in_array($view, $views)) { 123 return (in_array($view, $views) ? $view . '.twig' : 'home.twig');
103 return $view . '.twig';
104 }
105
106 return 'home.twig';
107 } 124 }
108 125
126 /**
127 * Download a file (typically, for downloading pictures on web server)
128 *
129 * @param $url
130 * @return bool|mixed|string
131 */
109 public static function getFile($url) 132 public static function getFile($url)
110 { 133 {
111 $timeout = 15; 134 $timeout = 15;
@@ -186,6 +209,11 @@ class Tools
186 } 209 }
187 } 210 }
188 211
212 /**
213 * Headers for JSON export
214 *
215 * @param $data
216 */
189 public static function renderJson($data) 217 public static function renderJson($data)
190 { 218 {
191 header('Cache-Control: no-cache, must-revalidate'); 219 header('Cache-Control: no-cache, must-revalidate');
@@ -195,6 +223,11 @@ class Tools
195 exit(); 223 exit();
196 } 224 }
197 225
226 /**
227 * Create new line in log file
228 *
229 * @param $message
230 */
198 public static function logm($message) 231 public static function logm($message)
199 { 232 {
200 if (DEBUG_POCHE && php_sapi_name() != 'cli') { 233 if (DEBUG_POCHE && php_sapi_name() != 'cli') {
@@ -204,36 +237,57 @@ class Tools
204 } 237 }
205 } 238 }
206 239
240 /**
241 * Encode a URL by using a salt
242 *
243 * @param $string
244 * @return string
245 */
207 public static function encodeString($string) 246 public static function encodeString($string)
208 { 247 {
209 return sha1($string . SALT); 248 return sha1($string . SALT);
210 } 249 }
211 250
251 /**
252 * Cleans a variable
253 *
254 * @param $var
255 * @param string $default
256 * @return string
257 */
212 public static function checkVar($var, $default = '') 258 public static function checkVar($var, $default = '')
213 { 259 {
214 return ((isset ($_REQUEST["$var"])) ? htmlentities($_REQUEST["$var"]) : $default); 260 return ((isset($_REQUEST["$var"])) ? htmlentities($_REQUEST["$var"]) : $default);
215 } 261 }
216 262
263 /**
264 * Returns the domain name for a URL
265 *
266 * @param $url
267 * @return string
268 */
217 public static function getDomain($url) 269 public static function getDomain($url)
218 { 270 {
219 return parse_url($url, PHP_URL_HOST); 271 return parse_url($url, PHP_URL_HOST);
220 } 272 }
221 273
222 public static function getReadingTime($text) { 274 /**
223 $word = str_word_count(strip_tags($text)); 275 * For a given text, we calculate reading time for an article
224 $minutes = floor($word / 200); 276 *
225 $seconds = floor($word % 200 / (200 / 60)); 277 * @param $text
226 $time = array('minutes' => $minutes, 'seconds' => $seconds); 278 * @return float
227 279 */
228 return $minutes; 280 public static function getReadingTime($text)
229 } 281 {
230 282 return floor(str_word_count(strip_tags($text)) / 200);
231 public static function getDocLanguage($userlanguage) {
232 $lang = explode('.', $userlanguage);
233 return str_replace('_', '-', $lang[0]);
234 } 283 }
235 284
236 public static function status($status_code) 285 /**
286 * Returns the correct header for a status code
287 *
288 * @param $status_code
289 */
290 private static function _status($status_code)
237 { 291 {
238 if (strpos(php_sapi_name(), 'apache') !== false) { 292 if (strpos(php_sapi_name(), 'apache') !== false) {
239 293
@@ -245,9 +299,13 @@ class Tools
245 } 299 }
246 } 300 }
247 301
248 public static function download_db() { 302 /**
303 * Download the sqlite database
304 */
305 public static function downloadDb()
306 {
249 header('Content-Disposition: attachment; filename="poche.sqlite.gz"'); 307 header('Content-Disposition: attachment; filename="poche.sqlite.gz"');
250 self::status(200); 308 self::_status(200);
251 309
252 header('Content-Transfer-Encoding: binary'); 310 header('Content-Transfer-Encoding: binary');
253 header('Content-Type: application/octet-stream'); 311 header('Content-Type: application/octet-stream');
@@ -256,18 +314,24 @@ class Tools
256 exit; 314 exit;
257 } 315 }
258 316
317 /**
318 * Get the content for a given URL (by a call to FullTextFeed)
319 *
320 * @param Url $url
321 * @return mixed
322 */
259 public static function getPageContent(Url $url) 323 public static function getPageContent(Url $url)
260 { 324 {
261 // Saving and clearing context 325 // Saving and clearing context
262 $REAL = array(); 326 $REAL = array();
263 foreach( $GLOBALS as $key => $value ) { 327 foreach( $GLOBALS as $key => $value ) {
264 if( $key != 'GLOBALS' && $key != '_SESSION' && $key != 'HTTP_SESSION_VARS' ) { 328 if( $key != 'GLOBALS' && $key != '_SESSION' && $key != 'HTTP_SESSION_VARS' ) {
265 $GLOBALS[$key] = array(); 329 $GLOBALS[$key] = array();
266 $REAL[$key] = $value; 330 $REAL[$key] = $value;
267 } 331 }
268 } 332 }
269 // Saving and clearing session 333 // Saving and clearing session
270 if ( isset($_SESSION) ) { 334 if (isset($_SESSION)) {
271 $REAL_SESSION = array(); 335 $REAL_SESSION = array();
272 foreach( $_SESSION as $key => $value ) { 336 foreach( $_SESSION as $key => $value ) {
273 $REAL_SESSION[$key] = $value; 337 $REAL_SESSION[$key] = $value;
@@ -279,12 +343,12 @@ class Tools
279 $scope = function() { 343 $scope = function() {
280 extract( func_get_arg(1) ); 344 extract( func_get_arg(1) );
281 $_GET = $_REQUEST = array( 345 $_GET = $_REQUEST = array(
282 "url" => $url->getUrl(), 346 "url" => $url->getUrl(),
283 "max" => 5, 347 "max" => 5,
284 "links" => "preserve", 348 "links" => "preserve",
285 "exc" => "", 349 "exc" => "",
286 "format" => "json", 350 "format" => "json",
287 "submit" => "Create Feed" 351 "submit" => "Create Feed"
288 ); 352 );
289 ob_start(); 353 ob_start();
290 require func_get_arg(0); 354 require func_get_arg(0);
@@ -292,23 +356,26 @@ class Tools
292 ob_end_clean(); 356 ob_end_clean();
293 return $json; 357 return $json;
294 }; 358 };
295 $json = $scope( "inc/3rdparty/makefulltextfeed.php", array("url" => $url) ); 359
360 $json = $scope("inc/3rdparty/makefulltextfeed.php", array("url" => $url));
296 361
297 // Clearing and restoring context 362 // Clearing and restoring context
298 foreach( $GLOBALS as $key => $value ) { 363 foreach ($GLOBALS as $key => $value) {
299 if( $key != "GLOBALS" && $key != "_SESSION" ) { 364 if($key != "GLOBALS" && $key != "_SESSION" ) {
300 unset($GLOBALS[$key]); 365 unset($GLOBALS[$key]);
301 } 366 }
302 } 367 }
303 foreach( $REAL as $key => $value ) { 368 foreach ($REAL as $key => $value) {
304 $GLOBALS[$key] = $value; 369 $GLOBALS[$key] = $value;
305 } 370 }
371
306 // Clearing and restoring session 372 // Clearing and restoring session
307 if ( isset($REAL_SESSION) ) { 373 if (isset($REAL_SESSION)) {
308 foreach( $_SESSION as $key => $value ) { 374 foreach($_SESSION as $key => $value) {
309 unset($_SESSION[$key]); 375 unset($_SESSION[$key]);
310 } 376 }
311 foreach( $REAL_SESSION as $key => $value ) { 377
378 foreach($REAL_SESSION as $key => $value) {
312 $_SESSION[$key] = $value; 379 $_SESSION[$key] = $value;
313 } 380 }
314 } 381 }
@@ -318,11 +385,12 @@ class Tools
318 385
319 /** 386 /**
320 * Returns whether we handle an AJAX (XMLHttpRequest) request. 387 * Returns whether we handle an AJAX (XMLHttpRequest) request.
388 *
321 * @return boolean whether we handle an AJAX (XMLHttpRequest) request. 389 * @return boolean whether we handle an AJAX (XMLHttpRequest) request.
322 */ 390 */
323 public static function isAjaxRequest() 391 public static function isAjaxRequest()
324 { 392 {
325 return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest'; 393 return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest';
326 } 394 }
327 395
328} 396}
diff --git a/inc/poche/Url.class.php b/inc/poche/Url.class.php
index aba236fa..d9172b7d 100644
--- a/inc/poche/Url.class.php
+++ b/inc/poche/Url.class.php
@@ -5,7 +5,7 @@
5 * @category wallabag 5 * @category wallabag
6 * @author Nicolas Lœuillet <nicolas@loeuillet.org> 6 * @author Nicolas Lœuillet <nicolas@loeuillet.org>
7 * @copyright 2013 7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file 8 * @license http://opensource.org/licenses/MIT see COPYING file
9 */ 9 */
10 10
11class Url 11class Url
diff --git a/inc/poche/User.class.php b/inc/poche/User.class.php
index cc8bec65..eaadd3e5 100644
--- a/inc/poche/User.class.php
+++ b/inc/poche/User.class.php
@@ -5,7 +5,7 @@
5 * @category wallabag 5 * @category wallabag
6 * @author Nicolas Lœuillet <nicolas@loeuillet.org> 6 * @author Nicolas Lœuillet <nicolas@loeuillet.org>
7 * @copyright 2013 7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file 8 * @license http://opensource.org/licenses/MIT see COPYING file
9 */ 9 */
10 10
11class User 11class User
@@ -44,7 +44,14 @@ class User
44 $this->config = $config; 44 $this->config = $config;
45 } 45 }
46 46
47 public function getConfigValue($name) { 47 /**
48 * Returns configuration entry for a user
49 *
50 * @param $name
51 * @return bool
52 */
53 public function getConfigValue($name)
54 {
48 return (isset($this->config[$name])) ? $this->config[$name] : FALSE; 55 return (isset($this->config[$name])) ? $this->config[$name] : FALSE;
49 } 56 }
50} \ No newline at end of file 57} \ No newline at end of file
diff --git a/inc/poche/config.inc.default.php b/inc/poche/config.inc.default.php
index 95f727c6..6f03af18 100755
--- a/inc/poche/config.inc.default.php
+++ b/inc/poche/config.inc.default.php
@@ -5,7 +5,7 @@
5 * @category wallabag 5 * @category wallabag
6 * @author Nicolas Lœuillet <nicolas@loeuillet.org> 6 * @author Nicolas Lœuillet <nicolas@loeuillet.org>
7 * @copyright 2013 7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file 8 * @license http://opensource.org/licenses/MIT see COPYING file
9 */ 9 */
10 10
11@define ('SALT', ''); # put a strong string here 11@define ('SALT', ''); # put a strong string here
diff --git a/inc/poche/global.inc.php b/inc/poche/global.inc.php
index 8cf86d03..2c22c014 100755
--- a/inc/poche/global.inc.php
+++ b/inc/poche/global.inc.php
@@ -5,7 +5,7 @@
5 * @category wallabag 5 * @category wallabag
6 * @author Nicolas Lœuillet <nicolas@loeuillet.org> 6 * @author Nicolas Lœuillet <nicolas@loeuillet.org>
7 * @copyright 2013 7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file 8 * @license http://opensource.org/licenses/MIT see COPYING file
9 */ 9 */
10 10
11# the poche system root directory (/inc) 11# the poche system root directory (/inc)
@@ -18,6 +18,10 @@ require_once INCLUDES . '/poche/Tools.class.php';
18require_once INCLUDES . '/poche/User.class.php'; 18require_once INCLUDES . '/poche/User.class.php';
19require_once INCLUDES . '/poche/Url.class.php'; 19require_once INCLUDES . '/poche/Url.class.php';
20require_once INCLUDES . '/3rdparty/class.messages.php'; 20require_once INCLUDES . '/3rdparty/class.messages.php';
21require_once ROOT . '/vendor/autoload.php';
22require_once INCLUDES . '/poche/Template.class.php';
23require_once INCLUDES . '/poche/Language.class.php';
24require_once INCLUDES . '/poche/Routing.class.php';
21require_once INCLUDES . '/poche/Poche.class.php'; 25require_once INCLUDES . '/poche/Poche.class.php';
22 26
23require_once INCLUDES . '/poche/Database.class.php'; 27require_once INCLUDES . '/poche/Database.class.php';
@@ -36,22 +40,11 @@ require_once INCLUDES . '/3rdparty/libraries/PHPePub/Logger.php';
36require_once INCLUDES . '/3rdparty/libraries/PHPePub/EPub.php'; 40require_once INCLUDES . '/3rdparty/libraries/PHPePub/EPub.php';
37require_once INCLUDES . '/3rdparty/libraries/PHPePub/EPubChapterSplitter.php'; 41require_once INCLUDES . '/3rdparty/libraries/PHPePub/EPubChapterSplitter.php';
38 42
39# Composer its autoloader for automatically loading Twig
40if (! file_exists(ROOT . '/vendor/autoload.php')) {
41 Poche::$canRenderTemplates = false;
42} else {
43 require_once ROOT . '/vendor/autoload.php';
44}
45
46# system configuration; database credentials et caetera 43# system configuration; database credentials et caetera
47if (! file_exists(INCLUDES . '/poche/config.inc.php')) { 44require_once INCLUDES . '/poche/config.inc.php';
48 Poche::$configFileAvailable = false; 45require_once INCLUDES . '/poche/config.inc.default.php';
49} else {
50 require_once INCLUDES . '/poche/config.inc.php';
51 require_once INCLUDES . '/poche/config.inc.default.php';
52}
53 46
54if (Poche::$configFileAvailable && DOWNLOAD_PICTURES) { 47if (DOWNLOAD_PICTURES) {
55 require_once INCLUDES . '/poche/pochePictures.php'; 48 require_once INCLUDES . '/poche/pochePictures.php';
56} 49}
57 50
diff --git a/inc/poche/pochePictures.php b/inc/poche/pochePictures.php
index 7c319a85..26bf0706 100644
--- a/inc/poche/pochePictures.php
+++ b/inc/poche/pochePictures.php
@@ -5,154 +5,169 @@
5 * @category wallabag 5 * @category wallabag
6 * @author Nicolas Lœuillet <nicolas@loeuillet.org> 6 * @author Nicolas Lœuillet <nicolas@loeuillet.org>
7 * @copyright 2013 7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file 8 * @license http://opensource.org/licenses/MIT see COPYING file
9 */ 9 */
10 10
11/** 11
12 * On modifie les URLS des images dans le corps de l'article 12final class Picture
13 */
14function filtre_picture($content, $url, $id)
15{ 13{
16 $matches = array(); 14 private function __construct()
17 $processing_pictures = array(); // list of processing image to avoid processing the same pictures twice 15 {
18 preg_match_all('#<\s*(img)[^>]+src="([^"]*)"[^>]*>#Si', $content, $matches, PREG_SET_ORDER); 16
19 foreach($matches as $i => $link) { 17 }
20 $link[1] = trim($link[1]); 18
21 if (!preg_match('#^(([a-z]+://)|(\#))#', $link[1])) { 19 /**
22 $absolute_path = get_absolute_link($link[2],$url); 20 * Changing pictures URL in article content
23 $filename = basename(parse_url($absolute_path, PHP_URL_PATH)); 21 */
24 $directory = create_assets_directory($id); 22 public static function filterPicture($content, $url, $id)
25 $fullpath = $directory . '/' . $filename; 23 {
26 24 $matches = array();
27 if (in_array($absolute_path, $processing_pictures) === true) { 25 $processing_pictures = array(); // list of processing image to avoid processing the same pictures twice
28 // replace picture's URL only if processing is OK : already processing -> go to next picture 26 preg_match_all('#<\s*(img)[^>]+src="([^"]*)"[^>]*>#Si', $content, $matches, PREG_SET_ORDER);
29 continue; 27 foreach($matches as $i => $link) {
30 } 28 $link[1] = trim($link[1]);
31 29 if (!preg_match('#^(([a-z]+://)|(\#))#', $link[1])) {
32 if (download_pictures($absolute_path, $fullpath) === true) { 30 $absolute_path = self::_getAbsoluteLink($link[2], $url);
33 $content = str_replace($matches[$i][2], $fullpath, $content); 31 $filename = basename(parse_url($absolute_path, PHP_URL_PATH));
32 $directory = self::_createAssetsDirectory($id);
33 $fullpath = $directory . '/' . $filename;
34
35 if (in_array($absolute_path, $processing_pictures) === true) {
36 // replace picture's URL only if processing is OK : already processing -> go to next picture
37 continue;
38 }
39
40 if (self::_downloadPictures($absolute_path, $fullpath) === true) {
41 $content = str_replace($matches[$i][2], $fullpath, $content);
42 }
43
44 $processing_pictures[] = $absolute_path;
34 } 45 }
35
36 $processing_pictures[] = $absolute_path;
37 } 46 }
38 47
48 return $content;
39 } 49 }
40 50
41 return $content; 51 /**
42} 52 * Get absolute URL
53 */
54 private static function _getAbsoluteLink($relativeLink, $url)
55 {
56 /* return if already absolute URL */
57 if (parse_url($relativeLink, PHP_URL_SCHEME) != '') return $relativeLink;
43 58
44/** 59 /* queries and anchors */
45 * Retourne le lien absolu 60 if ($relativeLink[0]=='#' || $relativeLink[0]=='?') return $url . $relativeLink;
46 */
47function get_absolute_link($relative_link, $url) {
48 /* return if already absolute URL */
49 if (parse_url($relative_link, PHP_URL_SCHEME) != '') return $relative_link;
50 61
51 /* queries and anchors */ 62 /* parse base URL and convert to local variables:
52 if ($relative_link[0]=='#' || $relative_link[0]=='?') return $url . $relative_link; 63 $scheme, $host, $path */
64 extract(parse_url($url));
53 65
54 /* parse base URL and convert to local variables: 66 /* remove non-directory element from path */
55 $scheme, $host, $path */ 67 $path = preg_replace('#/[^/]*$#', '', $path);
56 extract(parse_url($url));
57 68
58 /* remove non-directory element from path */ 69 /* destroy path if relative url points to root */
59 $path = preg_replace('#/[^/]*$#', '', $path); 70 if ($relativeLink[0] == '/') $path = '';
60 71
61 /* destroy path if relative url points to root */ 72 /* dirty absolute URL */
62 if ($relative_link[0] == '/') $path = ''; 73 $abs = $host . $path . '/' . $relativeLink;
63 74
64 /* dirty absolute URL */ 75 /* replace '//' or '/./' or '/foo/../' with '/' */
65 $abs = $host . $path . '/' . $relative_link; 76 $re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
77 for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {}
66 78
67 /* replace '//' or '/./' or '/foo/../' with '/' */ 79 /* absolute URL is ready! */
68 $re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#'); 80 return $scheme.'://'.$abs;
69 for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {} 81 }
70 82
71 /* absolute URL is ready! */ 83 /**
72 return $scheme.'://'.$abs; 84 * Downloading pictures
73} 85 *
86 * @return bool true if the download and processing is OK, false else
87 */
88 private static function _downloadPictures($absolute_path, $fullpath)
89 {
90 $rawdata = Tools::getFile($absolute_path);
91 $fullpath = urldecode($fullpath);
92
93 if(file_exists($fullpath)) {
94 unlink($fullpath);
95 }
74 96
75/** 97 // check extension
76 * Téléchargement des images 98 $file_ext = strrchr($fullpath, '.');
77 * 99 $whitelist = array(".jpg",".jpeg",".gif",".png");
78 * @return bool true if the download and processing is OK, false else 100 if (!(in_array($file_ext, $whitelist))) {
79 */ 101 Tools::logm('processed image with not allowed extension. Skipping ' . $fullpath);
80function download_pictures($absolute_path, $fullpath) 102 return false;
81{ 103 }
82 $rawdata = Tools::getFile($absolute_path);
83 $fullpath = urldecode($fullpath);
84 104
85 if(file_exists($fullpath)) { 105 // check headers
86 unlink($fullpath); 106 $imageinfo = getimagesize($absolute_path);
87 } 107 if ($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg'&& $imageinfo['mime'] != 'image/jpg'&& $imageinfo['mime'] != 'image/png') {
88 108 Tools::logm('processed image with bad header. Skipping ' . $fullpath);
89 // check extension 109 return false;
90 $file_ext = strrchr($fullpath, '.'); 110 }
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;
126}
127 111
128/** 112 // regenerate image
129 * Crée un répertoire de médias pour l'article 113 $im = imagecreatefromstring($rawdata);
130 */ 114 if ($im === false) {
131function create_assets_directory($id) 115 Tools::logm('error while regenerating image ' . $fullpath);
132{ 116 return false;
133 $assets_path = ABS_PATH; 117 }
134 if(!is_dir($assets_path)) { 118
135 mkdir($assets_path, 0715); 119 switch ($imageinfo['mime']) {
136 } 120 case 'image/gif':
121 $result = imagegif($im, $fullpath);
122 break;
123 case 'image/jpeg':
124 case 'image/jpg':
125 $result = imagejpeg($im, $fullpath, REGENERATE_PICTURES_QUALITY);
126 break;
127 case 'image/png':
128 $result = imagepng($im, $fullpath, ceil(REGENERATE_PICTURES_QUALITY / 100 * 9));
129 break;
130 }
131 imagedestroy($im);
137 132
138 $article_directory = $assets_path . $id; 133 return $result;
139 if(!is_dir($article_directory)) {
140 mkdir($article_directory, 0715);
141 } 134 }
142 135
143 return $article_directory; 136 /**
144} 137 * Create a directory for an article
138 *
139 * @param $id ID of the article
140 * @return string
141 */
142 private static function _createAssetsDirectory($id)
143 {
144 $assets_path = ABS_PATH;
145 if (!is_dir($assets_path)) {
146 mkdir($assets_path, 0715);
147 }
145 148
146/** 149 $article_directory = $assets_path . $id;
147 * Suppression du répertoire d'images 150 if (!is_dir($article_directory)) {
148 */ 151 mkdir($article_directory, 0715);
149function remove_directory($directory) 152 }
150{ 153
151 if(is_dir($directory)) { 154 return $article_directory;
152 $files = array_diff(scandir($directory), array('.','..')); 155 }
153 foreach ($files as $file) { 156
154 (is_dir("$directory/$file")) ? remove_directory("$directory/$file") : unlink("$directory/$file"); 157 /**
158 * Remove the directory
159 *
160 * @param $directory
161 * @return bool
162 */
163 public static function removeDirectory($directory)
164 {
165 if (is_dir($directory)) {
166 $files = array_diff(scandir($directory), array('.','..'));
167 foreach ($files as $file) {
168 (is_dir("$directory/$file")) ? self::removeDirectory("$directory/$file") : unlink("$directory/$file");
169 }
170 return rmdir($directory);
155 } 171 }
156 return rmdir($directory);
157 } 172 }
158} 173} \ No newline at end of file
diff --git a/index.php b/index.php
index 481841ec..825e9d5a 100755
--- a/index.php
+++ b/index.php
@@ -5,139 +5,21 @@
5 * @category wallabag 5 * @category wallabag
6 * @author Nicolas Lœuillet <nicolas@loeuillet.org> 6 * @author Nicolas Lœuillet <nicolas@loeuillet.org>
7 * @copyright 2013 7 * @copyright 2013
8 * @license http://www.wtfpl.net/ see COPYING file 8 * @license http://opensource.org/licenses/MIT see COPYING file
9 */ 9 */
10 10
11define ('POCHE', '1.7.1'); 11define ('POCHE', '1.8.0');
12require 'check_setup.php'; 12require 'check_setup.php';
13require_once 'inc/poche/global.inc.php'; 13require_once 'inc/poche/global.inc.php';
14 14
15# Set error reporting level
16if (defined('ERROR_REPORTING')) { 15if (defined('ERROR_REPORTING')) {
17 error_reporting(ERROR_REPORTING); 16 error_reporting(ERROR_REPORTING);
18} 17}
19 18
20# Start session 19// Start session
21Session::$sessionName = 'poche'; 20Session::$sessionName = 'wallabag';
22Session::init(); 21Session::init();
23 22
24# Start Poche 23// Let's rock !
25$poche = new Poche(); 24$wallabag = new Poche();
26$notInstalledMessage = $poche -> getNotInstalledMessage(); 25$wallabag->run();
27
28# Parse GET & REFERER vars
29$referer = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER'];
30$view = Tools::checkVar('view', 'home');
31$action = Tools::checkVar('action');
32$id = Tools::checkVar('id');
33$_SESSION['sort'] = Tools::checkVar('sort', 'id');
34$url = new Url((isset ($_GET['url'])) ? $_GET['url'] : '');
35
36# vars to _always_ send to templates
37$tpl_vars = array(
38 'referer' => $referer,
39 'view' => $view,
40 'poche_url' => Tools::getPocheUrl(),
41 'title' => _('wallabag, a read it later open source system'),
42 'token' => Session::getToken(),
43 'theme' => $poche->getTheme()
44);
45
46if (! empty($notInstalledMessage)) {
47 if (! Poche::$canRenderTemplates || ! Poche::$configFileAvailable) {
48 # We cannot use Twig to display the error message
49 echo '<h1>Errors</h1><ol>';
50 foreach ($notInstalledMessage as $message) {
51 echo '<li>' . $message . '</li>';
52 }
53 echo '</ol>';
54 die();
55 } else {
56 # Twig is installed, put the error message in the template
57 $tpl_file = Tools::getTplFile('error');
58 $tpl_vars = array_merge($tpl_vars, array('msg' => $poche->getNotInstalledMessage()));
59 echo $poche->tpl->render($tpl_file, $tpl_vars);
60 exit;
61 }
62}
63
64# poche actions
65if (isset($_GET['login'])) {
66 # hello you
67 $poche->login($referer);
68} elseif (isset($_GET['logout'])) {
69 # see you soon !
70 $poche->logout();
71} elseif (isset($_GET['config'])) {
72 # Update password
73 $poche->updatePassword();
74} elseif (isset($_GET['newuser'])) {
75 $poche->createNewUser();
76} elseif (isset($_GET['deluser'])) {
77 $poche->deleteUser();
78} elseif (isset($_GET['epub'])) {
79 $poche->createEpub();
80} elseif (isset($_GET['import'])) {
81 $import = $poche->import();
82 $tpl_vars = array_merge($tpl_vars, $import);
83} elseif (isset($_GET['download'])) {
84 Tools::download_db();
85} elseif (isset($_GET['empty-cache'])) {
86 $poche->emptyCache();
87} elseif (isset($_GET['export'])) {
88 $poche->export();
89} elseif (isset($_GET['updatetheme'])) {
90 $poche->updateTheme();
91} elseif (isset($_GET['updatelanguage'])) {
92 $poche->updateLanguage();
93} elseif (isset($_GET['uploadfile'])) {
94 $poche->uploadFile();
95} elseif (isset($_GET['feed'])) {
96 if (isset($_GET['action']) && $_GET['action'] == 'generate') {
97 $poche->generateToken();
98 }
99 else {
100 $tag_id = (isset($_GET['tag_id']) ? intval($_GET['tag_id']) : 0);
101 $poche->generateFeeds($_GET['token'], filter_var($_GET['user_id'],FILTER_SANITIZE_NUMBER_INT), $tag_id, $_GET['type']);
102 }
103}
104
105elseif (isset($_GET['plainurl']) && !empty($_GET['plainurl'])) {
106 $plain_url = new Url(base64_encode($_GET['plainurl']));
107 $poche->action('add', $plain_url);
108}
109
110if (Session::isLogged()) {
111 $poche->action($action, $url, $id);
112 $tpl_file = Tools::getTplFile($view);
113 $tpl_vars = array_merge($tpl_vars, $poche->displayView($view, $id));
114} elseif(isset($_SERVER['PHP_AUTH_USER'])) {
115 if($poche->store->userExists($_SERVER['PHP_AUTH_USER'])) {
116 $poche->login($referer);
117 } else {
118 $poche->messages->add('e', _('login failed: user doesn\'t exist'));
119 Tools::logm('user doesn\'t exist');
120 $tpl_file = Tools::getTplFile('login');
121 $tpl_vars['http_auth'] = 1;
122 }
123} elseif(isset($_SERVER['REMOTE_USER'])) {
124 if($poche->store->userExists($_SERVER['REMOTE_USER'])) {
125 $poche->login($referer);
126 } else {
127 $poche->messages->add('e', _('login failed: user doesn\'t exist'));
128 Tools::logm('user doesn\'t exist');
129 $tpl_file = Tools::getTplFile('login');
130 $tpl_vars['http_auth'] = 1;
131 }
132} else {
133 $tpl_file = Tools::getTplFile('login');
134 $tpl_vars['http_auth'] = 0;
135 Session::logout();
136}
137
138# because messages can be added in $poche->action(), we have to add this entry now (we can add it before)
139$messages = $poche->messages->display('all', FALSE);
140$tpl_vars = array_merge($tpl_vars, array('messages' => $messages));
141
142# display poche
143echo $poche->tpl->render($tpl_file, $tpl_vars);
diff --git a/install/index.php b/install/index.php
index e702891b..1ae782a2 100755
--- a/install/index.php
+++ b/install/index.php
@@ -1,4 +1,13 @@
1<?php 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://opensource.org/licenses/MIT see COPYING file
9 */
10
2$errors = array(); 11$errors = array();
3$successes = array(); 12$successes = array();
4 13
diff --git a/wallabag_compatibility_test.php b/wallabag_compatibility_test.php
index d6f22156..da078623 100644
--- a/wallabag_compatibility_test.php
+++ b/wallabag_compatibility_test.php
@@ -1,4 +1,13 @@
1<?php 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://opensource.org/licenses/MIT see COPYING file
9 */
10
2$app_name = 'wallabag'; 11$app_name = 'wallabag';
3 12
4$php_ok = (function_exists('version_compare') && version_compare(phpversion(), '5.3.3', '>=')); 13$php_ok = (function_exists('version_compare') && version_compare(phpversion(), '5.3.3', '>='));