date_default_timezone_set('UTC');
// -----------------------------------------------------------------------------------------------
-// Hardcoded parameter (These parameters can be overwritten by creating the file /data/options.php)
+// Hardcoded parameter (These parameters can be overwritten by editing the file /data/config.php)
+// You should not touch any code below (or at your own risks!)
$GLOBALS['config']['DATADIR'] = 'data'; // Data subdirectory
$GLOBALS['config']['CONFIG_FILE'] = $GLOBALS['config']['DATADIR'].'/config.php'; // Configuration file (user login/password)
$GLOBALS['config']['DATASTORE'] = $GLOBALS['config']['DATADIR'].'/datastore.php'; // Data storage file.
$GLOBALS['config']['ENABLE_RSS_PERMALINKS'] = true; // Enable RSS permalinks by default. This corresponds to the default behavior of shaarli before this was added as an option.
$GLOBALS['config']['HIDE_PUBLIC_LINKS'] = false;
// -----------------------------------------------------------------------------------------------
-// You should not touch below (or at your own risks!)
-// Optional config file.
-if (is_file($GLOBALS['config']['DATADIR'].'/options.php')) require($GLOBALS['config']['DATADIR'].'/options.php');
-
define('shaarli_version','0.0.45beta');
// http://server.com/x/shaarli --> /shaarli/
define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0)));
error_reporting(E_ALL^E_WARNING); // See all error except warnings.
//error_reporting(-1); // See all errors (for debugging only)
+// User configuration
+if (is_file($GLOBALS['config']['CONFIG_FILE'])) {
+ require_once $GLOBALS['config']['CONFIG_FILE'];
+}
+
// Shaarli library
require_once 'application/LinkDB.php';
require_once 'application/Utils.php';
+require_once 'application/Config.php';
include "inc/rain.tpl.class.php"; //include Rain TPL
raintpl::$tpl_dir = $GLOBALS['config']['RAINTPL_TPL']; // template directory
if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get();
if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']='';
if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false;
-if (empty($GLOBALS['disablejquery'])) $GLOBALS['disablejquery']=false;
if (empty($GLOBALS['privateLinkByDefault'])) $GLOBALS['privateLinkByDefault']=false;
if (empty($GLOBALS['titleLink'])) $GLOBALS['titleLink']='?';
// I really need to rewrite Shaarli with a proper configuation manager.
// Run config screen if first run:
-if (!is_file($GLOBALS['config']['CONFIG_FILE'])) install();
+if (! is_file($GLOBALS['config']['CONFIG_FILE'])) {
+ install();
+}
-require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS.
$GLOBALS['title'] = !empty($GLOBALS['title']) ? escape($GLOBALS['title']) : '';
$GLOBALS['titleLink'] = !empty($GLOBALS['titleLink']) ? escape($GLOBALS['titleLink']) : '';
$GLOBALS['redirector'] = !empty($GLOBALS['redirector']) ? escape($GLOBALS['redirector']) : '';
// Daily RSS feed: 1 RSS entry per day giving all the links on that day.
// Gives the last 7 days (which have links).
// This RSS feed cannot be filtered.
-function showDailyRSS()
-{
+function showDailyRSS() {
// Cache system
$query = $_SERVER["QUERY_STRING"];
- $cache = new pageCache(pageUrl(),startsWith($query,'do=dailyrss') && !isLoggedIn());
- $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; }
- // If cached was not found (or not usable), then read the database and build the response:
+ $cache = new pageCache(pageUrl(), startsWith($query, 'do=dailyrss') && !isLoggedIn());
+ $cached = $cache->cachedVersion();
+ if (!empty($cached)) {
+ echo $cached;
+ exit;
+ }
-// Read links from database (and filter private links if used it not logged in).
+ // If cached was not found (or not usable), then read the database and build the response:
+ // Read links from database (and filter private links if used it not logged in).
$LINKSDB = new LinkDB(
$GLOBALS['config']['DATASTORE'],
isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'],
/* Some Shaarlies may have very few links, so we need to look
back in time (rsort()) until we have enough days ($nb_of_days).
*/
- $linkdates=array(); foreach($LINKSDB as $linkdate=>$value) { $linkdates[]=$linkdate; }
+ $linkdates = array();
+ foreach ($LINKSDB as $linkdate => $value) {
+ $linkdates[] = $linkdate;
+ }
rsort($linkdates);
- $nb_of_days=7; // We take 7 days.
- $today=Date('Ymd');
- $days=array();
- foreach($linkdates as $linkdate)
- {
- $day=substr($linkdate,0,8); // Extract day (without time)
- if (strcmp($day,$today)<0)
- {
- if (empty($days[$day])) $days[$day]=array();
- $days[$day][]=$linkdate;
+ $nb_of_days = 7; // We take 7 days.
+ $today = Date('Ymd');
+ $days = array();
+
+ foreach ($linkdates as $linkdate) {
+ $day = substr($linkdate, 0, 8); // Extract day (without time)
+ if (strcmp($day,$today) < 0) {
+ if (empty($days[$day])) {
+ $days[$day] = array();
+ }
+ $days[$day][] = $linkdate;
+ }
+
+ if (count($days) > $nb_of_days) {
+ break; // Have we collected enough days?
}
- if (count($days)>$nb_of_days) break; // Have we collected enough days?
}
// Build the RSS feed.
header('Content-Type: application/rss+xml; charset=utf-8');
- $pageaddr=escape(indexUrl());
+ $pageaddr = escape(indexUrl());
echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">';
- echo '<channel><title>Daily - '.$GLOBALS['title'].'</title><link>'.$pageaddr.'</link>';
- echo '<description>Daily shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n";
-
- foreach($days as $day=>$linkdates) // For each day.
- {
- $daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date
+ echo '<channel>';
+ echo '<title>Daily - '. $GLOBALS['title'] . '</title>';
+ echo '<link>'. $pageaddr .'</link>';
+ echo '<description>Daily shared links</description>';
+ echo '<language>en-en</language>';
+ echo '<copyright>'. $pageaddr .'</copyright>'. PHP_EOL;
+
+ // For each day.
+ foreach ($days as $day => $linkdates) {
+ $daydate = linkdate2timestamp($day.'_000000'); // Full text date
$rfc822date = linkdate2rfc822($day.'_000000');
- $absurl=escape(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page.
- echo '<item><title>'.$GLOBALS['title'].' - '.$daydate.'</title><guid>'.$absurl.'</guid><link>'.$absurl.'</link>';
- echo '<pubDate>'.escape($rfc822date)."</pubDate>";
+ $absurl = escape(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page.
// Build the HTML body of this RSS entry.
- $html='';
- $href='';
- $links=array();
+ $html = '';
+ $href = '';
+ $links = array();
+
// We pre-format some fields for proper output.
- foreach($linkdates as $linkdate)
- {
+ foreach ($linkdates as $linkdate) {
$l = $LINKSDB[$linkdate];
- $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable($l['description'])));
+ $l['formatedDescription'] = nl2br(keepMultipleSpaces(text2clickable($l['description'])));
$l['thumbnail'] = thumbnail($l['url']);
$l['timestamp'] = linkdate2timestamp($l['linkdate']);
- if (startsWith($l['url'],'?')) $l['url']=indexUrl().$l['url']; // make permalink URL absolute
- $links[$linkdate]=$l;
+ if (startsWith($l['url'], '?')) {
+ $l['url'] = indexUrl() . $l['url']; // make permalink URL absolute
+ }
+ $links[$linkdate] = $l;
}
+
// Then build the HTML for this day:
$tpl = new RainTPL;
- $tpl->assign('links',$links);
- $html = $tpl->draw('dailyrss',$return_string=true);
- echo "\n";
- echo '<description><![CDATA['.$html.']]></description>'."\n</item>\n\n";
+ $tpl->assign('title', $GLOBALS['title']);
+ $tpl->assign('daydate', $daydate);
+ $tpl->assign('absurl', $absurl);
+ $tpl->assign('links', $links);
+ $tpl->assign('rfc822date', escape($rfc822date));
+ $html = $tpl->draw('dailyrss', $return_string=true);
+ echo $html . PHP_EOL;
}
- echo '</channel></rss><!-- Cached version of '.escape(pageUrl()).' -->';
+ echo '</channel></rss><!-- Cached version of '. escape(pageUrl()) .' -->';
$cache->cache(ob_get_contents());
ob_end_flush();
if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?searchtags='.urlencode($_GET['addtag'])); exit; } // In case browser does not send HTTP_REFERER
parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params);
+ // Prevent redirection loop
+ if (isset($params['addtag'])) {
+ unset($params['addtag']);
+ }
+
// Check if this tag is already in the search query and ignore it if it is.
// Each tag is always separated by a space
- $current_tags = explode(' ', $params['searchtags']);
+ if (isset($params['searchtags'])) {
+ $current_tags = explode(' ', $params['searchtags']);
+ } else {
+ $current_tags = array();
+ }
$addtag = true;
foreach ($current_tags as $value) {
if ($value === $_GET['addtag']) {
}
// -------- User clicks on a tag in result count: Remove the tag from the list of searched tags (searchtags=...)
- if (isset($_GET['removetag']))
- {
+ if (isset($_GET['removetag'])) {
// Get previous URL (http_referer) and remove the tag from the searchtags parameters in query.
- if (empty($_SERVER['HTTP_REFERER'])) { header('Location: ?'); exit; } // In case browser does not send HTTP_REFERER
- parse_str(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_QUERY), $params);
- if (isset($params['searchtags']))
- {
+ if (empty($_SERVER['HTTP_REFERER'])) {
+ header('Location: ?');
+ exit;
+ }
+
+ // In case browser does not send HTTP_REFERER
+ parse_str(parse_url($_SERVER['HTTP_REFERER'], PHP_URL_QUERY), $params);
+
+ // Prevent redirection loop
+ if (isset($params['removetag'])) {
+ unset($params['removetag']);
+ }
+
+ if (isset($params['searchtags'])) {
$tags = explode(' ',$params['searchtags']);
$tags=array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags.
- if (count($tags)==0) unset($params['searchtags']); else $params['searchtags'] = implode(' ',$tags);
+ if (count($tags)==0) {
+ unset($params['searchtags']);
+ } else {
+ $params['searchtags'] = implode(' ',$tags);
+ }
unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different)
}
header('Location: ?'.http_build_query($params));
}
// -------- User wants to change the number of links per page (linksperpage=...)
- if (isset($_GET['linksperpage']))
- {
- if (is_numeric($_GET['linksperpage'])) { $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage'])); }
- // Make sure the referrer is Shaarli itself.
- $referer = '?';
- if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0)
- $referer = $_SERVER['HTTP_REFERER'];
- header('Location: '.$referer);
+ if (isset($_GET['linksperpage'])) {
+ if (is_numeric($_GET['linksperpage'])) {
+ $_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage']));
+ }
+
+ header('Location: '. generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('linksperpage')));
exit;
}
// -------- User wants to see only private links (toggle)
- if (isset($_GET['privateonly']))
- {
- if (empty($_SESSION['privateonly']))
- {
- $_SESSION['privateonly']=1; // See only private links
- }
- else
- {
+ if (isset($_GET['privateonly'])) {
+ if (empty($_SESSION['privateonly'])) {
+ $_SESSION['privateonly'] = 1; // See only private links
+ } else {
unset($_SESSION['privateonly']); // See all links
}
- // Make sure the referrer is Shaarli itself.
- $referer = '?';
- if (!empty($_SERVER['HTTP_REFERER']) && strcmp(parse_url($_SERVER['HTTP_REFERER'],PHP_URL_HOST),$_SERVER['HTTP_HOST'])==0)
- $referer = $_SERVER['HTTP_REFERER'];
- header('Location: '.$referer);
+
+ header('Location: '. generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('privateonly')));
exit;
}
// Save new password
$GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless.
$GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']);
- writeConfig();
+ try {
+ writeConfig($GLOBALS, isLoggedIn());
+ }
+ catch(Exception $e) {
+ error_log(
+ 'ERROR while writing config file after changing password.' . PHP_EOL .
+ $e->getMessage()
+ );
+
+ // TODO: do not handle exceptions/errors in JS.
+ echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=tools\';</script>';
+ exit;
+ }
echo '<script>alert("Your password has been changed.");document.location=\'?do=tools\';</script>';
exit;
}
$GLOBALS['titleLink']=$_POST['titleLink'];
$GLOBALS['redirector']=$_POST['redirector'];
$GLOBALS['disablesessionprotection']=!empty($_POST['disablesessionprotection']);
- $GLOBALS['disablejquery']=!empty($_POST['disablejquery']);
$GLOBALS['privateLinkByDefault']=!empty($_POST['privateLinkByDefault']);
$GLOBALS['config']['ENABLE_RSS_PERMALINKS']= !empty($_POST['enableRssPermalinks']);
$GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']);
$GLOBALS['config']['HIDE_PUBLIC_LINKS'] = !empty($_POST['hidePublicLinks']);
- writeConfig();
+ try {
+ writeConfig($GLOBALS, isLoggedIn());
+ }
+ catch(Exception $e) {
+ error_log(
+ 'ERROR while writing config file after configuration update.' . PHP_EOL .
+ $e->getMessage()
+ );
+
+ // TODO: do not handle exceptions/errors in JS.
+ echo '<script>alert("'. $e->getMessage() .'");document.location=\'?do=tools\';</script>';
+ exit;
+ }
echo '<script>alert("Configuration was saved.");document.location=\'?do=tools\';</script>';
exit;
}
{
if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away!
$tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces.
+ $tags = implode(' ', array_unique(explode(' ', $tags))); // Remove duplicates.
$linkdate=$_POST['lf_linkdate'];
$url = trim($_POST['lf_url']);
if (!startsWith($url,'http:') && !startsWith($url,'https:') && !startsWith($url,'ftp:') && !startsWith($url,'magnet:') && !startsWith($url,'?') && !startsWith($url,'javascript:'))
// If we are called from the bookmarklet, we must close the popup:
if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; }
- $returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
- $returnurl .= '#'.smallHash($linkdate); // Scroll to the link which has been edited.
- if (strstr($returnurl, "do=addlink")) { $returnurl = '?'; } //if we come from ?do=addlink, set returnurl to homepage instead
- header('Location: '.$returnurl); // After saving the link, redirect to the page the user was on.
+ $returnurl = ( !empty($_POST['returnurl']) ? escape($_POST['returnurl']) : '?' );
+ $returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited.
+ $location = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link'));
+ header('Location: '. $location); // After saving the link, redirect to the page the user was on.
exit;
}
if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo '<script>self.close();</script>'; exit; }
$returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
$returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited.
+ $returnurl = generateLocation($returnurl, $_SERVER['HTTP_HOST'], array('addlink', 'post', 'edit_link'));
header('Location: '.$returnurl); // After canceling, redirect to the page the user was on.
exit;
}
// redirect is not satisfied, and only then redirect to /
$location = "?";
// Self redirection
- if (count($_GET) == 0 ||
- isset($_GET['page']) ||
- isset($_GET['searchterm']) ||
- isset($_GET['searchtags'])) {
-
+ if (count($_GET) == 0
+ || isset($_GET['page'])
+ || isset($_GET['searchterm'])
+ || isset($_GET['searchtags'])
+ ) {
if (isset($_POST['returnurl'])) {
$location = $_POST['returnurl']; // Handle redirects given by the form
- }
-
- if ($location === "?" &&
- isset($_SERVER['HTTP_REFERER'])) { // Handle HTTP_REFERER in case we're not coming from the same place.
- $location = $_SERVER['HTTP_REFERER'];
+ } else {
+ $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('delete_link'));
}
}
{
header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
echo '<h1>404 Not found.</h1>Oh crap. The link you are trying to reach does not exist or has been deleted.';
- echo '<br>You would mind <a href="?">clicking here</a>?';
+ echo '<br>Would you mind <a href="?">clicking here</a>?';
exit;
}
$search_type='permalink';
$GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']);
$GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.escape(indexUrl()) : $_POST['title'] );
$GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']);
- writeConfig();
+ try {
+ writeConfig($GLOBALS, isLoggedIn());
+ }
+ catch(Exception $e) {
+ error_log(
+ 'ERROR while writing config file after installation.' . PHP_EOL .
+ $e->getMessage()
+ );
+
+ // TODO: do not handle exceptions/errors in JS.
+ echo '<script>alert("'. $e->getMessage() .'");document.location=\'?\';</script>';
+ exit;
+ }
echo '<script>alert("Shaarli is now configured. Please enter your login/password and start shaaring your links!");document.location=\'?do=login\';</script>';
exit;
}
}
}
-// Re-write configuration file according to globals.
-// Requires some $GLOBALS to be set (login,hash,salt,title).
-// If the config file cannot be saved, an error message is displayed and the user is redirected to "Tools" menu.
-// (otherwise, the function simply returns.)
-function writeConfig()
-{
- if (is_file($GLOBALS['config']['CONFIG_FILE']) && !isLoggedIn()) die('You are not authorized to alter config.'); // Only logged in user can alter config.
- $config='<?php $GLOBALS[\'login\']='.var_export($GLOBALS['login'],true).'; $GLOBALS[\'hash\']='.var_export($GLOBALS['hash'],true).'; $GLOBALS[\'salt\']='.var_export($GLOBALS['salt'],true).'; ';
- $config .='$GLOBALS[\'timezone\']='.var_export($GLOBALS['timezone'],true).'; date_default_timezone_set('.var_export($GLOBALS['timezone'],true).'); $GLOBALS[\'title\']='.var_export($GLOBALS['title'],true).';';
- $config .= '$GLOBALS[\'titleLink\']='.var_export($GLOBALS['titleLink'],true).'; ';
- $config .= '$GLOBALS[\'redirector\']='.var_export($GLOBALS['redirector'],true).'; ';
- $config .= '$GLOBALS[\'disablesessionprotection\']='.var_export($GLOBALS['disablesessionprotection'],true).'; ';
- $config .= '$GLOBALS[\'disablejquery\']='.var_export($GLOBALS['disablejquery'],true).'; ';
- $config .= '$GLOBALS[\'privateLinkByDefault\']='.var_export($GLOBALS['privateLinkByDefault'],true).'; ';
- $config .= '$GLOBALS[\'config\'][\'ENABLE_RSS_PERMALINKS\']='.var_export($GLOBALS['config']['ENABLE_RSS_PERMALINKS'], true).'; ';
- $config .= '$GLOBALS[\'config\'][\'ENABLE_UPDATECHECK\']='.var_export($GLOBALS['config']['ENABLE_UPDATECHECK'], true).'; ';
- $config .= '$GLOBALS[\'config\'][\'HIDE_PUBLIC_LINKS\']='.var_export($GLOBALS['config']['HIDE_PUBLIC_LINKS'], true).'; ';
- $config .= ' ?>';
- if (!file_put_contents($GLOBALS['config']['CONFIG_FILE'],$config) || strcmp(file_get_contents($GLOBALS['config']['CONFIG_FILE']),$config)!=0)
- {
- echo '<script>alert("Shaarli could not create the config file. Please make sure Shaarli has the right to write in the folder is it installed in.");document.location=\'?\';</script>';
- exit;
- }
-}
+
/* Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL,
I have deported the thumbnail URL code generation here, otherwise this would slow down page generation.
pageCache::purgeCache(); // Purge page cache shared by sessions.
}
+try {
+ mergeDeprecatedConfig($GLOBALS, isLoggedIn());
+} catch(Exception $e) {
+ error_log(
+ 'ERROR while merging deprecated options.php file.' . PHP_EOL .
+ $e->getMessage()
+ );
+}
+
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=genthumbnail')) { genThumbnail(); exit; } // Thumbnail generation/cache does not need the link database.
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; }
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; }