* Genarate RSS2 or JSON (original: RSS 1.0, RSS2.0 and ATOM Feed)\r
*\r
* Modified for FiveFilters.org's Full-Text RSS project\r
- * to allow for inclusion of hubs, JSON output. \r
+ * to allow for inclusion of hubs, JSON output.\r
* Stripped RSS1 and ATOM support.\r
- * \r
+ *\r
* @package UnivarselFeedWriter\r
* @author Anis uddin Ahmad <anisniit@gmail.com>\r
* @link http://www.ajaxray.com/projects/rss\r
private $CDATAEncoding = array(); // The tag names which have to encoded as CDATA\r
private $xsl = null; // stylesheet to render RSS (used by Chrome)\r
private $json = null; // JSON object\r
- \r
- private $version = null; \r
- \r
+\r
+ private $version = null;\r
+\r
/**\r
* Constructor\r
- * \r
- * @param constant the version constant (RSS2 or JSON). \r
- */ \r
+ *\r
+ * @param constant the version constant (RSS2 or JSON).\r
+ */\r
function __construct($version = RSS2)\r
- { \r
+ {\r
$this->version = $version;\r
- \r
+\r
// Setting default value for assential channel elements\r
$this->channels['title'] = $version . ' Feed';\r
$this->channels['link'] = 'http://www.ajaxray.com/blog';\r
- \r
+\r
//Tag names to encode in CDATA\r
$this->CDATAEncoding = array('description', 'content:encoded', 'content', 'subtitle', 'summary');\r
}\r
- \r
+\r
public function setFormat($format) {\r
$this->version = $format;\r
}\r
\r
// Start # public functions ---------------------------------------------\r
- \r
+\r
/**\r
* Set a channel element\r
* @access public\r
{\r
$this->channels[$elementName] = $content ;\r
}\r
- \r
+\r
/**\r
- * Set multiple channel elements from an array. Array elements \r
+ * Set multiple channel elements from an array. Array elements\r
* should be 'channelName' => 'channelContent' format.\r
- * \r
+ *\r
* @access public\r
* @param array array of channels\r
* @return void\r
public function setChannelElementsFromArray($elementArray)\r
{\r
if(! is_array($elementArray)) return;\r
- foreach ($elementArray as $elementName => $content) \r
+ foreach ($elementArray as $elementName => $content)\r
{\r
$this->setChannelElement($elementName, $content);\r
}\r
}\r
- \r
+\r
/**\r
* Genarate the actual RSS/JSON file\r
- * \r
+ *\r
* @access public\r
* @return void\r
- */ \r
+ */\r
public function genarateFeed()\r
{\r
if ($this->version == RSS2) {\r
- header('Content-type: text/xml; charset=UTF-8');\r
+// header('Content-type: text/xml; charset=UTF-8');\r
// this line prevents Chrome 20 from prompting download\r
// used by Google: https://news.google.com/news/feeds?ned=us&topic=b&output=rss\r
- header('X-content-type-options: nosniff');\r
+// header('X-content-type-options: nosniff');\r
} elseif ($this->version == JSON) {\r
- header('Content-type: application/json; charset=UTF-8');\r
+// header('Content-type: application/json; charset=UTF-8');\r
$this->json = new stdClass();\r
} elseif ($this->version == JSONP) {\r
- header('Content-type: application/javascript; charset=UTF-8');\r
+// header('Content-type: application/javascript; charset=UTF-8');\r
$this->json = new stdClass();\r
}\r
$this->printHead();\r
echo json_encode($this->json);\r
}\r
}\r
- \r
+\r
/**\r
* Create a new FeedItem.\r
- * \r
+ *\r
* @access public\r
* @return object instance of FeedItem class\r
*/\r
$Item = new FeedItem($this->version);\r
return $Item;\r
}\r
- \r
+\r
/**\r
* Add a FeedItem to the main class\r
- * \r
+ *\r
* @access public\r
* @param object instance of FeedItem class\r
* @return void\r
*/\r
public function addItem($feedItem)\r
{\r
- $this->items[] = $feedItem; \r
+ $this->items[] = $feedItem;\r
}\r
- \r
+\r
// Wrapper functions -------------------------------------------------------------------\r
- \r
+\r
/**\r
* Set the 'title' channel element\r
- * \r
+ *\r
* @access public\r
* @param srting value of 'title' channel tag\r
* @return void\r
{\r
$this->setChannelElement('title', $title);\r
}\r
- \r
+\r
/**\r
* Add a hub to the channel element\r
- * \r
+ *\r
* @access public\r
* @param string URL\r
* @return void\r
*/\r
public function addHub($hub)\r
{\r
- $this->hubs[] = $hub; \r
+ $this->hubs[] = $hub;\r
}\r
- \r
+\r
/**\r
* Set XSL URL\r
- * \r
+ *\r
* @access public\r
* @param string URL\r
* @return void\r
*/\r
public function setXsl($xsl)\r
{\r
- $this->xsl = $xsl; \r
- } \r
- \r
+ $this->xsl = $xsl;\r
+ }\r
+\r
/**\r
* Set self URL\r
- * \r
+ *\r
* @access public\r
* @param string URL\r
* @return void\r
*/\r
public function setSelf($self)\r
{\r
- $this->self = $self; \r
- } \r
- \r
+ $this->self = $self;\r
+ }\r
+\r
/**\r
* Set the 'description' channel element\r
- * \r
+ *\r
* @access public\r
* @param srting value of 'description' channel tag\r
* @return void\r
*/\r
public function setDescription($desciption)\r
{\r
- $tag = ($this->version == ATOM)? 'subtitle' : 'description'; \r
+ $tag = ($this->version == ATOM)? 'subtitle' : 'description';\r
$this->setChannelElement($tag, $desciption);\r
}\r
- \r
+\r
/**\r
* Set the 'link' channel element\r
- * \r
+ *\r
* @access public\r
* @param srting value of 'link' channel tag\r
* @return void\r
{\r
$this->setChannelElement('link', $link);\r
}\r
- \r
+\r
/**\r
* Set the 'image' channel element\r
- * \r
+ *\r
* @access public\r
* @param srting title of image\r
* @param srting link url of the imahe\r
{\r
$this->setChannelElement('image', array('title'=>$title, 'link'=>$link, 'url'=>$url));\r
}\r
- \r
+\r
// End # public functions ----------------------------------------------\r
- \r
+\r
// Start # private functions ----------------------------------------------\r
- \r
+\r
/**\r
* Prints the xml and rss namespace\r
- * \r
+ *\r
* @access private\r
* @return void\r
*/\r
$this->json->rss = array('@attributes' => array('version' => '2.0'));\r
}\r
}\r
- \r
+\r
/**\r
* Closes the open tags at the end of file\r
- * \r
+ *\r
* @access private\r
* @return void\r
*/\r
{\r
if ($this->version == RSS2)\r
{\r
- echo '</channel>',PHP_EOL,'</rss>'; \r
- } \r
+ echo '</channel>',PHP_EOL,'</rss>';\r
+ }\r
// do nothing for JSON\r
}\r
\r
/**\r
* Creates a single node as xml format\r
- * \r
+ *\r
* @access private\r
* @param string name of the tag\r
* @param mixed tag value as string or array of nested tags in 'tagName' => 'tagValue' format\r
* @return string formatted xml tag\r
*/\r
private function makeNode($tagName, $tagContent, $attributes = null)\r
- { \r
+ {\r
if ($this->version == RSS2)\r
{\r
$nodeText = '';\r
$attrText = '';\r
if (is_array($attributes))\r
{\r
- foreach ($attributes as $key => $value) \r
+ foreach ($attributes as $key => $value)\r
{\r
$attrText .= " $key=\"$value\" ";\r
}\r
}\r
$nodeText .= "<{$tagName}{$attrText}>";\r
if (is_array($tagContent))\r
- { \r
- foreach ($tagContent as $key => $value) \r
+ {\r
+ foreach ($tagContent as $key => $value)\r
{\r
$nodeText .= $this->makeNode($key, $value);\r
}\r
{\r
//$nodeText .= (in_array($tagName, $this->CDATAEncoding))? $tagContent : htmlentities($tagContent);\r
$nodeText .= htmlspecialchars($tagContent);\r
- } \r
+ }\r
//$nodeText .= (in_array($tagName, $this->CDATAEncoding))? "]]></$tagName>" : "</$tagName>";\r
$nodeText .= "</$tagName>";\r
return $nodeText . PHP_EOL;\r
}\r
return ''; // should not get here\r
}\r
- \r
+\r
private function json_keys(array $array) {\r
$new = array();\r
foreach ($array as $key => $val) {\r
}\r
return $new;\r
}\r
- \r
+\r
/**\r
* @desc Print channels\r
* @access private\r
{\r
//Start channel tag\r
if ($this->version == RSS2) {\r
- echo '<channel>' . PHP_EOL; \r
+ echo '<channel>' . PHP_EOL;\r
// add hubs\r
foreach ($this->hubs as $hub) {\r
//echo $this->makeNode('link', '', array('rel'=>'hub', 'href'=>$hub, 'xmlns'=>'http://www.w3.org/2005/Atom'));\r
echo '<link rel="self" href="'.htmlspecialchars($this->self).'" xmlns="http://www.w3.org/2005/Atom" />' . PHP_EOL;\r
}\r
//Print Items of channel\r
- foreach ($this->channels as $key => $value) \r
+ foreach ($this->channels as $key => $value)\r
{\r
echo $this->makeNode($key, $value);\r
}\r
$this->json->rss['channel'] = (object)$this->json_keys($this->channels);\r
}\r
}\r
- \r
+\r
/**\r
* Prints formatted feed items\r
- * \r
+ *\r
* @access private\r
* @return void\r
*/\r
private function printItems()\r
- { \r
+ {\r
foreach ($this->items as $item) {\r
$itemElements = $item->getElements();\r
- \r
+\r
echo $this->startItem();\r
- \r
+\r
if ($this->version == JSON || $this->version == JSONP) {\r
$json_item = array();\r
}\r
- \r
+\r
foreach ($itemElements as $thisElement) {\r
- foreach ($thisElement as $instance) { \r
+ foreach ($thisElement as $instance) {\r
if ($this->version == RSS2) {\r
echo $this->makeNode($instance['name'], $instance['content'], $instance['attributes']);\r
} elseif ($this->version == JSON || $this->version == JSONP) {\r
}\r
}\r
}\r
- \r
+\r
/**\r
* Make the starting tag of channels\r
- * \r
+ *\r
* @access private\r
* @return void\r
*/\r
{\r
if ($this->version == RSS2)\r
{\r
- echo '<item>' . PHP_EOL; \r
- } \r
+ echo '<item>' . PHP_EOL;\r
+ }\r
// nothing for JSON\r
}\r
- \r
+\r
/**\r
* Closes feed item tag\r
- * \r
+ *\r
* @access private\r
* @return void\r
*/\r
{\r
if ($this->version == RSS2)\r
{\r
- echo '</item>' . PHP_EOL; \r
- } \r
+ echo '</item>' . PHP_EOL;\r
+ }\r
// nothing for JSON\r
}\r
- \r
+\r
// End # private functions ----------------------------------------------\r
}
\ No newline at end of file
'default' => 'ORDER BY entries.id'
);
- function __construct()
+ function __construct()
{
switch (STORAGE) {
case 'sqlite':
break;
case 'mysql':
$db_path = 'mysql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB;
- $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD);
+ $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD);
break;
case 'postgres':
$db_path = 'pgsql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB;
- $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD);
+ $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD);
break;
}
}
$hasAdmin = count($query->fetchAll());
- if ($hasAdmin == 0)
+ if ($hasAdmin == 0)
return false;
return true;
$sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)';
$params = array($id_user, 'language', LANG);
$query = $this->executeQuery($sql, $params);
-
+
$sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)';
$params = array($id_user, 'theme', DEFAULT_THEME);
$query = $this->executeQuery($sql, $params);
$query = $this->executeQuery($sql, array($id));
$result = $query->fetchAll();
$user_config = array();
-
+
foreach ($result as $key => $value) {
$user_config[$value['name']] = $value['value'];
}
$params_update = array($password, $userId);
$query = $this->executeQuery($sql_update, $params_update);
}
-
+
public function updateUserConfig($userId, $key, $value) {
$config = $this->getConfigUser($userId);
-
+
if (! isset($config[$key])) {
$sql = "INSERT INTO users_config (value, user_id, name) VALUES (?, ?, ?)";
}
return $entries;
}
+ public function retrieveUnfetchedEntriesCount($user_id) {
+ $sql = "SELECT count(*) FROM entries WHERE (content = '' OR content IS NULL) AND user_id=?";
+ $query = $this->executeQuery($sql, array($user_id));
+ list($count) = $query->fetch();
+
+ return $count;
+ }
+
public function retrieveAll($user_id) {
- $sql = "SELECT * FROM entries WHERE content <> '' AND user_id=? ORDER BY id";
+ $sql = "SELECT * FROM entries WHERE user_id=? ORDER BY id";
$query = $this->executeQuery($sql, array($user_id));
$entries = $query->fetchAll();
public function retrieveOneByURL($url, $user_id) {
$entry = NULL;
- $sql = "SELECT * FROM entries WHERE content <> '' AND url=? AND user_id=?";
+ $sql = "SELECT * FROM entries WHERE url=? AND user_id=?";
$params = array($url, $user_id);
$query = $this->executeQuery($sql, $params);
$entry = $query->fetchAll();
public function getEntriesByView($view, $user_id, $limit = '', $tag_id = 0) {
switch ($view) {
case 'archive':
- $sql = "SELECT * FROM entries WHERE content <> '' AND user_id=? AND is_read=? ";
+ $sql = "SELECT * FROM entries WHERE user_id=? AND is_read=? ";
$params = array($user_id, 1);
break;
case 'fav' :
- $sql = "SELECT * FROM entries WHERE content <> '' AND user_id=? AND is_fav=? ";
+ $sql = "SELECT * FROM entries WHERE user_id=? AND is_fav=? ";
$params = array($user_id, 1);
break;
case 'tag' :
$sql = "SELECT entries.* FROM entries
LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id
- WHERE entries.content <> '' AND
- entries.user_id=? AND tags_entries.tag_id = ? ";
+ WHERE entries.user_id=? AND tags_entries.tag_id = ? ";
$params = array($user_id, $tag_id);
break;
default:
- $sql = "SELECT * FROM entries WHERE content <> '' AND user_id=? AND is_read=? ";
+ $sql = "SELECT * FROM entries WHERE user_id=? AND is_read=? ";
$params = array($user_id, 0);
break;
}
public function getEntriesByViewCount($view, $user_id, $tag_id = 0) {
switch ($view) {
case 'archive':
- $sql = "SELECT count(*) FROM entries WHERE content <> '' AND user_id=? AND is_read=? ";
+ $sql = "SELECT count(*) FROM entries WHERE user_id=? AND is_read=? ";
$params = array($user_id, 1);
break;
case 'fav' :
- $sql = "SELECT count(*) FROM entries WHERE content <> '' AND user_id=? AND is_fav=? ";
+ $sql = "SELECT count(*) FROM entries WHERE user_id=? AND is_fav=? ";
$params = array($user_id, 1);
break;
case 'tag' :
$sql = "SELECT count(*) FROM entries
LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id
- WHERE entries.content <> '' AND
- entries.user_id=? AND tags_entries.tag_id = ? ";
+ WHERE entries.user_id=? AND tags_entries.tag_id = ? ";
$params = array($user_id, $tag_id);
break;
default:
- $sql = "SELECT count(*) FROM entries WHERE content <> '' AND user_id=? AND is_read=? ";
+ $sql = "SELECT count(*) FROM entries WHERE user_id=? AND is_read=? ";
$params = array($user_id, 0);
break;
}
return $query;
}
- public function add($url, $title, $content, $user_id) {
- $sql_action = 'INSERT INTO entries ( url, title, content, user_id ) VALUES (?, ?, ?, ?)';
- $params_action = array($url, $title, $content, $user_id);
- $query = $this->executeQuery($sql_action, $params_action);
- return $query;
+ /**
+ *
+ * @param string $url
+ * @param string $title
+ * @param string $content
+ * @param integer $user_id
+ * @return integer $id of inserted record
+ */
+ public function add($url, $title, $content, $user_id, $isFavorite=0, $isRead=0) {
+ $sql_action = 'INSERT INTO entries ( url, title, content, user_id, is_fav, is_read ) VALUES (?, ?, ?, ?, ?, ?)';
+ $params_action = array($url, $title, $content, $user_id, $isFavorite, $isRead);
+ if ( !$this->executeQuery($sql_action, $params_action) ) {
+ $id = null;
+ }
+ else {
+ $id = intval($this->getLastId( (STORAGE == 'postgres') ? 'users_id_seq' : '' ));
+ }
+ return $id;
}
public function deleteById($id, $user_id) {
public function getLastId($column = '') {
return $this->getHandle()->lastInsertId($column);
}
-
+
public function search($term){
$search = '%'.$term.'%';
$query = $this->getHandle()->prepare("SELECT * FROM entries WHERE content LIKE ? OR title LIKE ? OR url LIKE ?"); //searches in content, title and URL
$sql = "SELECT DISTINCT tags.*, count(entries.id) AS entriescount FROM tags
LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id
LEFT JOIN entries ON tags_entries.entry_id=entries.id
- WHERE entries.content <> '' AND entries.user_id=?
+ WHERE entries.user_id=?
". (($term) ? "AND lower(tags.value) LIKE ?" : '') ."
GROUP BY tags.id, tags.value
ORDER BY tags.value";
$sql = "SELECT DISTINCT tags.* FROM tags
LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id
LEFT JOIN entries ON tags_entries.entry_id=entries.id
- WHERE entries.content <> '' AND tags.id=? AND entries.user_id=?";
+ WHERE tags.id=? AND entries.user_id=?";
$params = array(intval($id), $user_id);
$query = $this->executeQuery($sql, $params);
$tag = $query->fetchAll();
}
public function retrieveEntriesByTag($tag_id, $user_id) {
- $sql =
+ $sql =
"SELECT entries.* FROM entries
LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id
- WHERE entries.content <> '' AND
- tags_entries.tag_id = ? AND entries.user_id=?";
+ WHERE tags_entries.tag_id = ? AND entries.user_id=?";
$query = $this->executeQuery($sql, array($tag_id, $user_id));
$entries = $query->fetchAll();
}
public function retrieveTagsByEntry($entry_id) {
- $sql =
+ $sql =
"SELECT tags.* FROM tags
LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id
WHERE tags_entries.entry_id = ?";
public $tpl;
public $messages;
public $pagination;
-
+
private $currentTheme = '';
private $currentLanguage = '';
private $notInstalledMessage = array();
if ($this->configFileIsAvailable()) {
$this->init();
}
-
+
if ($this->themeIsInstalled()) {
$this->initTpl();
}
-
+
if ($this->systemIsInstalled()) {
$this->store = new Database();
$this->messages = new Messages();
$this->store->checkTags();
}
}
-
- private function init()
+
+ private function init()
{
Tools::initPhp();
$language = $this->user->getConfigValue('language');
putenv('LC_ALL=' . $language);
setlocale(LC_ALL, $language);
- bindtextdomain($language, LOCALE);
- textdomain($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;
# Set up language
$languageDirectory = $this->user->getConfigValue('language');
-
+
if ($languageDirectory === false) {
$languageDirectory = DEFAULT_THEME;
}
-
+
$this->currentLanguage = $languageDirectory;
}
return true;
}
-
+
public function themeIsInstalled() {
$passTheme = TRUE;
# Twig is an absolute requirement for Poche to function. Abort immediately if the Composer installer hasn't been run yet
self::$canRenderTemplates = false;
$passTheme = FALSE;
- }
-
+ }
+
# Check if the selected theme and its requirements are present
$theme = $this->getTheme();
if ($theme != '' && ! is_dir(THEME . '/' . $theme)) {
$this->notInstalledMessage[] = 'The currently selected theme (' . $theme . ') does not seem to be properly installed (Missing directory: ' . THEME . '/' . $theme . ')';
-
+
self::$canRenderTemplates = false;
-
+
$passTheme = FALSE;
}
-
+
$themeInfo = $this->getThemeInfo($theme);
if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) {
foreach ($themeInfo['requirements'] as $requiredTheme) {
if (! is_dir(THEME . '/' . $requiredTheme)) {
$this->notInstalledMessage[] = 'The required "' . $requiredTheme . '" theme is missing for the current theme (' . $theme . ')';
-
+
self::$canRenderTemplates = false;
-
+
$passTheme = FALSE;
}
}
return FALSE;
}
-
+
return true;
}
-
+
/**
* all checks before installation.
* @todo move HTML to template
- * @return boolean
+ * @return boolean
*/
public function systemIsInstalled()
{
$msg = TRUE;
-
+
$configSalt = defined('SALT') ? constant('SALT') : '';
-
+
if (empty($configSalt)) {
$this->notInstalledMessage[] = 'You have not yet filled in the SALT value in the config.inc.php file.';
$msg = FALSE;
return true;
}
-
+
public function getNotInstalledMessage() {
return $this->notInstalledMessage;
}
{
$loaderChain = new Twig_Loader_Chain();
$theme = $this->getTheme();
-
+
# 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 . '/' . $theme));
# @todo isInstalled() should catch this, inject Twig later
die('The currently selected theme (' . $theme . ') does not seem to be properly installed (' . THEME . '/' . $theme .' is missing)');
}
-
+
# add all required themes to the loader chain
$themeInfo = $this->getThemeInfo($theme);
if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) {
}
}
}
-
+
if (DEBUG_POCHE) {
$twigParams = array();
} else {
$twigParams = array('cache' => CACHE);
}
-
+
$this->tpl = new Twig_Environment($loaderChain, $twigParams);
$this->tpl->addExtension(new Twig_Extensions_Extension_I18n());
-
+
# filter to display domain name of an url
$filter = new Twig_SimpleFilter('getDomain', 'Tools::getDomain');
$this->tpl->addFilter($filter);
'poche_url' => Tools::getPocheUrl()
));
if (isset($_GET['install'])) {
- if (($_POST['password'] == $_POST['password_repeat'])
+ if (($_POST['password'] == $_POST['password_repeat'])
&& $_POST['password'] != "" && $_POST['login'] != "") {
# let's rock, install poche baby !
if ($this->store->install($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login'])))
}
exit();
}
-
+
public function getTheme() {
return $this->currentTheme;
}
if (is_file($themeIniFile) && is_readable($themeIniFile)) {
$themeInfo = parse_ini_file($themeIniFile);
}
-
+
if ($themeInfo === false) {
$themeInfo = array();
}
return $themeInfo;
}
-
+
public function getInstalledThemes() {
$handle = opendir(THEME);
$themes = array();
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('..', '.', 'tools'))) {
continue;
}
-
+
$current = false;
-
+
if ($language === $this->getLanguage()) {
$current = true;
}
-
+
$languages[] = array('name' => (isset($this->language_names[$language]) ? $this->language_names[$language] : $language), 'value' => $language, 'current' => $current);
}
-
+
return $languages;
}
public function getDefaultConfig()
- {
+ {
return array(
'pager' => PAGINATION,
'language' => LANG,
$body = '';
}
- //search for possible duplicate if not in import mode
+ //search for possible duplicate
$duplicate = NULL;
if (!$import) {
- $duplicate = $this->store->retrieveOneByURL($url->getUrl(), $this->user->getId());
+ $duplicate = $this->store->retrieveOneByURL($url->getUrl(), $this->user->getId());
}
- if ($this->store->add($url->getUrl(), $title, $body, $this->user->getId())) {
+ $last_id = $this->store->add($url->getUrl(), $title, $body, $this->user->getId());
+ if ( $last_id && !$import ) {
Tools::logm('add link ' . $url->getUrl());
- $sequence = '';
- if (STORAGE == 'postgres') {
- $sequence = 'entries_id_seq';
- }
- $last_id = $this->store->getLastId($sequence);
if (DOWNLOAD_PICTURES) {
$content = filtre_picture($body, $url->getUrl(), $last_id);
Tools::logm('updating content article');
}
}
- if (!$import) {
- $this->messages->add('s', _('the link has been added successfully'));
- }
+ $this->messages->add('s', _('the link has been added successfully'));
}
else {
if (!$import) {
'tags' => $tags,
);
break;
-
+
case 'search':
if (isset($_GET['search'])){
$search = $_GET['search'];
'nb_results' => '',
'listmode' => (isset($_COOKIE['listmode']) ? true : false),
);
-
+
//if id is given - we retrive entries by tag: id is tag id
if ($id) {
$tpl_vars['tag'] = $this->store->retrieveTag($id, $this->user->getId());
}
/**
- * update the password of the current user.
- * if MODE_DEMO is TRUE, the password can't be updated.
+ * 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
}
}
}
-
+
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 (array_keys($themes) as $theme) {
if ($theme == $_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);
$this->emptyCache();
-
+
Tools::redirect('?view=config');
}
# 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['value'] == $_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);
$this->emptyCache();
-
+
Tools::redirect('?view=config');
- }
+ }
/**
* get credentials from differents sources
* it redirects the user to the $referer link
/**
* log out the poche user. It cleans the session.
* @todo add the return value
- * @return boolean
+ * @return boolean
*/
public function logout()
{
* import from Pocket. poche needs a ./ril_export.html file
* @todo add the return value
* @param string $targetFile the file used for importing
- * @return boolean
+ * @return boolean
*/
private function importFromPocket($targetFile)
{
$this->action('add_tag',$url,$last_id,true,false,$tags);
}
}
-
+
# the second <ul> is for read links
$read = 1;
}
* import from Readability. poche needs a ./readability file
* @todo add the return value
* @param string $targetFile the file used for importing
- * @return boolean
+ * @return boolean
*/
private function importFromReadability($targetFile)
{
/**
* import from Poche exported file
* @param string $targetFile the file used for importing
- * @return boolean
+ * @return boolean
*/
private function importFromPoche($targetFile)
{
$url = new Url(base64_encode($value['url']));
$favorite = ($value['is_fav'] == -1);
$archive = ($value['is_read'] == -1);
-
+
# 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_archive', $url, $last_id, TRUE);
}
}
-
+
}
unlink($targetFile);
/**
* 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
+ * @return boolean
*/
- public function import($from)
- {
- $providers = array(
- 'pocket' => 'importFromPocket',
- 'readability' => 'importFromReadability',
- 'instapaper' => 'importFromInstapaper',
- 'poche' => 'importFromPoche',
- );
-
- if (! isset($providers[$from])) {
- $this->messages->add('e', _('Unknown import provider.'));
- Tools::redirect();
+ public function import() {
+
+ if ( isset($_FILES['file']) ) {
+ // assume, that file is in json format
+ $str_data = file_get_contents($_FILES['file']['tmp_name']);
+ $data = json_decode($str_data, true);
+
+ if ( $data === null ) {
+ //not json - assume html
+ $html = new simple_html_dom();
+ $html->load_file($_FILES['file']['tmp_name']);
+ $data = array();
+ $read = 0;
+ foreach (array('ol','ul') as $list) {
+ foreach ($html->find($list) as $ul) {
+ foreach ($ul->find('li') as $li) {
+ $tmpEntry = array();
+ $a = $li->find('a');
+ $tmpEntry['url'] = $a[0]->href;
+ $tmpEntry['tags'] = $a[0]->tags;
+ $tmpEntry['is_read'] = $read;
+ if ($tmpEntry['url']) {
+ $data[] = $tmpEntry;
+ }
+ }
+ # the second <ol/ul> is for read links
+ $read = ((sizeof($data) && $read)?0:1);
+ }
+ }
}
-
- $targetFile = CACHE . '/' . constant(strtoupper($from) . '_FILE');
-
- if (! file_exists($targetFile)) {
- $this->messages->add('e', _('Could not find required "' . $targetFile . '" import file.'));
- Tools::redirect();
+
+ $i = 0; //counter for articles inserted
+ foreach ($data as $record) {
+ //echo '<pre>';
+ //var_dump($record);
+ // foreach ($record as $key=>$val) {
+ // echo "\n=================\n$i: $key: $val\n";
+ // }
+ // exit;
+
+ $url = trim($record['url']);
+ if ( $url ) {
+ $title = (isset($record['title']) ? $record['title'] : _('Untitled - Import - ').'</a> <a href="./?import">'._('click to finish import').'</a><a>');
+ $body = (isset($record['content']) ? $record['content'] : '');
+ $isRead = (isset($record['is_read']) ? intval($record['is_read']) : 0);
+ $isFavorite = (isset($record['is_fav']) ? intval($record['is_fav']) : 0);
+ //insert new record
+ $id = $this->store->add($url, $title, $body, $this->user->getId(), $isFavorite, $isRead);
+ if ( $id ) {
+ //increment no of records inserted
+ $i++;
+ if ( isset($record['tags']) && trim($record['tags']) ) {
+ //@TODO: set tags
+
+ }
+ }
+ }
+ }
+
+ if ( $i > 0 ) {
+ $this->messages->add('s', _('Articles inserted: ').$i._('. Please note, that some may be marked as "read".'));
+ }
+ }
+ //file parsing finished here
+
+ //now download article contents if any
+
+ //check if we need to download any content
+ $recordsDownloadRequired = $this->store->retrieveUnfetchedEntriesCount($this->user->getId());
+ if ( $recordsDownloadRequired == 0 ) {
+ //nothing to download
+ $this->messages->add('s', _('Import finished.'));
+ Tools::redirect();
+ }
+ else {
+ //if just inserted - don't download anything, download will start in next reload
+ if ( !isset($_FILES['file']) ) {
+ //download next batch
+ $items = $this->store->retrieveUnfetchedEntries($this->user->getId(), IMPORT_LIMIT);
+
+ $config = HTMLPurifier_Config::createDefault();
+ $config->set('Cache.SerializerPath', CACHE);
+ $purifier = new HTMLPurifier($config);
+
+ foreach ($items as $item) {
+ $url = new Url(base64_encode($item['url']));
+ $content = Tools::getPageContent($url);
+
+ $title = (($content['rss']['channel']['item']['title'] != '') ? $content['rss']['channel']['item']['title'] : _('Untitled'));
+ $body = (($content['rss']['channel']['item']['description'] != '') ? $content['rss']['channel']['item']['description'] : _('Undefined'));
+
+ //clean content to prevent xss attack
+ $title = $purifier->purify($title);
+ $body = $purifier->purify($body);
+
+ $this->store->updateContentAndTitle($item['id'], $title, $body, $this->user->getId());
+ }
+
}
-
- $this->$providers[$from]($targetFile);
+ }
+
+ return array('includeImport'=>true, 'import'=>array('recordsDownloadRequired'=>$recordsDownloadRequired, 'recordsUnderDownload'=> IMPORT_LIMIT, 'delay'=> IMPORT_DELAY * 1000) );
}
public function uploadFile() {
- if(isset($_FILES['file']))
- {
+ if (isset($_FILES['file']))
+ {
$dir = CACHE . '/';
$file = basename($_FILES['file']['name']);
if(move_uploaded_file($_FILES['file']['tmp_name'], $dir . $file)) {
$this->messages->add('e', _('Error while importing file. Do you have access to upload it?'));
}
}
-
+
Tools::redirect('?view=config');
}
{
$filename = "wallabag-export-".$this->user->getId()."-".date("Y-m-d").".json";
header('Content-Disposition: attachment; filename='.$filename);
-
+
$entries = $this->store->retrieveAll($this->user->getId());
echo $this->tpl->render('export.twig', array(
'export' => Tools::renderJson($entries),
* @copyright 2013
* @license http://www.wtfpl.net/ see COPYING file
*/
-
+
class Tools
{
public static function initPhp()
&& (strtolower($_SERVER['HTTPS']) == 'on'))
|| (isset($_SERVER["SERVER_PORT"])
&& $_SERVER["SERVER_PORT"] == '443') // HTTPS detection.
- || (isset($_SERVER["SERVER_PORT"]) //Custom HTTPS port detection
+ || (isset($_SERVER["SERVER_PORT"]) //Custom HTTPS port detection
&& $_SERVER["SERVER_PORT"] == SSL_PORT)
|| (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
&& $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https');
);
# only download page lesser than 4MB
- $data = @file_get_contents($url, false, $context, -1, 4000000);
+ $data = @file_get_contents($url, false, $context, -1, 4000000);
if (isset($http_response_header) and isset($http_response_header[0])) {
$httpcodeOK = isset($http_response_header) and isset($http_response_header[0]) and ((strpos($http_response_header[0], '200 OK') !== FALSE) or (strpos($http_response_header[0], '301 Moved Permanently') !== FALSE));
}
}
- public static function encodeString($string)
+ public static function encodeString($string)
{
return sha1($string . SALT);
}
define ('PAGINATION', '10');
-define ('POCKET_FILE', '/ril_export.html');
-define ('READABILITY_FILE', '/readability');
-define ('INSTAPAPER_FILE', '/instapaper-export.html');
-define ('POCHE_FILE', '/poche-export');
-
-define ('IMPORT_POCKET_FILE', ROOT . POCKET_FILE);
-define ('IMPORT_READABILITY_FILE', ROOT . READABILITY_FILE);
-define ('IMPORT_INSTAPAPER_FILE', ROOT . INSTAPAPER_FILE);
-define ('IMPORT_POCHE_FILE', ROOT . POCHE_FILE);
\ No newline at end of file
+//limit for download of articles during import
+define ('IMPORT_LIMIT', 5);
+//delay between downloads (in sec)
+define ('IMPORT_DELAY', 5);
+
if (! empty($notInstalledMessage)) {
if (! Poche::$canRenderTemplates || ! Poche::$configFileAvailable) {
- # We cannot use Twig to display the error message
+ # We cannot use Twig to display the error message
echo '<h1>Errors</h1><ol>';
foreach ($notInstalledMessage as $message) {
echo '<li>' . $message . '</li>';
# Update password
$poche->updatePassword();
} elseif (isset($_GET['import'])) {
- $import = $poche->import($_GET['from']);
+ $import = $poche->import();
+ $tpl_vars = array_merge($tpl_vars, $import);
} elseif (isset($_GET['download'])) {
Tools::download_db();
} elseif (isset($_GET['empty-cache'])) {
--- /dev/null
+<script type="text/javascript">
+<!--
+ $(document).ready(function() {
+ $("body").css("cursor", "wait");
+
+ setTimeout(function(){
+ window.location = '/?import';
+ }, {{ import.delay }} );
+ });
+//-->
+</script>
+<div class="messages warning">
+ <p>{% trans "Download required for " %} {{ import.recordsDownloadRequired }} {% trans "records" %}.</p>
+ <p>{% trans "Downloading next " %} {{ import.recordsUnderDownload }} {% trans "articles, please wait" %}...</p>
+</div>
{% endif %}
<h2>{% trans "Import" %}</h2>
- <p>{% trans "Importing from other services can be quite long, and webservers default configuration often prevents long scripts execution time, so it must be done in multiple parts." %}</p>
- <p>1. {% trans "First, select the export file on your computer and upload it." %}</p>
- <form method="post" action="?uploadfile" name="uploadfile" enctype="multipart/form-data">
+ <p>{% trans "You can import your Pocket, Readability, Instapaper, Wallabag or any data in appropriate json or html format." %}</p>
+ <p>{% trans "Please select export file on your computer:" %}</p>
+ <form method="post" action="?import" name="uploadfile" enctype="multipart/form-data">
<fieldset class="w500p">
<div class="row">
<label class="col w150p" for="file">{% trans "File:" %}</label>
<input class="col" type="file" id="file" name="file" tabindex="4">
</div>
<div class="row mts txtcenter">
- <button class="bouton" type="submit" tabindex="4">{% trans "Upload" %}</button>
+ <button class="bouton" type="submit" tabindex="4">{% trans "Import" %}</button>
</div>
</fieldset>
- <input type="hidden" name="MAX_FILE_SIZE" value="1048576">
- <input type="hidden" name="returnurl" value="{{ referer }}">
</form>
- <p>2. {% trans "Then, click on the right link below." %}</p>
- <ul>
- <li><a href="./?import&from=pocket">{% trans "Import from Pocket" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('POCKET_FILE')) }}</li>
- <li><a href="./?import&from=readability">{% trans "Import from Readability" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('READABILITY_FILE')) }}</li>
- <li><a href="./?import&from=instapaper">{% trans "Import from Instapaper" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('INSTAPAPER_FILE')) }}</li>
- <li><a href="./?import&from=poche">{% trans "Import from wallabag" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('POCHE_FILE')) }}</li>
- </ul>
-
- {% if token == '' %}
- <p>{% trans "3. Your feed token is currently empty and must first be generated to fetch content. Click <a href='?feed&action=generate'>here to generate it</a>." %}</p>
- {% else %}
- <p>3. {% trans "Finally, you have to fetch content for imported items." %} <a href="cron.php?limit=10&user-id={{ user_id }}&token={{token}}" target="_blank">{% trans "Click here" %}</a> {% trans "to fetch content for 10 articles" %}.</p>
- <p>{% trans "If you have console access to your server, you can also create a cron task:" %}</p>
- <pre><code>0 */4 * * * cd /path/to/wallabag && php cron.php --limit=10 --user-id={{user_id}} --token={{token}} >/dev/null 2>&1</code></pre>
- {% endif %}
<h2>{% trans "Export your wallabag data" %}</h2>
{% if constant('STORAGE') == 'sqlite' %}
{% include '_sorting.twig' %}
{% endblock %}
{% block content %}
+
+ {% if includeImport %}
+ {% include '_import.twig' %}
+ {% endif %}
+
{% if tag %}
<h3>{% trans "Tag" %}: <b>{{ tag.value }}</b></h3>
{% endif %}