2013-08-04 18:58:31 +00:00
< ? php
/**
* poche , a read it later open source system
*
* @ category poche
* @ author Nicolas Lœuillet < support @ inthepoche . com >
* @ copyright 2013
* @ license http :// www . wtfpl . net / see COPYING file
*/
class Poche
{
2013-09-20 08:21:39 +00:00
public static $canRenderTemplates = true ;
public static $configFileAvailable = true ;
2013-08-06 12:18:03 +00:00
public $user ;
2013-08-04 18:58:31 +00:00
public $store ;
public $tpl ;
2013-08-05 13:54:37 +00:00
public $messages ;
2013-08-05 19:56:32 +00:00
public $pagination ;
2013-09-20 08:21:39 +00:00
private $currentTheme = '' ;
2013-10-07 12:26:25 +00:00
private $currentLanguage = '' ;
2013-10-07 11:12:28 +00:00
private $notInstalledMessage = array ();
2013-09-20 08:21:39 +00:00
# @todo make this dynamic (actually install themes and save them in the database including author information et cetera)
private $installedThemes = array (
'default' => array ( 'requires' => array ()),
'dark' => array ( 'requires' => array ( 'default' )),
'dmagenta' => array ( 'requires' => array ( 'default' )),
'solarized' => array ( 'requires' => array ( 'default' )),
'solarized-dark' => array ( 'requires' => array ( 'default' ))
);
2013-08-04 18:58:31 +00:00
2013-09-20 08:21:39 +00:00
public function __construct ()
2013-08-04 18:58:31 +00:00
{
2013-10-07 11:12:28 +00:00
if ( $this -> configFileIsAvailable ()) {
$this -> init ();
2013-09-20 08:21:39 +00:00
}
2013-10-07 11:12:28 +00:00
if ( $this -> themeIsInstalled ()) {
$this -> initTpl ();
2013-09-20 08:21:39 +00:00
}
2013-10-07 11:12:28 +00:00
if ( $this -> systemIsInstalled ()) {
$this -> store = new Database ();
$this -> messages = new Messages ();
# installation
if ( ! $this -> store -> isInstalled ()) {
$this -> install ();
}
2013-12-23 09:35:09 +00:00
$this -> store -> checkTags ();
2013-08-04 18:58:31 +00:00
}
}
2013-09-20 08:21:39 +00:00
private function init ()
{
Tools :: initPhp ();
Session :: $sessionName = 'poche' ;
Session :: init ();
2013-08-04 18:58:31 +00:00
2013-09-20 08:21:39 +00:00
if ( isset ( $_SESSION [ 'poche_user' ]) && $_SESSION [ 'poche_user' ] != array ()) {
$this -> user = $_SESSION [ 'poche_user' ];
} else {
# fake user, just for install & login screens
$this -> user = new User ();
$this -> user -> setConfig ( $this -> getDefaultConfig ());
}
# l10n
$language = $this -> user -> getConfigValue ( 'language' );
putenv ( 'LC_ALL=' . $language );
setlocale ( LC_ALL , $language );
bindtextdomain ( $language , LOCALE );
textdomain ( $language );
# Pagination
$this -> pagination = new Paginator ( $this -> user -> getConfigValue ( 'pager' ), 'p' );
# Set up theme
$themeDirectory = $this -> user -> getConfigValue ( 'theme' );
if ( $themeDirectory === false ) {
$themeDirectory = DEFAULT_THEME ;
}
$this -> currentTheme = $themeDirectory ;
2013-10-07 12:26:25 +00:00
# Set up language
$languageDirectory = $this -> user -> getConfigValue ( 'language' );
if ( $languageDirectory === false ) {
$languageDirectory = DEFAULT_THEME ;
}
$this -> currentLanguage = $languageDirectory ;
2013-09-20 08:21:39 +00:00
}
public function configFileIsAvailable () {
if ( ! self :: $configFileAvailable ) {
2013-10-07 11:12:28 +00:00
$this -> notInstalledMessage [] = 'You have to rename inc/poche/config.inc.php.new to inc/poche/config.inc.php.' ;
2013-09-20 08:21:39 +00:00
return false ;
}
return true ;
}
public function themeIsInstalled () {
2013-10-07 11:12:28 +00:00
$passTheme = TRUE ;
2013-09-20 08:21:39 +00:00
# Twig is an absolute requirement for Poche to function. Abort immediately if the Composer installer hasn't been run yet
if ( ! self :: $canRenderTemplates ) {
2013-10-07 11:12:28 +00:00
$this -> notInstalledMessage [] = 'Twig does not seem to be installed. Please initialize the Composer installation to automatically fetch dependencies. Have a look at <a href="http://doc.inthepoche.com/doku.php?id=users:begin:install">the documentation.</a>' ;
$passTheme = FALSE ;
2013-09-20 08:21:39 +00:00
}
2013-10-03 12:23:03 +00:00
if ( ! is_writable ( CACHE )) {
2013-10-07 11:12:28 +00:00
$this -> notInstalledMessage [] = 'You don\'t have write access on cache directory.' ;
2013-10-03 12:23:03 +00:00
self :: $canRenderTemplates = false ;
2013-10-07 11:12:28 +00:00
$passTheme = FALSE ;
2013-10-03 12:23:03 +00:00
}
2013-09-20 08:21:39 +00:00
# Check if the selected theme and its requirements are present
2013-10-07 11:12:28 +00:00
if ( $this -> getTheme () != '' && ! is_dir ( THEME . '/' . $this -> getTheme ())) {
$this -> notInstalledMessage [] = 'The currently selected theme (' . $this -> getTheme () . ') does not seem to be properly installed (Missing directory: ' . THEME . '/' . $this -> getTheme () . ')' ;
2013-09-20 08:21:39 +00:00
self :: $canRenderTemplates = false ;
2013-10-07 11:12:28 +00:00
$passTheme = FALSE ;
2013-09-20 08:21:39 +00:00
}
foreach ( $this -> installedThemes [ $this -> getTheme ()][ 'requires' ] as $requiredTheme ) {
if ( ! is_dir ( THEME . '/' . $requiredTheme )) {
2013-10-07 11:12:28 +00:00
$this -> notInstalledMessage [] = 'The required "' . $requiredTheme . '" theme is missing for the current theme (' . $this -> getTheme () . ')' ;
2013-09-20 08:21:39 +00:00
self :: $canRenderTemplates = false ;
2013-10-07 11:12:28 +00:00
$passTheme = FALSE ;
2013-09-20 08:21:39 +00:00
}
}
2013-10-07 11:12:28 +00:00
if ( ! $passTheme ) {
return FALSE ;
}
2013-09-20 08:21:39 +00:00
return true ;
}
2013-08-15 08:54:14 +00:00
/**
* all checks before installation .
2013-09-20 08:21:39 +00:00
* @ todo move HTML to template
2013-08-15 08:54:14 +00:00
* @ return boolean
*/
2013-09-20 08:21:39 +00:00
public function systemIsInstalled ()
2013-08-04 18:58:31 +00:00
{
2013-10-07 11:12:28 +00:00
$msg = TRUE ;
2013-09-20 08:21:39 +00:00
$configSalt = defined ( 'SALT' ) ? constant ( 'SALT' ) : '' ;
if ( empty ( $configSalt )) {
2013-10-07 11:12:28 +00:00
$this -> notInstalledMessage [] = 'You have not yet filled in the SALT value in the config.inc.php file.' ;
$msg = FALSE ;
}
if ( STORAGE == 'sqlite' && ! file_exists ( STORAGE_SQLITE )) {
2013-09-20 08:21:39 +00:00
Tools :: logm ( 'sqlite file doesn\'t exist' );
2013-10-07 11:12:28 +00:00
$this -> notInstalledMessage [] = 'sqlite file doesn\'t exist, you can find it in install folder. Copy it in /db folder.' ;
$msg = FALSE ;
}
if ( is_dir ( ROOT . '/install' ) && ! DEBUG_POCHE ) {
$this -> notInstalledMessage [] = 'you have to delete the /install folder before using poche.' ;
$msg = FALSE ;
}
if ( STORAGE == 'sqlite' && ! is_writable ( STORAGE_SQLITE )) {
2013-08-16 18:19:31 +00:00
Tools :: logm ( 'you don\'t have write access on sqlite file' );
2013-10-07 11:12:28 +00:00
$this -> notInstalledMessage [] = 'You don\'t have write access on sqlite file.' ;
$msg = FALSE ;
2013-08-16 18:19:31 +00:00
}
2013-09-20 08:21:39 +00:00
2013-10-07 11:12:28 +00:00
if ( ! $msg ) {
2013-09-20 08:21:39 +00:00
return false ;
2013-08-06 13:51:48 +00:00
}
2013-08-06 12:18:03 +00:00
2013-09-20 08:21:39 +00:00
return true ;
}
public function getNotInstalledMessage () {
return $this -> notInstalledMessage ;
2013-08-15 08:54:14 +00:00
}
2013-08-04 18:58:31 +00:00
2013-08-15 08:54:14 +00:00
private function initTpl ()
{
2013-09-20 08:21:39 +00:00
$loaderChain = new Twig_Loader_Chain ();
# add the current theme as first to the loader chain so Twig will look there first for overridden template files
try {
$loaderChain -> addLoader ( new Twig_Loader_Filesystem ( THEME . '/' . $this -> getTheme ()));
} catch ( Twig_Error_Loader $e ) {
# @todo isInstalled() should catch this, inject Twig later
die ( 'The currently selected theme (' . $this -> getTheme () . ') does not seem to be properly installed (' . THEME . '/' . $this -> getTheme () . ' is missing)' );
}
# add all required themes to the loader chain
foreach ( $this -> installedThemes [ $this -> getTheme ()][ 'requires' ] as $requiredTheme ) {
try {
$loaderChain -> addLoader ( new Twig_Loader_Filesystem ( THEME . '/' . DEFAULT_THEME ));
} catch ( Twig_Error_Loader $e ) {
# @todo isInstalled() should catch this, inject Twig later
die ( 'The required "' . $requiredTheme . '" theme is missing for the current theme (' . $this -> getTheme () . ')' );
}
}
2013-08-07 12:24:07 +00:00
if ( DEBUG_POCHE ) {
$twig_params = array ();
2013-09-20 08:21:39 +00:00
} else {
2013-08-07 12:24:07 +00:00
$twig_params = array ( 'cache' => CACHE );
}
2013-09-20 08:21:39 +00:00
$this -> tpl = new Twig_Environment ( $loaderChain , $twig_params );
2013-08-04 18:58:31 +00:00
$this -> tpl -> addExtension ( new Twig_Extensions_Extension_I18n ());
2013-09-20 08:21:39 +00:00
2013-08-05 13:54:37 +00:00
# filter to display domain name of an url
$filter = new Twig_SimpleFilter ( 'getDomain' , 'Tools::getDomain' );
$this -> tpl -> addFilter ( $filter );
2013-08-04 18:58:31 +00:00
2013-08-09 06:25:16 +00:00
# filter for reading time
$filter = new Twig_SimpleFilter ( 'getReadingTime' , 'Tools::getReadingTime' );
$this -> tpl -> addFilter ( $filter );
2013-09-20 08:21:39 +00:00
# filter for simple filenames in config view
$filter = new Twig_SimpleFilter ( 'getPrettyFilename' , function ( $string ) { return str_replace ( ROOT , '' , $string ); });
$this -> tpl -> addFilter ( $filter );
2013-08-04 18:58:31 +00:00
}
private function install ()
{
Tools :: logm ( 'poche still not installed' );
echo $this -> tpl -> render ( 'install.twig' , array (
2013-09-20 08:21:39 +00:00
'token' => Session :: getToken (),
'theme' => $this -> getTheme (),
'poche_url' => Tools :: getPocheUrl ()
2013-08-04 18:58:31 +00:00
));
if ( isset ( $_GET [ 'install' ])) {
if (( $_POST [ 'password' ] == $_POST [ 'password_repeat' ])
&& $_POST [ 'password' ] != " " && $_POST [ 'login' ] != " " ) {
# let's rock, install poche baby !
2013-08-16 18:19:31 +00:00
if ( $this -> store -> install ( $_POST [ 'login' ], Tools :: encodeString ( $_POST [ 'password' ] . $_POST [ 'login' ])))
{
Session :: logout ();
Tools :: logm ( 'poche is now installed' );
Tools :: redirect ();
}
2013-08-05 19:56:32 +00:00
}
else {
Tools :: logm ( 'error during installation' );
2013-08-04 18:58:31 +00:00
Tools :: redirect ();
}
}
exit ();
}
2013-09-20 08:21:39 +00:00
public function getTheme () {
return $this -> currentTheme ;
}
2013-10-07 12:26:25 +00:00
public function getLanguage () {
return $this -> currentLanguage ;
}
2013-09-20 08:21:39 +00:00
public function getInstalledThemes () {
$handle = opendir ( THEME );
$themes = array ();
while (( $theme = readdir ( $handle )) !== false ) {
# Themes are stored in a directory, so all directory names are themes
# @todo move theme installation data to database
2013-10-05 08:52:08 +00:00
if ( ! is_dir ( THEME . '/' . $theme ) || in_array ( $theme , array ( '..' , '.' ))) {
2013-09-20 08:21:39 +00:00
continue ;
}
$current = false ;
if ( $theme === $this -> getTheme ()) {
$current = true ;
}
$themes [] = array ( 'name' => $theme , 'current' => $current );
}
2013-10-05 09:03:41 +00:00
sort ( $themes );
2013-09-20 08:21:39 +00:00
return $themes ;
}
2013-08-04 18:58:31 +00:00
2013-10-07 12:26:25 +00:00
public function getInstalledLanguages () {
$handle = opendir ( LOCALE );
$languages = array ();
while (( $language = readdir ( $handle )) !== false ) {
# Languages are stored in a directory, so all directory names are languages
# @todo move language installation data to database
if ( ! is_dir ( LOCALE . '/' . $language ) || in_array ( $language , array ( '..' , '.' ))) {
continue ;
}
$current = false ;
if ( $language === $this -> getLanguage ()) {
$current = true ;
}
$languages [] = array ( 'name' => $language , 'current' => $current );
}
return $languages ;
}
2013-08-06 13:51:48 +00:00
public function getDefaultConfig ()
2013-09-20 08:21:39 +00:00
{
2013-08-06 13:51:48 +00:00
return array (
'pager' => PAGINATION ,
'language' => LANG ,
2013-09-20 08:21:39 +00:00
'theme' => DEFAULT_THEME
);
2013-08-06 13:51:48 +00:00
}
2013-08-04 18:58:31 +00:00
/**
* Call action ( mark as fav , archive , delete , etc . )
*/
2013-10-27 06:37:05 +00:00
public function action ( $action , Url $url , $id = 0 , $import = FALSE , $autoclose = FALSE )
2013-08-04 18:58:31 +00:00
{
switch ( $action )
{
case 'add' :
2014-01-07 12:15:43 +00:00
$options = array ( 'http' => array ( 'user_agent' => 'poche' ));
$context = stream_context_create ( $options );
$json = file_get_contents ( Tools :: getPocheUrl () . '/inc/3rdparty/makefulltextfeed.php?url=' . urlencode ( $url -> getUrl ()) . '&max=5&links=preserve&exc=&format=json&submit=Create+Feed' , false , $context );
2013-12-06 08:45:27 +00:00
$content = json_decode ( $json , true );
$title = $content [ 'rss' ][ 'channel' ][ 'item' ][ 'title' ];
$body = $content [ 'rss' ][ 'channel' ][ 'item' ][ 'description' ];
2013-08-25 18:10:23 +00:00
2013-12-06 08:45:27 +00:00
if ( $this -> store -> add ( $url -> getUrl (), $title , $body , $this -> user -> getId ())) {
2013-08-25 18:10:23 +00:00
Tools :: logm ( 'add link ' . $url -> getUrl ());
$sequence = '' ;
if ( STORAGE == 'postgres' ) {
$sequence = 'entries_id_seq' ;
2013-08-04 18:58:31 +00:00
}
2013-08-25 18:10:23 +00:00
$last_id = $this -> store -> getLastId ( $sequence );
if ( DOWNLOAD_PICTURES ) {
2013-12-06 08:45:27 +00:00
$content = filtre_picture ( $body , $url -> getUrl (), $last_id );
2013-08-25 18:10:23 +00:00
Tools :: logm ( 'updating content article' );
$this -> store -> updateContent ( $last_id , $content , $this -> user -> getId ());
}
if ( ! $import ) {
$this -> messages -> add ( 's' , _ ( 'the link has been added successfully' ));
2013-08-04 18:58:31 +00:00
}
}
else {
2013-08-07 17:14:28 +00:00
if ( ! $import ) {
2013-08-25 18:10:23 +00:00
$this -> messages -> add ( 'e' , _ ( 'error during insertion : the link wasn\'t added' ));
Tools :: logm ( 'error during insertion : the link wasn\'t added ' . $url -> getUrl ());
2013-08-07 17:14:28 +00:00
}
}
2013-08-25 18:10:23 +00:00
2013-08-07 17:14:28 +00:00
if ( ! $import ) {
2013-10-27 06:37:05 +00:00
if ( $autoclose == TRUE ) {
Tools :: redirect ( '?view=home' );
} else {
2013-10-27 06:47:14 +00:00
Tools :: redirect ( '?view=home&closewin=true' );
2013-10-27 06:37:05 +00:00
}
2013-08-04 18:58:31 +00:00
}
break ;
case 'delete' :
2013-08-07 12:24:07 +00:00
$msg = 'delete link #' . $id ;
2013-08-06 13:51:48 +00:00
if ( $this -> store -> deleteById ( $id , $this -> user -> getId ())) {
2013-08-04 18:58:31 +00:00
if ( DOWNLOAD_PICTURES ) {
remove_directory ( ABS_PATH . $id );
}
2013-08-05 19:56:32 +00:00
$this -> messages -> add ( 's' , _ ( 'the link has been deleted successfully' ));
2013-08-04 18:58:31 +00:00
}
else {
2013-08-05 19:56:32 +00:00
$this -> messages -> add ( 'e' , _ ( 'the link wasn\'t deleted' ));
2013-08-07 12:24:07 +00:00
$msg = 'error : can\'t delete link #' . $id ;
2013-08-04 18:58:31 +00:00
}
2013-08-07 12:24:07 +00:00
Tools :: logm ( $msg );
2013-10-25 12:25:37 +00:00
Tools :: redirect ( '?' );
2013-08-04 18:58:31 +00:00
break ;
case 'toggle_fav' :
2013-08-06 13:51:48 +00:00
$this -> store -> favoriteById ( $id , $this -> user -> getId ());
2013-08-04 18:58:31 +00:00
Tools :: logm ( 'mark as favorite link #' . $id );
2013-08-07 17:14:28 +00:00
if ( ! $import ) {
Tools :: redirect ();
}
2013-08-04 18:58:31 +00:00
break ;
case 'toggle_archive' :
2013-08-06 13:51:48 +00:00
$this -> store -> archiveById ( $id , $this -> user -> getId ());
2013-08-04 18:58:31 +00:00
Tools :: logm ( 'archive link #' . $id );
2013-08-07 17:14:28 +00:00
if ( ! $import ) {
Tools :: redirect ();
}
2013-08-04 18:58:31 +00:00
break ;
2013-12-06 14:07:51 +00:00
case 'add_tag' :
$tags = explode ( ',' , $_POST [ 'value' ]);
$entry_id = $_POST [ 'entry_id' ];
foreach ( $tags as $key => $tag_value ) {
$value = trim ( $tag_value );
$tag = $this -> store -> retrieveTagByValue ( $value );
if ( is_null ( $tag )) {
# we create the tag
$tag = $this -> store -> createTag ( $value );
$sequence = '' ;
if ( STORAGE == 'postgres' ) {
$sequence = 'tags_id_seq' ;
}
$tag_id = $this -> store -> getLastId ( $sequence );
}
else {
$tag_id = $tag [ 'id' ];
}
# we assign the tag to the article
$this -> store -> setTagToEntry ( $tag_id , $entry_id );
}
Tools :: redirect ();
break ;
case 'remove_tag' :
$tag_id = $_GET [ 'tag_id' ];
$this -> store -> removeTagForEntry ( $id , $tag_id );
Tools :: redirect ();
break ;
2013-08-04 18:58:31 +00:00
default :
break ;
}
}
function displayView ( $view , $id = 0 )
{
$tpl_vars = array ();
switch ( $view )
{
case 'config' :
2013-08-05 10:34:16 +00:00
$dev = $this -> getPocheVersion ( 'dev' );
$prod = $this -> getPocheVersion ( 'prod' );
2013-10-07 11:19:34 +00:00
$compare_dev = version_compare ( POCHE , $dev );
$compare_prod = version_compare ( POCHE , $prod );
2013-09-20 08:21:39 +00:00
$themes = $this -> getInstalledThemes ();
2013-10-07 12:26:25 +00:00
$languages = $this -> getInstalledLanguages ();
2013-12-03 09:40:27 +00:00
$token = $this -> user -> getConfigValue ( 'token' );
2013-12-23 08:09:10 +00:00
$http_auth = ( isset ( $_SERVER [ 'PHP_AUTH_USER' ]) || isset ( $_SERVER [ 'REMOTE_USER' ])) ? true : false ;
2013-08-05 10:34:16 +00:00
$tpl_vars = array (
2013-09-20 08:21:39 +00:00
'themes' => $themes ,
2013-10-07 12:26:25 +00:00
'languages' => $languages ,
2013-08-05 10:34:16 +00:00
'dev' => $dev ,
'prod' => $prod ,
'compare_dev' => $compare_dev ,
'compare_prod' => $compare_prod ,
2013-12-03 09:40:27 +00:00
'token' => $token ,
'user_id' => $this -> user -> getId (),
2013-10-20 14:53:54 +00:00
'http_auth' => $http_auth ,
2013-08-05 10:34:16 +00:00
);
2013-08-04 18:58:31 +00:00
Tools :: logm ( 'config view' );
break ;
2013-12-06 13:03:14 +00:00
case 'edit-tags' :
# tags
$tags = $this -> store -> retrieveTagsByEntry ( $id );
$tpl_vars = array (
2013-12-06 14:07:51 +00:00
'entry_id' => $id ,
2013-12-06 13:03:14 +00:00
'tags' => $tags ,
);
break ;
2013-12-06 13:22:29 +00:00
case 'tag' :
$entries = $this -> store -> retrieveEntriesByTag ( $id );
$tag = $this -> store -> retrieveTag ( $id );
$tpl_vars = array (
'tag' => $tag ,
'entries' => $entries ,
);
break ;
2013-12-06 12:15:06 +00:00
case 'tags' :
2013-12-06 13:37:42 +00:00
$token = $this -> user -> getConfigValue ( 'token' );
2013-12-06 12:15:06 +00:00
$tags = $this -> store -> retrieveAllTags ();
$tpl_vars = array (
2013-12-06 13:37:42 +00:00
'token' => $token ,
'user_id' => $this -> user -> getId (),
2013-12-06 12:15:06 +00:00
'tags' => $tags ,
);
break ;
2013-08-04 18:58:31 +00:00
case 'view' :
2013-08-06 13:51:48 +00:00
$entry = $this -> store -> retrieveOneById ( $id , $this -> user -> getId ());
2013-08-04 18:58:31 +00:00
if ( $entry != NULL ) {
Tools :: logm ( 'view link #' . $id );
$content = $entry [ 'content' ];
if ( function_exists ( 'tidy_parse_string' )) {
$tidy = tidy_parse_string ( $content , array ( 'indent' => true , 'show-body-only' => true ), 'UTF8' );
$tidy -> cleanRepair ();
$content = $tidy -> value ;
2013-09-20 12:09:26 +00:00
}
2013-09-08 18:54:11 +00:00
2013-09-20 12:09:26 +00:00
# flattr checking
$flattr = new FlattrItem ();
2013-12-06 12:02:38 +00:00
$flattr -> checkItem ( $entry [ 'url' ], $entry [ 'id' ]);
# tags
$tags = $this -> store -> retrieveTagsByEntry ( $entry [ 'id' ]);
2013-09-08 18:54:11 +00:00
2013-09-20 12:09:26 +00:00
$tpl_vars = array (
2013-12-06 12:02:38 +00:00
'entry' => $entry ,
'content' => $content ,
'flattr' => $flattr ,
'tags' => $tags
2013-09-20 12:09:26 +00:00
);
2013-08-04 18:58:31 +00:00
}
else {
2013-08-09 20:15:40 +00:00
Tools :: logm ( 'error in view call : entry is null' );
2013-08-04 18:58:31 +00:00
}
break ;
2013-09-10 17:22:47 +00:00
default : # home, favorites and archive views
2013-08-06 13:51:48 +00:00
$entries = $this -> store -> getEntriesByView ( $view , $this -> user -> getId ());
2013-08-04 18:58:31 +00:00
$tpl_vars = array (
2013-08-27 14:02:25 +00:00
'entries' => '' ,
'page_links' => '' ,
2013-08-28 17:12:11 +00:00
'nb_results' => '' ,
2013-08-04 18:58:31 +00:00
);
2013-10-03 12:46:46 +00:00
2013-08-27 14:02:25 +00:00
if ( count ( $entries ) > 0 ) {
$this -> pagination -> set_total ( count ( $entries ));
$page_links = $this -> pagination -> page_links ( '?view=' . $view . '&sort=' . $_SESSION [ 'sort' ] . '&' );
$datas = $this -> store -> getEntriesByView ( $view , $this -> user -> getId (), $this -> pagination -> get_limit ());
$tpl_vars [ 'entries' ] = $datas ;
$tpl_vars [ 'page_links' ] = $page_links ;
2013-08-28 17:12:11 +00:00
$tpl_vars [ 'nb_results' ] = count ( $entries );
2013-08-27 14:02:25 +00:00
}
2013-08-05 19:56:32 +00:00
Tools :: logm ( 'display ' . $view . ' view' );
2013-08-04 18:58:31 +00:00
break ;
}
return $tpl_vars ;
}
2013-08-04 19:42:46 +00:00
2013-08-08 10:33:02 +00:00
/**
* update the password of the current user .
* if MODE_DEMO is TRUE , the password can ' t be updated .
* @ todo add the return value
* @ todo set the new password in function header like this updatePassword ( $newPassword )
* @ return boolean
*/
2013-08-04 19:42:46 +00:00
public function updatePassword ()
{
2013-08-05 13:54:37 +00:00
if ( MODE_DEMO ) {
2013-08-06 13:51:48 +00:00
$this -> messages -> add ( 'i' , _ ( 'in demo mode, you can\'t update your password' ));
2013-08-05 13:54:37 +00:00
Tools :: logm ( 'in demo mode, you can\'t do this' );
2013-08-05 19:56:32 +00:00
Tools :: redirect ( '?view=config' );
2013-08-05 13:54:37 +00:00
}
else {
if ( isset ( $_POST [ 'password' ]) && isset ( $_POST [ 'password_repeat' ])) {
if ( $_POST [ 'password' ] == $_POST [ 'password_repeat' ] && $_POST [ 'password' ] != " " ) {
2013-08-06 13:51:48 +00:00
$this -> messages -> add ( 's' , _ ( 'your password has been updated' ));
$this -> store -> updatePassword ( $this -> user -> getId (), Tools :: encodeString ( $_POST [ 'password' ] . $this -> user -> getUsername ()));
2013-08-04 19:42:46 +00:00
Session :: logout ();
2013-08-06 13:51:48 +00:00
Tools :: logm ( 'password updated' );
2013-08-04 19:42:46 +00:00
Tools :: redirect ();
}
else {
2013-08-06 13:51:48 +00:00
$this -> messages -> add ( 'e' , _ ( 'the two fields have to be filled & the password must be the same in the two fields' ));
2013-08-05 19:56:32 +00:00
Tools :: redirect ( '?view=config' );
2013-08-04 19:42:46 +00:00
}
}
}
}
2013-09-20 08:21:39 +00:00
public function updateTheme ()
{
# no data
if ( empty ( $_POST [ 'theme' ])) {
}
# we are not going to change it to the current theme...
if ( $_POST [ 'theme' ] == $this -> getTheme ()) {
$this -> messages -> add ( 'w' , _ ( 'still using the "' . $this -> getTheme () . '" theme!' ));
Tools :: redirect ( '?view=config' );
}
$themes = $this -> getInstalledThemes ();
$actualTheme = false ;
foreach ( $themes as $theme ) {
if ( $theme [ 'name' ] == $_POST [ 'theme' ]) {
$actualTheme = true ;
break ;
}
}
if ( ! $actualTheme ) {
$this -> messages -> add ( 'e' , _ ( 'that theme does not seem to be installed' ));
Tools :: redirect ( '?view=config' );
}
$this -> store -> updateUserConfig ( $this -> user -> getId (), 'theme' , $_POST [ 'theme' ]);
$this -> messages -> add ( 's' , _ ( 'you have changed your theme preferences' ));
$currentConfig = $_SESSION [ 'poche_user' ] -> config ;
$currentConfig [ 'theme' ] = $_POST [ 'theme' ];
$_SESSION [ 'poche_user' ] -> setConfig ( $currentConfig );
Tools :: redirect ( '?view=config' );
}
2013-08-04 19:42:46 +00:00
2013-10-07 12:26:25 +00:00
public function updateLanguage ()
{
# no data
if ( empty ( $_POST [ 'language' ])) {
}
# we are not going to change it to the current language...
if ( $_POST [ 'language' ] == $this -> getLanguage ()) {
$this -> messages -> add ( 'w' , _ ( 'still using the "' . $this -> getLanguage () . '" language!' ));
Tools :: redirect ( '?view=config' );
}
$languages = $this -> getInstalledLanguages ();
$actualLanguage = false ;
foreach ( $languages as $language ) {
if ( $language [ 'name' ] == $_POST [ 'language' ]) {
$actualLanguage = true ;
break ;
}
}
if ( ! $actualLanguage ) {
$this -> messages -> add ( 'e' , _ ( 'that language does not seem to be installed' ));
Tools :: redirect ( '?view=config' );
}
$this -> store -> updateUserConfig ( $this -> user -> getId (), 'language' , $_POST [ 'language' ]);
$this -> messages -> add ( 's' , _ ( 'you have changed your language preferences' ));
$currentConfig = $_SESSION [ 'poche_user' ] -> config ;
$currentConfig [ 'language' ] = $_POST [ 'language' ];
$_SESSION [ 'poche_user' ] -> setConfig ( $currentConfig );
Tools :: redirect ( '?view=config' );
}
2013-10-20 14:53:54 +00:00
/**
* get credentials from differents sources
* it redirects the user to the $referer link
* @ return array
*/
2013-12-23 08:09:10 +00:00
private function credentials () {
if ( isset ( $_SERVER [ 'PHP_AUTH_USER' ])) {
return array ( $_SERVER [ 'PHP_AUTH_USER' ], 'php_auth' );
}
if ( ! empty ( $_POST [ 'login' ]) && ! empty ( $_POST [ 'password' ])) {
return array ( $_POST [ 'login' ], $_POST [ 'password' ]);
}
if ( isset ( $_SERVER [ 'REMOTE_USER' ])) {
return array ( $_SERVER [ 'REMOTE_USER' ], 'http_auth' );
}
2013-12-23 09:35:09 +00:00
2013-12-23 08:09:10 +00:00
return array ( false , false );
2013-10-20 14:53:54 +00:00
}
2013-08-08 10:33:02 +00:00
/**
* checks if login & password are correct and save the user in session .
* it redirects the user to the $referer link
* @ param string $referer the url to redirect after login
* @ todo add the return value
* @ return boolean
*/
2013-08-04 19:42:46 +00:00
public function login ( $referer )
{
2013-10-20 14:53:54 +00:00
list ( $login , $password ) = $this -> credentials ();
if ( $login === false || $password === false ) {
$this -> messages -> add ( 'e' , _ ( 'login failed: you have to fill all fields' ));
Tools :: logm ( 'login failed' );
Tools :: redirect ();
}
if ( ! empty ( $login ) && ! empty ( $password )) {
$user = $this -> store -> login ( $login , Tools :: encodeString ( $password . $login ));
2013-08-06 12:18:03 +00:00
if ( $user != array ()) {
# Save login into Session
2013-12-21 19:39:45 +00:00
$longlastingsession = isset ( $_POST [ 'longlastingsession' ]);
Session :: login ( $user [ 'username' ], $user [ 'password' ], $login , Tools :: encodeString ( $password . $login ), $longlastingsession , array ( 'poche_user' => new User ( $user )));
2013-08-06 13:51:48 +00:00
$this -> messages -> add ( 's' , _ ( 'welcome to your poche' ));
Tools :: logm ( 'login successful' );
2013-08-04 19:42:46 +00:00
Tools :: redirect ( $referer );
}
2013-08-06 13:51:48 +00:00
$this -> messages -> add ( 'e' , _ ( 'login failed: bad login or password' ));
2013-08-04 19:42:46 +00:00
Tools :: logm ( 'login failed' );
Tools :: redirect ();
}
}
2013-08-08 10:33:02 +00:00
/**
* log out the poche user . It cleans the session .
* @ todo add the return value
* @ return boolean
*/
2013-08-04 19:42:46 +00:00
public function logout ()
{
2013-08-06 12:18:03 +00:00
$this -> user = array ();
2013-08-04 19:42:46 +00:00
Session :: logout ();
2013-08-07 17:14:28 +00:00
$this -> messages -> add ( 's' , _ ( 'see you soon!' ));
Tools :: logm ( 'logout' );
2013-08-04 19:42:46 +00:00
Tools :: redirect ();
}
2013-08-08 10:33:02 +00:00
/**
* import from Instapaper . poche needs a ./ instapaper - export . html file
* @ todo add the return value
2013-08-24 13:59:51 +00:00
* @ param string $targetFile the file used for importing
2013-08-08 10:33:02 +00:00
* @ return boolean
*/
2013-08-24 13:59:51 +00:00
private function importFromInstapaper ( $targetFile )
2013-08-04 19:42:46 +00:00
{
2013-08-05 08:32:15 +00:00
# TODO gestion des articles favs
2013-08-05 07:43:33 +00:00
$html = new simple_html_dom ();
2013-08-24 13:59:51 +00:00
$html -> load_file ( $targetFile );
2013-08-07 17:14:28 +00:00
Tools :: logm ( 'starting import from instapaper' );
2013-08-05 07:43:33 +00:00
$read = 0 ;
$errors = array ();
foreach ( $html -> find ( 'ol' ) as $ul )
{
foreach ( $ul -> find ( 'li' ) as $li )
{
$a = $li -> find ( 'a' );
$url = new Url ( base64_encode ( $a [ 0 ] -> href ));
2013-08-07 17:14:28 +00:00
$this -> action ( 'add' , $url , 0 , TRUE );
2013-08-05 07:43:33 +00:00
if ( $read == '1' ) {
2013-08-07 17:14:28 +00:00
$sequence = '' ;
if ( STORAGE == 'postgres' ) {
$sequence = 'entries_id_seq' ;
}
$last_id = $this -> store -> getLastId ( $sequence );
$this -> action ( 'toggle_archive' , $url , $last_id , TRUE );
2013-08-05 07:43:33 +00:00
}
}
2013-08-05 08:32:15 +00:00
# the second <ol> is for read links
2013-08-05 07:43:33 +00:00
$read = 1 ;
}
2013-08-06 13:51:48 +00:00
$this -> messages -> add ( 's' , _ ( 'import from instapaper completed' ));
2013-08-04 20:35:08 +00:00
Tools :: logm ( 'import from instapaper completed' );
Tools :: redirect ();
}
2013-08-04 19:42:46 +00:00
2013-08-08 10:33:02 +00:00
/**
* import from Pocket . poche needs a ./ ril_export . html file
* @ todo add the return value
2013-08-24 13:59:51 +00:00
* @ param string $targetFile the file used for importing
2013-08-08 10:33:02 +00:00
* @ return boolean
*/
2013-08-24 13:59:51 +00:00
private function importFromPocket ( $targetFile )
2013-08-04 20:35:08 +00:00
{
2013-08-05 08:32:15 +00:00
# TODO gestion des articles favs
2013-08-04 20:35:08 +00:00
$html = new simple_html_dom ();
2013-08-24 13:59:51 +00:00
$html -> load_file ( $targetFile );
2013-08-07 17:14:28 +00:00
Tools :: logm ( 'starting import from pocket' );
2013-08-04 20:35:08 +00:00
$read = 0 ;
$errors = array ();
foreach ( $html -> find ( 'ul' ) as $ul )
{
foreach ( $ul -> find ( 'li' ) as $li )
2013-08-04 19:42:46 +00:00
{
2013-08-04 20:35:08 +00:00
$a = $li -> find ( 'a' );
$url = new Url ( base64_encode ( $a [ 0 ] -> href ));
2013-08-07 17:14:28 +00:00
$this -> action ( 'add' , $url , 0 , TRUE );
2013-08-04 20:35:08 +00:00
if ( $read == '1' ) {
2013-08-07 17:14:28 +00:00
$sequence = '' ;
if ( STORAGE == 'postgres' ) {
$sequence = 'entries_id_seq' ;
}
$last_id = $this -> store -> getLastId ( $sequence );
$this -> action ( 'toggle_archive' , $url , $last_id , TRUE );
2013-08-04 19:42:46 +00:00
}
}
2013-08-05 08:32:15 +00:00
# the second <ul> is for read links
2013-08-04 20:35:08 +00:00
$read = 1 ;
2013-08-04 19:42:46 +00:00
}
2013-08-06 13:51:48 +00:00
$this -> messages -> add ( 's' , _ ( 'import from pocket completed' ));
2013-08-04 20:35:08 +00:00
Tools :: logm ( 'import from pocket completed' );
Tools :: redirect ();
}
2013-08-04 19:42:46 +00:00
2013-08-08 10:33:02 +00:00
/**
* import from Readability . poche needs a ./ readability file
* @ todo add the return value
2013-08-24 13:59:51 +00:00
* @ param string $targetFile the file used for importing
2013-08-08 10:33:02 +00:00
* @ return boolean
*/
2013-08-24 13:59:51 +00:00
private function importFromReadability ( $targetFile )
2013-08-04 20:35:08 +00:00
{
2013-08-05 08:32:15 +00:00
# TODO gestion des articles lus / favs
2013-08-24 13:59:51 +00:00
$str_data = file_get_contents ( $targetFile );
2013-08-04 20:35:08 +00:00
$data = json_decode ( $str_data , true );
2013-08-07 17:14:28 +00:00
Tools :: logm ( 'starting import from Readability' );
2013-08-15 09:29:28 +00:00
$count = 0 ;
2013-08-04 20:35:08 +00:00
foreach ( $data as $key => $value ) {
2013-08-15 09:29:28 +00:00
$url = NULL ;
$favorite = FALSE ;
$archive = FALSE ;
2014-01-03 14:18:13 +00:00
foreach ( $value as $item ) {
foreach ( $item as $attr => $value ) {
if ( $attr == 'article__url' ) {
$url = new Url ( base64_encode ( $value ));
2013-08-15 09:29:28 +00:00
}
2014-01-03 14:18:13 +00:00
$sequence = '' ;
if ( STORAGE == 'postgres' ) {
$sequence = 'entries_id_seq' ;
}
if ( $value == 'true' ) {
if ( $attr == 'favorite' ) {
$favorite = TRUE ;
}
if ( $attr == 'archive' ) {
$archive = TRUE ;
}
2013-08-15 09:29:28 +00:00
}
}
2014-01-03 14:18:13 +00:00
# we can add the url
if ( ! is_null ( $url ) && $url -> isCorrect ()) {
$this -> action ( 'add' , $url , 0 , TRUE );
$count ++ ;
if ( $favorite ) {
$last_id = $this -> store -> getLastId ( $sequence );
$this -> action ( 'toggle_fav' , $url , $last_id , TRUE );
}
if ( $archive ) {
$last_id = $this -> store -> getLastId ( $sequence );
$this -> action ( 'toggle_archive' , $url , $last_id , TRUE );
}
2013-08-07 17:14:28 +00:00
}
2013-08-04 19:42:46 +00:00
}
}
2013-08-15 09:29:28 +00:00
$this -> messages -> add ( 's' , _ ( 'import from Readability completed. ' . $count . ' new links.' ));
2013-08-04 20:35:08 +00:00
Tools :: logm ( 'import from Readability completed' );
Tools :: redirect ();
2013-08-04 19:42:46 +00:00
}
2013-08-08 10:33:02 +00:00
/**
* import datas into your poche
* @ param string $from name of the service to import : pocket , instapaper or readability
* @ todo add the return value
* @ return boolean
*/
2013-08-04 20:35:08 +00:00
public function import ( $from )
2013-08-04 19:42:46 +00:00
{
2013-08-24 13:59:51 +00:00
$providers = array (
'pocket' => 'importFromPocket' ,
'readability' => 'importFromReadability' ,
'instapaper' => 'importFromInstapaper'
);
if ( ! isset ( $providers [ $from ])) {
$this -> messages -> add ( 'e' , _ ( 'Unknown import provider.' ));
Tools :: redirect ();
2013-08-04 20:35:08 +00:00
}
2013-08-24 13:59:51 +00:00
$targetDefinition = 'IMPORT_' . strtoupper ( $from ) . '_FILE' ;
$targetFile = constant ( $targetDefinition );
if ( ! defined ( $targetDefinition )) {
$this -> messages -> add ( 'e' , _ ( 'Incomplete inc/poche/define.inc.php file, please define "' . $targetDefinition . '".' ));
Tools :: redirect ();
2013-08-04 20:35:08 +00:00
}
2013-08-24 13:59:51 +00:00
if ( ! file_exists ( $targetFile )) {
$this -> messages -> add ( 'e' , _ ( 'Could not find required "' . $targetFile . '" import file.' ));
Tools :: redirect ();
2013-08-04 20:35:08 +00:00
}
2013-08-24 13:59:51 +00:00
$this -> $providers [ $from ]( $targetFile );
2013-08-04 20:35:08 +00:00
}
2013-08-04 19:42:46 +00:00
2013-08-08 10:33:02 +00:00
/**
* export poche entries in json
* @ return json all poche entries
*/
2013-08-04 20:35:08 +00:00
public function export ()
{
2013-08-06 13:51:48 +00:00
$entries = $this -> store -> retrieveAll ( $this -> user -> getId ());
2013-08-04 20:35:08 +00:00
echo $this -> tpl -> render ( 'export.twig' , array (
'export' => Tools :: renderJson ( $entries ),
));
Tools :: logm ( 'export view' );
2013-08-04 19:42:46 +00:00
}
2013-08-05 10:34:16 +00:00
2013-08-08 10:33:02 +00:00
/**
2013-08-08 11:49:57 +00:00
* Checks online the latest version of poche and cache it
2013-08-08 10:33:02 +00:00
* @ param string $which 'prod' or 'dev'
* @ return string latest $which version
*/
2013-08-05 10:34:16 +00:00
private function getPocheVersion ( $which = 'prod' )
{
$cache_file = CACHE . '/' . $which ;
2013-08-08 11:49:57 +00:00
# checks if the cached version file exists
2013-08-05 10:34:16 +00:00
if ( file_exists ( $cache_file ) && ( filemtime ( $cache_file ) > ( time () - 86400 ))) {
$version = file_get_contents ( $cache_file );
} else {
2013-08-07 12:24:07 +00:00
$version = file_get_contents ( 'http://static.inthepoche.com/versions/' . $which );
2013-08-05 10:34:16 +00:00
file_put_contents ( $cache_file , $version , LOCK_EX );
}
return $version ;
}
2013-12-03 09:40:27 +00:00
public function generateToken ()
{
if ( ini_get ( 'open_basedir' ) === '' ) {
$token = substr ( base64_encode ( file_get_contents ( '/dev/urandom' , false , null , 0 , 20 )), 0 , 15 );
}
else {
$token = substr ( base64_encode ( uniqid ( mt_rand (), true )), 0 , 20 );
}
$this -> store -> updateUserConfig ( $this -> user -> getId (), 'token' , $token );
$currentConfig = $_SESSION [ 'poche_user' ] -> config ;
$currentConfig [ 'token' ] = $token ;
$_SESSION [ 'poche_user' ] -> setConfig ( $currentConfig );
}
2013-12-06 13:37:42 +00:00
public function generateFeeds ( $token , $user_id , $tag_id , $type = 'home' )
2013-12-03 09:40:27 +00:00
{
2013-12-06 13:37:42 +00:00
$allowed_types = array ( 'home' , 'fav' , 'archive' , 'tag' );
2013-12-03 09:40:27 +00:00
$config = $this -> store -> getConfigUser ( $user_id );
if ( ! in_array ( $type , $allowed_types ) ||
$token != $config [ 'token' ]) {
die ( _ ( 'Uh, there is a problem while generating feeds.' ));
}
// Check the token
2013-12-06 09:14:59 +00:00
$feed = new FeedWriter ( RSS2 );
2013-12-03 09:40:27 +00:00
$feed -> setTitle ( 'poche - ' . $type . ' feed' );
$feed -> setLink ( Tools :: getPocheUrl ());
2013-12-06 09:14:59 +00:00
$feed -> setChannelElement ( 'updated' , date ( DATE_RSS , time ()));
2013-12-03 09:40:27 +00:00
$feed -> setChannelElement ( 'author' , 'poche' );
2013-12-06 13:37:42 +00:00
if ( $type == 'tag' ) {
$entries = $this -> store -> retrieveEntriesByTag ( $tag_id );
}
else {
$entries = $this -> store -> getEntriesByView ( $type , $user_id );
}
2013-12-03 09:40:27 +00:00
if ( count ( $entries ) > 0 ) {
foreach ( $entries as $entry ) {
$newItem = $feed -> createNewItem ();
2014-01-03 09:15:05 +00:00
$newItem -> setTitle ( $entry [ 'title' ]);
2013-12-03 09:40:27 +00:00
$newItem -> setLink ( Tools :: getPocheUrl () . '?view=view&id=' . $entry [ 'id' ]);
$newItem -> setDate ( time ());
$newItem -> setDescription ( $entry [ 'content' ]);
$feed -> addItem ( $newItem );
}
}
$feed -> genarateFeed ();
exit ;
}
2013-10-20 14:53:54 +00:00
}