X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=index.php;h=96a601dedd99c5a45b858922b470ab5475a20969;hb=ddfc400465d7f3bef8fce83ccca755df58a79ea0;hp=8b5ba334498dc161011f6c9f46f30055e3c194a5;hpb=2f32d0746b55243477837d5713e8d28056bb2f90;p=github%2Fshaarli%2FShaarli.git
diff --git a/index.php b/index.php
index 8b5ba334..96a601de 100644
--- a/index.php
+++ b/index.php
@@ -1,5 +1,5 @@
'); // Suffix to encapsulate data in PHP code.
// http://server.com/x/shaarli --> /shaarli/
@@ -66,6 +68,10 @@ checkphpversion();
error_reporting(E_ALL^E_WARNING); // See all error except warnings.
//error_reporting(-1); // See all errors (for debugging only)
+// Shaarli library
+require_once 'application/LinkDB.php';
+require_once 'application/Utils.php';
+
include "inc/rain.tpl.class.php"; //include Rain TPL
raintpl::$tpl_dir = $GLOBALS['config']['RAINTPL_TPL']; // template directory
raintpl::$cache_dir = $GLOBALS['config']['RAINTPL_TMP']; // cache directory
@@ -92,7 +98,7 @@ header("Pragma: no-cache");
if (!is_writable(realpath(dirname(__FILE__)))) die('
ERROR: Shaarli does not have the right to write in its own directory. ');
// Handling of old config file which do not have the new parameters.
-if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.htmlspecialchars(indexUrl());
+if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.escape(indexUrl());
if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get();
if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']='';
if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false;
@@ -105,6 +111,9 @@ if (empty($GLOBALS['titleLink'])) $GLOBALS['titleLink']='?';
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']) : '';
// a token depending of deployment salt, user password, and the current ip
define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GLOBALS['salt']));
@@ -112,6 +121,53 @@ define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GL
autoLocale(); // Sniff browser language and set date format accordingly.
header('Content-Type: text/html; charset=utf-8'); // We use UTF-8 for proper international characters handling.
+//==================================================================================================
+// Checking session state (i.e. is the user still logged in)
+//==================================================================================================
+
+function setup_login_state() {
+ $userIsLoggedIn = false; // By default, we do not consider the user as logged in;
+ $loginFailure = false; // If set to true, every attempt to authenticate the user will fail. This indicates that an important condition isn't met.
+ if ($GLOBALS['config']['OPEN_SHAARLI']) {
+ $userIsLoggedIn = true;
+ }
+ if (!isset($GLOBALS['login'])) {
+ $userIsLoggedIn = false; // Shaarli is not configured yet.
+ $loginFailure = true;
+ }
+ if (isset($_COOKIE['shaarli_staySignedIn']) &&
+ $_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN &&
+ !$loginFailure)
+ {
+ fillSessionInfo();
+ $userIsLoggedIn = true;
+ }
+ // If session does not exist on server side, or IP address has changed, or session has expired, logout.
+ if (empty($_SESSION['uid']) ||
+ ($GLOBALS['disablesessionprotection']==false && $_SESSION['ip']!=allIPs()) ||
+ time() >= $_SESSION['expires_on'])
+ {
+ logout();
+ $userIsLoggedIn = false;
+ $loginFailure = true;
+ }
+ if (!empty($_SESSION['longlastingsession'])) {
+ $_SESSION['expires_on']=time()+$_SESSION['longlastingsession']; // In case of "Stay signed in" checked.
+ }
+ else {
+ $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Standard session expiration date.
+ }
+ if (!$loginFailure) {
+ $userIsLoggedIn = true;
+ }
+
+ return $userIsLoggedIn;
+}
+//==================================================================================================
+$userIsLoggedIn = setup_login_state();
+//==================================================================================================
+//==================================================================================================
+
// Check PHP version
function checkphpversion()
{
@@ -130,13 +186,14 @@ function checkphpversion()
function checkUpdate()
{
if (!isLoggedIn()) return ''; // Do not check versions for visitors.
+ if (empty($GLOBALS['config']['ENABLE_UPDATECHECK'])) return ''; // Do not check if the user doesn't want to.
// Get latest version number at most once a day.
if (!is_file($GLOBALS['config']['UPDATECHECK_FILENAME']) || (filemtime($GLOBALS['config']['UPDATECHECK_FILENAME'])','',str_replace('
-function nl2br_escaped($html)
-{
- return str_replace('>','>',str_replace('<','<',nl2br($html)));
-}
-
-/* Returns the small hash of a string, using RFC 4648 base64url format
- e.g. smallHash('20111006_131924') --> yZH23w
- Small hashes:
- - are unique (well, as unique as crc32, at last)
- - are always 6 characters long.
- - only use the following characters: a-z A-Z 0-9 - _ @
- - are NOT cryptographically secure (they CAN be forged)
- In Shaarli, they are used as a tinyurl-like link to individual entries.
-*/
-function smallHash($text)
-{
- $t = rtrim(base64_encode(hash('crc32',$text,true)),'=');
- return strtr($t, '+/', '-_');
-}
-
// In a string, converts URLs to clickable links.
// Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722
function text2clickable($url)
@@ -253,12 +289,18 @@ function keepMultipleSpaces($text)
// (Note that is may not work on your server if the corresponding local is not installed.)
function autoLocale()
{
- $loc='en_US'; // Default if browser does not send HTTP_ACCEPT_LANGUAGE
+ $attempts = array('en_US'); // Default if browser does not send HTTP_ACCEPT_LANGUAGE
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) // e.g. "fr,fr-fr;q=0.8,en;q=0.5,en-us;q=0.3"
{ // (It's a bit crude, but it works very well. Preferred language is always presented first.)
- if (preg_match('/([a-z]{2}(-[a-z]{2})?)/i',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches)) $loc=$matches[1];
+ if (preg_match('/([a-z]{2})-?([a-z]{2})?/i',$_SERVER['HTTP_ACCEPT_LANGUAGE'],$matches)) {
+ $loc = $matches[1] . (!empty($matches[2]) ? '_' . strtoupper($matches[2]) : '');
+ $attempts = array($loc.'.UTF-8', $loc, str_replace('_', '-', $loc).'.UTF-8', str_replace('_', '-', $loc),
+ $loc . '_' . strtoupper($loc).'.UTF-8', $loc . '_' . strtoupper($loc),
+ $loc . '_' . $loc.'.UTF-8', $loc . '_' . $loc, $loc . '-' . strtoupper($loc).'.UTF-8',
+ $loc . '-' . strtoupper($loc), $loc . '-' . $loc.'.UTF-8', $loc . '-' . $loc);
+ }
}
- setlocale(LC_TIME,$loc); // LC_TIME = Set local for date/time format only.
+ setlocale(LC_TIME, $attempts); // LC_TIME = Set local for date/time format only.
}
// ------------------------------------------------------------------------------------------
@@ -315,30 +357,19 @@ function check_auth($login,$password)
// Returns true if the user is logged in.
function isLoggedIn()
{
- if ($GLOBALS['config']['OPEN_SHAARLI']) return true;
-
- if (!isset($GLOBALS['login'])) return false; // Shaarli is not configured yet.
-
- if (@$_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN)
- {
- fillSessionInfo();
- return true;
- }
- // If session does not exist on server side, or IP address has changed, or session has expired, logout.
- if (empty($_SESSION['uid']) || ($GLOBALS['disablesessionprotection']==false && $_SESSION['ip']!=allIPs()) || time()>=$_SESSION['expires_on'])
- {
- logout();
- return false;
- }
- if (!empty($_SESSION['longlastingsession'])) $_SESSION['expires_on']=time()+$_SESSION['longlastingsession']; // In case of "Stay signed in" checked.
- else $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Standard session expiration date.
-
- return true;
+ global $userIsLoggedIn;
+ return $userIsLoggedIn;
}
// Force logout.
-function logout() { if (isset($_SESSION)) { unset($_SESSION['uid']); unset($_SESSION['ip']); unset($_SESSION['username']); unset($_SESSION['privateonly']); }
-setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH);
+function logout() {
+ if (isset($_SESSION)) {
+ unset($_SESSION['uid']);
+ unset($_SESSION['ip']);
+ unset($_SESSION['username']);
+ unset($_SESSION['privateonly']);
+ }
+ setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH);
}
@@ -430,7 +461,7 @@ if (isset($_POST['login']))
ban_loginFailed();
$redir = '';
if (isset($_GET['post'])) { $redir = '&post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['description'])?'&description='.urlencode($_GET['description']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):''); }
- echo ''; // Redirect to login screen.
+ echo ''; // Redirect to login screen.
exit;
}
}
@@ -491,28 +522,17 @@ function getMaxFileSize()
return $maxsize;
}
-// Tells if a string start with a substring or not.
-function startsWith($haystack,$needle,$case=true)
-{
- if($case){return (strcmp(substr($haystack, 0, strlen($needle)),$needle)===0);}
- return (strcasecmp(substr($haystack, 0, strlen($needle)),$needle)===0);
-}
-
-// Tells if a string ends with a substring or not.
-function endsWith($haystack,$needle,$case=true)
-{
- if($case){return (strcmp(substr($haystack, strlen($haystack) - strlen($needle)),$needle)===0);}
- return (strcasecmp(substr($haystack, strlen($haystack) - strlen($needle)),$needle)===0);
-}
-
/* Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a timestamp (Unix epoch)
(used to build the ADD_DATE attribute in Netscape-bookmarks file)
PS: I could have used strptime(), but it does not exist on Windows. I'm too kind. */
function linkdate2timestamp($linkdate)
{
- $Y=$M=$D=$h=$m=$s=0;
- $r = sscanf($linkdate,'%4d%2d%2d_%2d%2d%2d',$Y,$M,$D,$h,$m,$s);
- return mktime($h,$m,$s,$M,$D,$Y);
+ if(strcmp($linkdate, '_000000') !== 0 || !$linkdate){
+ $Y=$M=$D=$h=$m=$s=0;
+ $r = sscanf($linkdate,'%4d%2d%2d_%2d%2d%2d',$Y,$M,$D,$h,$m,$s);
+ return mktime($h,$m,$s,$M,$D,$Y);
+ }
+ return time();
}
/* Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a RFC822 date.
@@ -529,16 +549,6 @@ function linkdate2iso8601($linkdate)
return date('c',linkdate2timestamp($linkdate)); // 'c' is for ISO 8601 date format.
}
-/* Converts a linkdate time (YYYYMMDD_HHMMSS) of an article to a localized date format.
- (used to display link date on screen)
- The date format is automatically chosen according to locale/languages sniffed from browser headers (see autoLocale()). */
-function linkdate2locale($linkdate)
-{
- return utf8_encode(strftime('%c',linkdate2timestamp($linkdate))); // %c is for automatic date format according to locale.
- // Note that if you use a locale which is not installed on your webserver,
- // the date will not be displayed in the chosen locale, but probably in US notation.
-}
-
// Parse HTTP response headers and return an associative array.
function http_parse_headers_shaarli( $headers )
{
@@ -638,8 +648,8 @@ class pageBuilder
private function initialize()
{
$this->tpl = new RainTPL;
- $this->tpl->assign('newversion',checkUpdate());
- $this->tpl->assign('feedurl',htmlspecialchars(indexUrl()));
+ $this->tpl->assign('newversion',escape(checkUpdate()));
+ $this->tpl->assign('feedurl',escape(indexUrl()));
$searchcrits=''; // Search criteria
if (!empty($_GET['searchtags'])) $searchcrits.='&searchtags='.urlencode($_GET['searchtags']);
elseif (!empty($_GET['searchterm'])) $searchcrits.='&searchterm='.urlencode($_GET['searchterm']);
@@ -672,220 +682,6 @@ class pageBuilder
}
}
-// ------------------------------------------------------------------------------------------
-/* Data storage for links.
- This object behaves like an associative array.
- Example:
- $mylinks = new linkdb();
- echo $mylinks['20110826_161819']['title'];
- foreach($mylinks as $link)
- echo $link['title'].' at url '.$link['url'].' ; description:'.$link['description'];
-
- Available keys:
- title : Title of the link
- url : URL of the link. Can be absolute or relative. Relative URLs are permalinks (e.g.'?m-ukcw')
- description : description of the entry
- private : Is this link private? 0=no, other value=yes
- linkdate : date of the creation of this entry, in the form YYYYMMDD_HHMMSS (e.g.'20110914_192317')
- tags : tags attached to this entry (separated by spaces)
-
- We implement 3 interfaces:
- - ArrayAccess so that this object behaves like an associative array.
- - Iterator so that this object can be used in foreach() loops.
- - Countable interface so that we can do a count() on this object.
-*/
-class linkdb implements Iterator, Countable, ArrayAccess
-{
- private $links; // List of links (associative array. Key=linkdate (e.g. "20110823_124546"), value= associative array (keys:title,description...)
- private $urls; // List of all recorded URLs (key=url, value=linkdate) for fast reserve search (url-->linkdate)
- private $keys; // List of linkdate keys (for the Iterator interface implementation)
- private $position; // Position in the $this->keys array. (for the Iterator interface implementation.)
- private $loggedin; // Is the user logged in? (used to filter private links)
-
- // Constructor:
- function __construct($isLoggedIn)
- // Input : $isLoggedIn : is the user logged in?
- {
- $this->loggedin = $isLoggedIn;
- $this->checkdb(); // Make sure data file exists.
- $this->readdb(); // Then read it.
- }
-
- // ---- Countable interface implementation
- public function count() { return count($this->links); }
-
- // ---- ArrayAccess interface implementation
- public function offsetSet($offset, $value)
- {
- if (!$this->loggedin) die('You are not authorized to add a link.');
- if (empty($value['linkdate']) || empty($value['url'])) die('Internal Error: A link should always have a linkdate and URL.');
- if (empty($offset)) die('You must specify a key.');
- $this->links[$offset] = $value;
- $this->urls[$value['url']]=$offset;
- }
- public function offsetExists($offset) { return array_key_exists($offset,$this->links); }
- public function offsetUnset($offset)
- {
- if (!$this->loggedin) die('You are not authorized to delete a link.');
- $url = $this->links[$offset]['url']; unset($this->urls[$url]);
- unset($this->links[$offset]);
- }
- public function offsetGet($offset) { return isset($this->links[$offset]) ? $this->links[$offset] : null; }
-
- // ---- Iterator interface implementation
- function rewind() { $this->keys=array_keys($this->links); rsort($this->keys); $this->position=0; } // Start over for iteration, ordered by date (latest first).
- function key() { return $this->keys[$this->position]; } // current key
- function current() { return $this->links[$this->keys[$this->position]]; } // current value
- function next() { ++$this->position; } // go to next item
- function valid() { return isset($this->keys[$this->position]); } // Check if current position is valid.
-
- // ---- Misc methods
- private function checkdb() // Check if db directory and file exists.
- {
- if (!file_exists($GLOBALS['config']['DATASTORE'])) // Create a dummy database for example.
- {
- $this->links = array();
- $link = array('title'=>'Shaarli - sebsauvage.net','url'=>'http://sebsauvage.net/wiki/doku.php?id=php:shaarli','description'=>'Welcome to Shaarli ! This is a bookmark. To edit or delete me, you must first login.','private'=>0,'linkdate'=>'20110914_190000','tags'=>'opensource software');
- $this->links[$link['linkdate']] = $link;
- $link = array('title'=>'My secret stuff... - Pastebin.com','url'=>'http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=','description'=>'SShhhh!! I\'m a private link only YOU can see. You can delete me too.','private'=>1,'linkdate'=>'20110914_074522','tags'=>'secretstuff');
- $this->links[$link['linkdate']] = $link;
- file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX); // Write database to disk
- }
- }
-
- // Read database from disk to memory
- private function readdb()
- {
- // Read data
- $this->links=(file_exists($GLOBALS['config']['DATASTORE']) ? unserialize(gzinflate(base64_decode(substr(file_get_contents($GLOBALS['config']['DATASTORE']),strlen(PHPPREFIX),-strlen(PHPSUFFIX))))) : array() );
- // Note that gzinflate is faster than gzuncompress. See: http://www.php.net/manual/en/function.gzdeflate.php#96439
-
- // If user is not logged in, filter private links.
- if (!$this->loggedin)
- {
- $toremove=array();
- foreach($this->links as $link) { if ($link['private']!=0) $toremove[]=$link['linkdate']; }
- foreach($toremove as $linkdate) { unset($this->links[$linkdate]); }
- }
-
- // Keep the list of the mapping URLs-->linkdate up-to-date.
- $this->urls=array();
- foreach($this->links as $link) { $this->urls[$link['url']]=$link['linkdate']; }
- }
-
- // Save database from memory to disk.
- public function savedb()
- {
- if (!$this->loggedin) die('You are not authorized to change the database.');
- file_put_contents($GLOBALS['config']['DATASTORE'], PHPPREFIX.base64_encode(gzdeflate(serialize($this->links))).PHPSUFFIX);
- invalidateCaches();
- }
-
- // Returns the link for a given URL (if it exists). False if it does not exist.
- public function getLinkFromUrl($url)
- {
- if (isset($this->urls[$url])) return $this->links[$this->urls[$url]];
- return false;
- }
-
- // Case insensitive search among links (in the URLs, title and description). Returns filtered list of links.
- // e.g. print_r($mydb->filterFulltext('hollandais'));
- public function filterFulltext($searchterms)
- {
- // FIXME: explode(' ',$searchterms) and perform a AND search.
- // FIXME: accept double-quotes to search for a string "as is"?
- // Using mb_convert_case($val, MB_CASE_LOWER, 'UTF-8') allows us to perform searches on
- // Unicode text. See https://github.com/shaarli/Shaarli/issues/75 for examples.
- $filtered=array();
- $s = mb_convert_case($searchterms, MB_CASE_LOWER, 'UTF-8');
- foreach($this->links as $l)
- {
- $found= (strpos(mb_convert_case($l['title'], MB_CASE_LOWER, 'UTF-8'),$s) !== false)
- || (strpos(mb_convert_case($l['description'], MB_CASE_LOWER, 'UTF-8'),$s) !== false)
- || (strpos(mb_convert_case($l['url'], MB_CASE_LOWER, 'UTF-8'),$s) !== false)
- || (strpos(mb_convert_case($l['tags'], MB_CASE_LOWER, 'UTF-8'),$s) !== false);
- if ($found) $filtered[$l['linkdate']] = $l;
- }
- krsort($filtered);
- return $filtered;
- }
-
- // Filter by tag.
- // You can specify one or more tags (tags can be separated by space or comma).
- // e.g. print_r($mydb->filterTags('linux programming'));
- public function filterTags($tags,$casesensitive=false)
- {
- // Same as above, we use UTF-8 conversion to handle various graphemes (i.e. cyrillic, or greek)
- // TODO: is $casesensitive ever true ?
- $t = str_replace(',',' ',($casesensitive?$tags:mb_convert_case($tags, MB_CASE_LOWER, 'UTF-8')));
- $searchtags=explode(' ',$t);
- $filtered=array();
- foreach($this->links as $l)
- {
- $linktags = explode(' ',($casesensitive?$l['tags']:mb_convert_case($l['tags'], MB_CASE_LOWER, 'UTF-8')));
- if (count(array_intersect($linktags,$searchtags)) == count($searchtags))
- $filtered[$l['linkdate']] = $l;
- }
- krsort($filtered);
- return $filtered;
- }
-
- // Filter by day. Day must be in the form 'YYYYMMDD' (e.g. '20120125')
- // Sort order is: older articles first.
- // e.g. print_r($mydb->filterDay('20120125'));
- public function filterDay($day)
- {
- $filtered=array();
- foreach($this->links as $l)
- {
- if (startsWith($l['linkdate'],$day)) $filtered[$l['linkdate']] = $l;
- }
- ksort($filtered);
- return $filtered;
- }
- // Filter by smallHash.
- // Only 1 article is returned.
- public function filterSmallHash($smallHash)
- {
- $filtered=array();
- foreach($this->links as $l)
- {
- if ($smallHash==smallHash($l['linkdate'])) // Yes, this is ugly and slow
- {
- $filtered[$l['linkdate']] = $l;
- return $filtered;
- }
- }
- return $filtered;
- }
-
- // Returns the list of all tags
- // Output: associative array key=tags, value=0
- public function allTags()
- {
- $tags=array();
- foreach($this->links as $link)
- foreach(explode(' ',$link['tags']) as $tag)
- if (!empty($tag)) $tags[$tag]=(empty($tags[$tag]) ? 1 : $tags[$tag]+1);
- arsort($tags); // Sort tags by usage (most used tag first)
- return $tags;
- }
-
- // Returns the list of days containing articles (oldest first)
- // Output: An array containing days (in format YYYYMMDD).
- public function days()
- {
- $linkdays=array();
- foreach(array_keys($this->links) as $day)
- {
- $linkdays[substr($day,0,8)]=0;
- }
- $linkdays=array_keys($linkdays);
- sort($linkdays);
- return $linkdays;
- }
-}
-
// ------------------------------------------------------------------------------------------
// Output the last N links in RSS 2.0 format.
function showRSS()
@@ -894,7 +690,8 @@ function showRSS()
// $usepermalink : If true, use permalink instead of final link.
// User just has to add 'permalink' in URL parameters. e.g. http://mysite.com/shaarli/?do=rss&permalinks
- $usepermalinks = isset($_GET['permalinks']);
+ // Also enabled through a config option
+ $usepermalinks = isset($_GET['permalinks']) || !$GLOBALS['config']['ENABLE_RSS_PERMALINKS'];
// Cache system
$query = $_SERVER["QUERY_STRING"];
@@ -902,28 +699,33 @@ function showRSS()
$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:
- $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if user it not logged in).
+ $LINKSDB = new LinkDB(
+ isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'],
+ $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+ );
+ // Read links from database (and filter private links if user it not logged in).
// Optionally filter the results:
$linksToDisplay=array();
if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']);
- elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
+ else if (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
else $linksToDisplay = $LINKSDB;
+
$nblinksToDisplay = 50; // Number of links to display.
if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.
{
$nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
}
- $pageaddr=htmlspecialchars(indexUrl());
+ $pageaddr=escape(indexUrl());
echo '';
- echo ''.htmlspecialchars($GLOBALS['title']).' '.$pageaddr.'';
+ echo ''.$GLOBALS['title'].' '.$pageaddr.'';
echo 'Shared links en-en '.$pageaddr.' '."\n\n";
if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
{
echo '';
- echo ' ';
- echo ' ';
+ echo ' ';
+ echo ' ';
echo '';
}
$i=0;
@@ -933,16 +735,16 @@ function showRSS()
$link = $linksToDisplay[$keys[$i]];
$guid = $pageaddr.'?'.smallHash($link['linkdate']);
$rfc822date = linkdate2rfc822($link['linkdate']);
- $absurl = htmlspecialchars($link['url']);
+ $absurl = $link['url'];
if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute
if ($usepermalinks===true)
- echo ''.htmlspecialchars($link['title']).' '.$guid.' '.$guid.'';
+ echo ''.$link['title'].' '.$guid.' '.$guid.'';
else
- echo ''.htmlspecialchars($link['title']).' '.$guid.' '.$absurl.'';
- if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo ''.htmlspecialchars($rfc822date)." \n";
+ echo ''.$link['title'].' '.$guid.' '.$absurl.'';
+ if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo ''.escape($rfc822date)." \n";
if ($link['tags']!='') // Adding tags to each RSS entry (as mentioned in RSS specification)
{
- foreach(explode(' ',$link['tags']) as $tag) { echo ''.htmlspecialchars($tag).' '."\n"; }
+ foreach(explode(' ',$link['tags']) as $tag) { echo ''.$tag.' '."\n"; }
}
// Add permalink in description
@@ -950,10 +752,10 @@ function showRSS()
// If user wants permalinks first, put the final link in description
if ($usepermalinks===true) $descriptionlink = '(Link )';
if (strlen($link['description'])>0) $descriptionlink = ' '.$descriptionlink;
- echo ' '."\n \n";
+ echo ' '."\n \n";
$i++;
}
- echo ' ';
+ echo '';
$cache->cache(ob_get_contents());
ob_end_flush();
@@ -968,7 +770,7 @@ function showATOM()
// $usepermalink : If true, use permalink instead of final link.
// User just has to add 'permalink' in URL parameters. e.g. http://mysite.com/shaarli/?do=atom&permalinks
- $usepermalinks = isset($_GET['permalinks']);
+ $usepermalinks = isset($_GET['permalinks']) || !$GLOBALS['config']['ENABLE_RSS_PERMALINKS'];
// Cache system
$query = $_SERVER["QUERY_STRING"];
@@ -976,21 +778,25 @@ function showATOM()
$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:
- $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in).
-
+// Read links from database (and filter private links if used it not logged in).
+ $LINKSDB = new LinkDB(
+ isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'],
+ $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+ );
// Optionally filter the results:
$linksToDisplay=array();
if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']);
- elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
+ else if (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
else $linksToDisplay = $LINKSDB;
+
$nblinksToDisplay = 50; // Number of links to display.
if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.
{
$nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
}
- $pageaddr=htmlspecialchars(indexUrl());
+ $pageaddr=escape(indexUrl());
$latestDate = '';
$entries='';
$i=0;
@@ -1001,44 +807,44 @@ function showATOM()
$guid = $pageaddr.'?'.smallHash($link['linkdate']);
$iso8601date = linkdate2iso8601($link['linkdate']);
$latestDate = max($latestDate,$iso8601date);
- $absurl = htmlspecialchars($link['url']);
+ $absurl = $link['url'];
if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute
- $entries.=''.htmlspecialchars($link['title']).' ';
+ $entries.=''.$link['title'].' ';
if ($usepermalinks===true)
$entries.=''.$guid.' ';
else
$entries.=''.$guid.' ';
- if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $entries.=''.htmlspecialchars($iso8601date).' ';
+ if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $entries.=''.escape($iso8601date).' ';
// Add permalink in description
- $descriptionlink = htmlspecialchars('(Permalink )');
+ $descriptionlink = '(Permalink )';
// If user wants permalinks first, put the final link in description
- if ($usepermalinks===true) $descriptionlink = htmlspecialchars('(Link )');
- if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink;
+ if ($usepermalinks===true) $descriptionlink = '(Link )';
+ if (strlen($link['description'])>0) $descriptionlink = ' '.$descriptionlink;
- $entries.=''.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))))).$descriptionlink." \n";
+ $entries.=' \n";
if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification)
{
foreach(explode(' ',$link['tags']) as $tag)
- { $entries.=' '."\n"; }
+ { $entries.=' '."\n"; }
}
$entries.=" \n";
$i++;
}
$feed='';
- $feed.=''.htmlspecialchars($GLOBALS['title']).' ';
- if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.=''.htmlspecialchars($latestDate).' ';
- $feed.=' ';
+ $feed.=''.$GLOBALS['title'].' ';
+ if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.=''.escape($latestDate).' ';
+ $feed.=' ';
if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
{
$feed.='';
- $feed.=' ';
+ $feed.=' ';
$feed.='';
}
- $feed.=''.htmlspecialchars($pageaddr).' '.htmlspecialchars($pageaddr).' ';
- $feed.=''.htmlspecialchars($pageaddr).' '."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do.
+ $feed.=''.$pageaddr.' '.$pageaddr.' ';
+ $feed.=''.$pageaddr.' '."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do.
$feed.=$entries;
- $feed.=' ';
+ $feed.='';
echo $feed;
$cache->cache(ob_get_contents());
@@ -1057,7 +863,12 @@ function showDailyRSS()
$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:
- $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in).
+
+// Read links from database (and filter private links if used it not logged in).
+ $LINKSDB = new LinkDB(
+ isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'],
+ $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+ );
/* Some Shaarlies may have very few links, so we need to look
back in time (rsort()) until we have enough days ($nb_of_days).
@@ -1080,18 +891,18 @@ function showDailyRSS()
// Build the RSS feed.
header('Content-Type: application/rss+xml; charset=utf-8');
- $pageaddr=htmlspecialchars(indexUrl());
+ $pageaddr=escape(indexUrl());
echo '';
- echo 'Daily - '.htmlspecialchars($GLOBALS['title']).' '.$pageaddr.'';
+ echo 'Daily - '.$GLOBALS['title'].' '.$pageaddr.'';
echo 'Daily shared links en-en '.$pageaddr.' '."\n";
foreach($days as $day=>$linkdates) // For each day.
{
$daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date
$rfc822date = linkdate2rfc822($day.'_000000');
- $absurl=htmlspecialchars(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page.
- echo ''.htmlspecialchars($GLOBALS['title'].' - '.$daydate).' '.$absurl.' '.$absurl.'';
- echo ''.htmlspecialchars($rfc822date)." ";
+ $absurl=escape(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page.
+ echo ''.$GLOBALS['title'].' - '.$daydate.' '.$absurl.' '.$absurl.'';
+ echo ''.escape($rfc822date)." ";
// Build the HTML body of this RSS entry.
$html='';
@@ -1101,9 +912,9 @@ function showDailyRSS()
foreach($linkdates as $linkdate)
{
$l = $LINKSDB[$linkdate];
- $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($l['description']))));
+ $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable($l['description'])));
$l['thumbnail'] = thumbnail($l['url']);
- $l['localdate']=linkdate2locale($l['linkdate']);
+ $l['timestamp'] = linkdate2timestamp($l['linkdate']);
if (startsWith($l['url'],'?')) $l['url']=indexUrl().$l['url']; // make permalink URL absolute
$links[$linkdate]=$l;
}
@@ -1115,7 +926,7 @@ function showDailyRSS()
echo ' '."\n \n\n";
}
- echo ' ';
+ echo '';
$cache->cache(ob_get_contents());
ob_end_flush();
@@ -1125,8 +936,10 @@ function showDailyRSS()
// "Daily" page.
function showDaily()
{
- $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in).
-
+ $LINKSDB = new LinkDB(
+ isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'],
+ $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+ );
$day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD.
if (isset($_GET['day'])) $day=$_GET['day'];
@@ -1146,11 +959,13 @@ function showDaily()
// We pre-format some fields for proper output.
foreach($linksToDisplay as $key=>$link)
{
+
$taglist = explode(' ',$link['tags']);
uasort($taglist, 'strcasecmp');
$linksToDisplay[$key]['taglist']=$taglist;
- $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))));
+ $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable($link['description'])));
$linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']);
+ $linksToDisplay[$key]['timestamp'] = linkdate2timestamp($link['linkdate']);
}
/* We need to spread the articles on 3 columns.
@@ -1178,7 +993,7 @@ function showDaily()
$PAGE->assign('linksToDisplay',$linksToDisplay);
$PAGE->assign('linkcount',count($LINKSDB));
$PAGE->assign('cols', $columns);
- $PAGE->assign('day',utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))));
+ $PAGE->assign('day',linkdate2timestamp($day.'_000000'));
$PAGE->assign('previousday',$previousday);
$PAGE->assign('nextday',$nextday);
$PAGE->renderPage('daily');
@@ -1190,7 +1005,10 @@ function showDaily()
// Render HTML page (according to URL parameters and user rights)
function renderPage()
{
- $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in).
+ $LINKSDB = new LinkDB(
+ isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'],
+ $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+ );
// -------- Display login form.
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=login'))
@@ -1199,7 +1017,7 @@ function renderPage()
$token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful.
$PAGE = new pageBuilder;
$PAGE->assign('token',$token);
- $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER']:''));
+ $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']):''));
$PAGE->renderPage('loginform');
exit;
}
@@ -1220,21 +1038,22 @@ function renderPage()
if (!empty($_GET['searchterm'])) $links = $LINKSDB->filterFulltext($_GET['searchterm']);
elseif (!empty($_GET['searchtags'])) $links = $LINKSDB->filterTags(trim($_GET['searchtags']));
else $links = $LINKSDB;
+
$body='';
$linksToDisplay=array();
// Get only links which have a thumbnail.
foreach($links as $link)
{
- $permalink='?'.htmlspecialchars(smallhash($link['linkdate']),ENT_QUOTES);
+ $permalink='?'.escape(smallhash($link['linkdate']));
$thumb=lazyThumbnail($link['url'],$permalink);
if ($thumb!='') // Only output links which have a thumbnail.
{
$link['thumbnail']=$thumb; // Thumbnail HTML code.
- $link['permalink']=$permalink;
$linksToDisplay[]=$link; // Add to array.
}
}
+
$PAGE = new pageBuilder;
$PAGE->assign('linkcount',count($LINKSDB));
$PAGE->assign('linksToDisplay',$linksToDisplay);
@@ -1246,6 +1065,7 @@ function renderPage()
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=tagcloud'))
{
$tags= $LINKSDB->allTags();
+
// We sort tags alphabetically, then choose a font size according to count.
// First, find max value.
$maxcount=0; foreach($tags as $key=>$value) $maxcount=max($maxcount,$value);
@@ -1387,12 +1207,12 @@ function renderPage()
// Make sure old password is correct.
$oldhash = sha1($_POST['oldpassword'].$GLOBALS['login'].$GLOBALS['salt']);
- if ($oldhash!=$GLOBALS['hash']) { echo ''; exit; }
+ if ($oldhash!=$GLOBALS['hash']) { echo ''; 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();
- echo '';
+ echo '';
exit;
}
else // show the change password form.
@@ -1422,8 +1242,11 @@ function renderPage()
$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();
- echo '';
+ echo '';
exit;
}
else // Show the configuration form.
@@ -1431,8 +1254,8 @@ function renderPage()
$PAGE = new pageBuilder;
$PAGE->assign('linkcount',count($LINKSDB));
$PAGE->assign('token',getToken());
- $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES));
- $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES));
+ $PAGE->assign('title', empty($GLOBALS['title']) ? '' : $GLOBALS['title'] );
+ $PAGE->assign('redirector', empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] );
list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']);
$PAGE->assign('timezone_form',$timezone_form); // FIXME: Put entire tz form generation in template?
$PAGE->assign('timezone_js',$timezone_js);
@@ -1449,6 +1272,7 @@ function renderPage()
$PAGE = new pageBuilder;
$PAGE->assign('linkcount',count($LINKSDB));
$PAGE->assign('token',getToken());
+ $PAGE->assign('tags', $LINKSDB->allTags());
$PAGE->renderPage('changetag');
exit;
}
@@ -1467,7 +1291,7 @@ function renderPage()
$LINKSDB[$key]=$value;
}
$LINKSDB->savedb(); // Save to disk.
- echo '';
+ echo '';
exit;
}
@@ -1484,7 +1308,7 @@ function renderPage()
$LINKSDB[$key]=$value;
}
$LINKSDB->savedb(); // Save to disk.
- echo '';
+ echo '';
exit;
}
}
@@ -1505,7 +1329,7 @@ function renderPage()
$tags = trim(preg_replace('/\s\s+/',' ', $_POST['lf_tags'])); // Remove multiple spaces.
$linkdate=$_POST['lf_linkdate'];
$url = trim($_POST['lf_url']);
- if (!startsWith($url,'http:') && !startsWith($url,'https:') && !startsWith($url,'ftp:') && !startsWith($url,'magnet:') && !startsWith($url,'?'))
+ if (!startsWith($url,'http:') && !startsWith($url,'https:') && !startsWith($url,'ftp:') && !startsWith($url,'magnet:') && !startsWith($url,'?') && !startsWith($url,'javascript:'))
$url = 'http://'.$url;
$link = array('title'=>trim($_POST['lf_title']),'url'=>$url,'description'=>trim($_POST['lf_description']),'private'=>(isset($_POST['lf_private']) ? 1 : 0),
'linkdate'=>$linkdate,'tags'=>str_replace(',',' ',$tags));
@@ -1515,9 +1339,10 @@ function renderPage()
pubsubhub();
// If we are called from the bookmarklet, we must close the popup:
- if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo ''; exit; }
+ if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo ''; 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.
exit;
}
@@ -1526,7 +1351,7 @@ function renderPage()
if (isset($_POST['cancel_edit']))
{
// If we are called from the bookmarklet, we must close the popup:
- if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo ''; exit; }
+ if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo ''; exit; }
$returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
$returnurl .= '#'.smallHash($_POST['lf_linkdate']); // Scroll to the link which has been edited.
header('Location: '.$returnurl); // After canceling, redirect to the page the user was on.
@@ -1545,8 +1370,38 @@ function renderPage()
$LINKSDB->savedb(); // save to disk
// If we are called from the bookmarklet, we must close the popup:
- if (isset($_GET['source']) && $_GET['source']=='bookmarklet') { echo ''; exit; }
- header('Location: ?'); // After deleting the link, redirect to the home page.
+ if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) { echo ''; exit; }
+ // Pick where we're going to redirect
+ // =============================================================
+ // Basically, we can't redirect to where we were previously if it was a permalink
+ // or an edit_link, because it would 404.
+ // Cases:
+ // - / : nothing in $_GET, redirect to self
+ // - /?page : redirect to self
+ // - /?searchterm : redirect to self (there might be other links)
+ // - /?searchtags : redirect to self
+ // - /permalink : redirect to / (the link does not exist anymore)
+ // - /?edit_link : redirect to / (the link does not exist anymore)
+ // PHP treats the permalink as a $_GET variable, so we need to check if every condition for self
+ // 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 (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'];
+ }
+ }
+
+ header('Location: ' . $location); // After deleting the link, redirect to appropriate location
exit;
}
@@ -1560,7 +1415,8 @@ function renderPage()
$PAGE->assign('link',$link);
$PAGE->assign('link_is_new',false);
$PAGE->assign('token',getToken()); // XSRF protection.
- $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''));
+ $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''));
+ $PAGE->assign('tags', $LINKSDB->allTags());
$PAGE->renderPage('editlink');
exit;
}
@@ -1570,10 +1426,26 @@ function renderPage()
{
$url=$_GET['post'];
- // We remove the annoying parameters added by FeedBurner and GoogleFeedProxy (?utm_source=...)
- $i=strpos($url,'&utm_source='); if ($i!==false) $url=substr($url,0,$i);
- $i=strpos($url,'?utm_source='); if ($i!==false) $url=substr($url,0,$i);
- $i=strpos($url,'#xtor=RSS-'); if ($i!==false) $url=substr($url,0,$i);
+
+ // We remove the annoying parameters added by FeedBurner, GoogleFeedProxy, Facebook...
+ $annoyingpatterns = array('/[\?&]utm_source=[^&]*/',
+ '/[\?&]utm_campaign=[^&]*/',
+ '/[\?&]utm_medium=[^&]*/',
+ '/#xtor=RSS-[^&]*/',
+ '/[\?&]fb_[^&]*/',
+ '/[\?&]__scoop[^&]*/',
+ '/#tk\.rss_all\?/',
+ '/[\?&]action_ref_map=[^&]*/',
+ '/[\?&]action_type_map=[^&]*/',
+ '/[\?&]action_object_map=[^&]*/',
+ '/[\?&]utm_content=[^&]*/',
+ '/[\?&]fb=[^&]*/',
+ '/[\?&]xtor=[^&]*/'
+ );
+ foreach($annoyingpatterns as $pattern)
+ {
+ $url = preg_replace($pattern, "", $url);
+ }
$link_is_new = false;
$link = $LINKSDB->getLinkFromUrl($url); // Check if URL is not already in database (in this case, we will edit the existing link)
@@ -1629,6 +1501,8 @@ function renderPage()
$PAGE->assign('link_is_new',$link_is_new);
$PAGE->assign('token',getToken()); // XSRF protection.
$PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''));
+ $PAGE->assign('source',(isset($_GET['source']) ? $_GET['source'] : ''));
+ $PAGE->assign('tags', $LINKSDB->allTags());
$PAGE->renderPage('editlink');
exit;
}
@@ -1665,10 +1539,10 @@ HTML;
($exportWhat=='private' && $link['private']!=0) ||
($exportWhat=='public' && $link['private']==0))
{
- echo ''.htmlspecialchars($link['title'])." \n";
- if ($link['description']!='') echo ''.htmlspecialchars($link['description'])."\n";
+ echo ' '.$link['title']." \n";
+ if ($link['description']!='') echo ''.$link['description']."\n";
}
}
exit;
@@ -1681,7 +1555,7 @@ HTML;
if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0))
{
$returnurl = ( empty($_SERVER['HTTP_REFERER']) ? '?' : $_SERVER['HTTP_REFERER'] );
- echo '';
+ echo '';
exit;
}
if (!tokenOk($_POST['token'])) die('Wrong token.');
@@ -1702,7 +1576,6 @@ HTML;
// -------- Otherwise, simply display search form and links:
$PAGE = new pageBuilder;
- $PAGE->assign('linkcount',count($LINKSDB));
buildLinkList($PAGE,$LINKSDB); // Compute list of links to display
$PAGE->renderPage('linklist');
exit;
@@ -1713,7 +1586,10 @@ HTML;
function importFile()
{
if (!(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'])) { die('Not allowed.'); }
- $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in).
+ $LINKSDB = new LinkDB(
+ isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'],
+ $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+ );
$filename=$_FILES['filetoupload']['name'];
$filesize=$_FILES['filetoupload']['size'];
$data=file_get_contents($_FILES['filetoupload']['tmp_name']);
@@ -1785,11 +1661,11 @@ function importFile()
}
$LINKSDB->savedb();
- echo '';
+ echo '';
}
else
{
- echo '';
+ echo '';
}
}
@@ -1805,13 +1681,13 @@ function buildLinkList($PAGE,$LINKSDB)
if (isset($_GET['searchterm'])) // Fulltext search
{
$linksToDisplay = $LINKSDB->filterFulltext(trim($_GET['searchterm']));
- $search_crits=htmlspecialchars(trim($_GET['searchterm']));
+ $search_crits=escape(trim($_GET['searchterm']));
$search_type='fulltext';
}
elseif (isset($_GET['searchtags'])) // Search by tag
{
$linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
- $search_crits=explode(' ',trim($_GET['searchtags']));
+ $search_crits=explode(' ',escape(trim($_GET['searchtags'])));
$search_type='tags';
}
elseif (isset($_SERVER['QUERY_STRING']) && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/',$_SERVER['QUERY_STRING'])) // Detect smallHashes in URL
@@ -1829,6 +1705,7 @@ function buildLinkList($PAGE,$LINKSDB)
else
$linksToDisplay = $LINKSDB; // Otherwise, display without filtering.
+
// Option: Show only private links
if (!empty($_SESSION['privateonly']))
{
@@ -1862,14 +1739,20 @@ function buildLinkList($PAGE,$LINKSDB)
while ($i<$end && $iassign('redirector',empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']); // Optional redirector URL.
$PAGE->assign('token',$token);
$PAGE->assign('links',$linkDisp);
+ $PAGE->assign('tags', $LINKSDB->allTags());
return;
}
@@ -2001,7 +1885,7 @@ function computeThumbnail($url,$href=false)
if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL.
}
$sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation)
- return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url),
+ return array('src'=>indexUrl().'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url),
'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail');
}
@@ -2012,7 +1896,7 @@ function computeThumbnail($url,$href=false)
if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif')
{
$sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation)
- return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url),
+ return array('src'=>indexUrl().'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url),
'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail');
}
return array(); // No thumbnail.
@@ -2031,16 +1915,15 @@ function thumbnail($url,$href=false)
$t = computeThumbnail($url,$href);
if (count($t)==0) return ''; // Empty array = no thumbnail for this URL.
- $html=' ';
return $html;
}
-
// Returns the HTML code to display a thumbnail for a link
// for the picture wall (using lazy image loading)
// Understands various services (youtube.com...)
@@ -2052,26 +1935,23 @@ function lazyThumbnail($url,$href=false)
$t = computeThumbnail($url,$href);
if (count($t)==0) return ''; // Empty array = no thumbnail for this URL.
- $html='';
+ $html=' ';
- // Lazy image (only loaded by JavaScript when in the viewport).
- if (!empty($GLOBALS['disablejquery'])) // (except if jQuery is disabled)
- $html.=' ';
// No-JavaScript fallback.
- $html.=' ';
return $html;
@@ -2121,15 +2001,16 @@ function install()
$GLOBALS['login'] = $_POST['setlogin'];
$GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless.
$GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']);
- $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title'] );
+ $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.escape(indexUrl()) : $_POST['title'] );
+ $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']);
writeConfig();
- echo '';
+ echo '';
exit;
}
// Display config form:
list($timezone_form,$timezone_js) = templateTZform();
- $timezone_html=''; if ($timezone_form!='') $timezone_html='Timezone: '.$timezone_form.' ';
+ $timezone_html=''; if ($timezone_form!='') $timezone_html='Timezone: '.$timezone_form.' ';
$PAGE = new pageBuilder;
$PAGE->assign('timezone_html',$timezone_html);
@@ -2177,7 +2058,7 @@ function templateTZform($ptz=false)
$cities_html = $cities[$pcontinent];
$timezone_form = "Continent: ${continents_html} ";
$timezone_form .= " City: ${cities[$pcontinent]} ";
- $timezone_js = "" ;
@@ -2236,45 +2117,6 @@ if (!function_exists('json_encode')) {
}
}
-// Webservices (for use with jQuery/jQueryUI)
-// e.g. index.php?ws=tags&term=minecr
-function processWS()
-{
- if (empty($_GET['ws']) || empty($_GET['term'])) return;
- $term = $_GET['term'];
- $LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in).
- header('Content-Type: application/json; charset=utf-8');
-
- // Search in tags (case insensitive, cumulative search)
- if ($_GET['ws']=='tags')
- {
- $tags=explode(' ',str_replace(',',' ',$term)); $last = array_pop($tags); // Get the last term ("a b c d" ==> "a b c", "d")
- $addtags=''; if ($tags) $addtags=implode(' ',$tags).' '; // We will pre-pend previous tags
- $suggested=array();
- /* To speed up things, we store list of tags in session */
- if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags();
- foreach($_SESSION['tags'] as $key=>$value)
- {
- if (startsWith($key,$last,$case=false) && !in_array($key,$tags)) $suggested[$addtags.$key.' ']=0;
- }
- echo json_encode(array_keys($suggested));
- exit;
- }
-
- // Search a single tag (case sensitive, single tag search)
- if ($_GET['ws']=='singletag')
- {
- /* To speed up things, we store list of tags in session */
- if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags();
- foreach($_SESSION['tags'] as $key=>$value)
- {
- if (startsWith($key,$term,$case=true)) $suggested[$key]=0;
- }
- echo json_encode(array_keys($suggested));
- 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.
@@ -2289,10 +2131,13 @@ function writeConfig()
$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 '';
+ echo '';
exit;
}
}
@@ -2383,7 +2228,7 @@ function genThumbnail()
// This is more complex: we have to perform a HTTP request, then parse the result.
// Maybe we should deport this to JavaScript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098
$vid = substr(parse_url($url,PHP_URL_PATH),1);
- list($httpstatus,$headers,$data) = getHTTP('https://vimeo.com/api/v2/video/'.htmlspecialchars($vid).'.php',5);
+ list($httpstatus,$headers,$data) = getHTTP('https://vimeo.com/api/v2/video/'.escape($vid).'.php',5);
if (strpos($httpstatus,'200 OK')!==false)
{
$t = unserialize($data);
@@ -2529,7 +2374,6 @@ if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=r
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; }
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=dailyrss')) { showDailyRSS(); exit; }
if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=daily')) { showDaily(); exit; }
-if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'ws=')) { processWS(); exit; } // Webservices (for jQuery/jQueryUI)
if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=$GLOBALS['config']['LINKS_PER_PAGE'];
renderPage();
?>