-// Returns a token.
-function getToken()
-{
- $rnd = sha1(uniqid('',true).'_'.mt_rand().$GLOBALS['salt']); // We generate a random string.
- $_SESSION['tokens'][$rnd]=1; // Store it on the server side.
- return $rnd;
-}
-
-// Tells if a token is ok. Using this function will destroy the token.
-// true=token is ok.
-function tokenOk($token)
-{
- if (isset($_SESSION['tokens'][$token]))
- {
- unset($_SESSION['tokens'][$token]); // Token is used: destroy it.
- return true; // Token is ok.
- }
- return false; // Wrong token, or already used.
-}
-
-// ------------------------------------------------------------------------------------------
-/* This class is in charge of building the final page.
- (This is basically a wrapper around RainTPL which pre-fills some fields.)
- p = new pageBuilder;
- p.assign('myfield','myvalue');
- p.renderPage('mytemplate');
-
-*/
-class pageBuilder
-{
- private $tpl; // RainTPL template
-
- function __construct()
- {
- $this->tpl=false;
- }
-
- private function initialize()
- {
- $this->tpl = new RainTPL;
- $this->tpl->assign('newversion',checkUpdate());
- $this->tpl->assign('feedurl',htmlspecialchars(indexUrl()));
- $searchcrits=''; // Search criteria
- if (!empty($_GET['searchtags'])) $searchcrits.='&searchtags='.urlencode($_GET['searchtags']);
- elseif (!empty($_GET['searchterm'])) $searchcrits.='&searchterm='.urlencode($_GET['searchterm']);
- $this->tpl->assign('searchcrits',$searchcrits);
- $this->tpl->assign('source',indexUrl());
- $this->tpl->assign('version',shaarli_version);
- $this->tpl->assign('scripturl',indexUrl());
- $this->tpl->assign('pagetitle','Shaarli');
- $this->tpl->assign('privateonly',!empty($_SESSION['privateonly'])); // Show only private links ?
- if (!empty($GLOBALS['title'])) $this->tpl->assign('pagetitle',$GLOBALS['title']);
- if (!empty($GLOBALS['pagetitle'])) $this->tpl->assign('pagetitle',$GLOBALS['pagetitle']);
- $this->tpl->assign('shaarlititle',empty($GLOBALS['title']) ? 'Shaarli': $GLOBALS['title'] );
- return;
- }
-
- // The following assign() method is basically the same as RainTPL (except that it's lazy)
- public function assign($what,$where)
- {
- if ($this->tpl===false) $this->initialize(); // Lazy initialization
- $this->tpl->assign($what,$where);
- }
-
- // Render a specific page (using a template).
- // eg. pb.renderPage('picwall')
- public function renderPage($page)
- {
- if ($this->tpl===false) $this->initialize(); // Lazy initialization
- $this->tpl->draw($page);
- }
-}
-
-// ------------------------------------------------------------------------------------------
-/* 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 (eg.'?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 (eg.'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 (eg. "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 used logged in ? (used to filter private links)
-
- // Constructor:
- function __construct($isLoggedIn)
- // Input : $isLoggedIn : is the used 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 it does not exist.
- public function getLinkFromUrl($url)
- {
- if (isset($this->urls[$url])) return $this->links[$this->urls[$url]];
- return false;
- }
-
- // Case insentitive search among links (in url, title and description). Returns filtered list of links.
- // eg. 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" ?
- $filtered=array();
- $s = strtolower($searchterms);
- foreach($this->links as $l)
- {
- $found= (strpos(strtolower($l['title']),$s)!==false)
- || (strpos(strtolower($l['description']),$s)!==false)
- || (strpos(strtolower($l['url']),$s)!==false)
- || (strpos(strtolower($l['tags']),$s)!==false);
- if ($found) $filtered[$l['linkdate']] = $l;