<?php
/**
- * Shaarli v0.8.1 - Shaare your links...
- *
- * The personal, minimalist, super-fast, database free, bookmarking service.
+ * Shaarli - The personal, minimalist, super-fast, database free, bookmarking service.
*
* Friendly fork by the Shaarli community:
* - https://github.com/shaarli/Shaarli
*
* Licence: http://www.opensource.org/licenses/zlib-license.php
*
- * Requires: PHP 5.3.x
+ * Requires: PHP 5.5.x
*/
// Set 'UTC' as the default timezone if it is not defined in php.ini
/*
* PHP configuration
*/
-define('shaarli_version', '0.8.1');
// http://server.com/x/shaarli --> /shaarli/
define('WEB_PATH', substr($_SERVER['REQUEST_URI'], 0, 1+strrpos($_SERVER['REQUEST_URI'], '/', 0)));
require_once 'application/ApplicationUtils.php';
require_once 'application/Cache.php';
require_once 'application/CachedPage.php';
-require_once 'application/config/ConfigManager.php';
require_once 'application/config/ConfigPlugin.php';
require_once 'application/FeedBuilder.php';
require_once 'application/FileUtils.php';
+require_once 'application/History.php';
require_once 'application/HttpUtils.php';
require_once 'application/Languages.php';
require_once 'application/LinkDB.php';
require_once 'application/PluginManager.php';
require_once 'application/Router.php';
require_once 'application/Updater.php';
+use \Shaarli\ThemeUtils;
+use \Shaarli\Config\ConfigManager;
// Ensure the PHP version is supported
try {
- ApplicationUtils::checkPHPVersion('5.3', PHP_VERSION);
+ ApplicationUtils::checkPHPVersion('5.5', PHP_VERSION);
} catch(Exception $exc) {
header('Content-Type: text/plain; charset=utf-8');
echo $exc->getMessage();
exit;
}
+define('shaarli_version', ApplicationUtils::getVersion(__DIR__ .'/'. ApplicationUtils::$VERSION_FILE));
+
// Force cookie path (but do not change lifetime)
$cookie = session_get_cookie_params();
$cookiedir = '';
$conf = new ConfigManager();
$conf->setEmpty('general.timezone', date_default_timezone_get());
$conf->setEmpty('general.title', 'Shared links on '. escape(index_url($_SERVER)));
-RainTPL::$tpl_dir = $conf->get('resource.raintpl_tpl'); // template directory
+RainTPL::$tpl_dir = $conf->get('resource.raintpl_tpl').'/'.$conf->get('resource.theme').'/'; // template directory
RainTPL::$cache_dir = $conf->get('resource.raintpl_tmp'); // cache directory
$pluginManager = new PluginManager($conf);
}
// If session does not exist on server side, or IP address has changed, or session has expired, logout.
if (empty($_SESSION['uid'])
- || ($conf->get('security.session_protection_disabled') == false && $_SESSION['ip'] != allIPs())
+ || ($conf->get('security.session_protection_disabled') === false && $_SESSION['ip'] != allIPs())
|| time() >= $_SESSION['expires_on'])
{
logout();
}
$userIsLoggedIn = setup_login_state($conf);
-/**
- * PubSubHubbub protocol support (if enabled) [UNTESTED]
- * (Source: http://aldarone.fr/les-flux-rss-shaarli-et-pubsubhubbub/ )
- *
- * @param ConfigManager $conf Configuration Manager instance.
- */
-function pubsubhub($conf)
-{
- $pshUrl = $conf->get('config.PUBSUBHUB_URL');
- if (!empty($pshUrl))
- {
- include_once './publisher.php';
- $p = new Publisher($pshUrl);
- $topic_url = array (
- index_url($_SERVER).'?do=atom',
- index_url($_SERVER).'?do=rss'
- );
- $p->publish_update($topic_url);
- }
-}
-
// ------------------------------------------------------------------------------------------
// Session management
// Optional redirect after login:
if (isset($_GET['post'])) {
$uri = '?post='. urlencode($_GET['post']);
- foreach (array('description', 'source', 'title') as $param) {
+ foreach (array('description', 'source', 'title', 'tags') as $param) {
if (!empty($_GET[$param])) {
$uri .= '&'.$param.'='.urlencode($_GET[$param]);
}
$redir = '&username='. $_POST['login'];
if (isset($_GET['post'])) {
$redir .= '&post=' . urlencode($_GET['post']);
- foreach (array('description', 'source', 'title') as $param) {
+ foreach (array('description', 'source', 'title', 'tags') as $param) {
if (!empty($_GET[$param])) {
$redir .= '&' . $param . '=' . urlencode($_GET[$param]);
}
}
}
-// ------------------------------------------------------------------------------------------
-// Misc utility functions:
-
-// Convert post_max_size/upload_max_filesize (e.g. '16M') parameters to bytes.
-function return_bytes($val)
-{
- $val = trim($val); $last=strtolower($val[strlen($val)-1]);
- switch($last)
- {
- case 'g': $val *= 1024;
- case 'm': $val *= 1024;
- case 'k': $val *= 1024;
- }
- return $val;
-}
-
-// Try to determine max file size for uploads (POST).
-// Returns an integer (in bytes)
-function getMaxFileSize()
-{
- $size1 = return_bytes(ini_get('post_max_size'));
- $size2 = return_bytes(ini_get('upload_max_filesize'));
- // Return the smaller of two:
- $maxsize = min($size1,$size2);
- // FIXME: Then convert back to readable notations ? (e.g. 2M instead of 2000000)
- return $maxsize;
-}
-
// ------------------------------------------------------------------------------------------
// Token management for XSRF protection
// Token should be used in any form which acts on data (create,update,delete,import...).
$tpl->assign('links', $links);
$tpl->assign('rssdate', escape($dayDate->format(DateTime::RSS)));
$tpl->assign('hide_timestamps', $conf->get('privacy.hide_timestamps', false));
- $html = $tpl->draw('dailyrss', $return_string=true);
+ $html = $tpl->draw('dailyrss', true);
echo $html . PHP_EOL;
}
$dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000');
$data = array(
+ 'pagetitle' => $conf->get('general.title') .' - '. format_date($dayDate, false),
'linksToDisplay' => $linksToDisplay,
'cols' => $columns,
'day' => $dayDate->getTimestamp(),
+ 'dayDate' => $dayDate,
'previousday' => $previousday,
'nextday' => $nextday,
);
* @param PluginManager $pluginManager Plugin Manager instance,
* @param LinkDB $LINKSDB
*/
-function renderPage($conf, $pluginManager, $LINKSDB)
+function renderPage($conf, $pluginManager, $LINKSDB, $history)
{
$updater = new Updater(
read_updates_file($conf->get('resource.updates')),
die($e->getMessage());
}
- $PAGE = new PageBuilder($conf);
+ $PAGE = new PageBuilder($conf, $LINKSDB);
$PAGE->assign('linkcount', count($LINKSDB));
$PAGE->assign('privateLinkcount', count_private($LINKSDB));
$PAGE->assign('plugin_errors', $pluginManager->getErrors());
// -------- Tag cloud
if ($targetPage == Router::$PAGE_TAGCLOUD)
{
- $tags= $LINKSDB->allTags();
+ $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all';
+ $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : [];
+ $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility);
// We sort tags alphabetically, then choose a font size according to count.
// First, find max value.
$maxcount = max($maxcount, $value);
}
- // Sort tags alphabetically: case insensitive, support locale if available.
- uksort($tags, function($a, $b) {
- // Collator is part of PHP intl.
- if (class_exists('Collator')) {
- $c = new Collator(setlocale(LC_COLLATE, 0));
- if (!intl_is_failure(intl_get_error_code())) {
- return $c->compare($a, $b);
- }
- }
- return strcasecmp($a, $b);
- });
+ alphabetical_sort($tags, true, true);
$tagList = array();
foreach($tags as $key => $value) {
}
$data = array(
+ 'search_tags' => implode(' ', $filteringTags),
'tags' => $tagList,
);
$pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => isLoggedIn()));
$PAGE->assign($key, $value);
}
- $PAGE->renderPage('tagcloud');
+ $PAGE->renderPage('tag.cloud');
+ exit;
+ }
+
+ // -------- Tag cloud
+ if ($targetPage == Router::$PAGE_TAGLIST)
+ {
+ $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all';
+ $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : [];
+ $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility);
+
+ if (! empty($_GET['sort']) && $_GET['sort'] === 'alpha') {
+ alphabetical_sort($tags, false, true);
+ }
+
+ $data = [
+ 'search_tags' => implode(' ', $filteringTags),
+ 'tags' => $tags,
+ ];
+ $pluginManager->executeHooks('render_taglist', $data, ['loggedin' => isLoggedIn()]);
+
+ foreach ($data as $key => $value) {
+ $PAGE->assign($key, $value);
+ }
+
+ $PAGE->renderPage('tag.list');
exit;
}
$_SESSION['LINKS_PER_PAGE']=abs(intval($_GET['linksperpage']));
}
- header('Location: '. generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('linksperpage')));
+ if (! empty($_SERVER['HTTP_REFERER'])) {
+ $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('linksperpage'));
+ } else {
+ $location = '?';
+ }
+ header('Location: '. $location);
exit;
}
unset($_SESSION['privateonly']); // See all links
}
- header('Location: '. generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('privateonly')));
+ if (! empty($_SERVER['HTTP_REFERER'])) {
+ $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('privateonly'));
+ } else {
+ $location = '?';
+ }
+ header('Location: '. $location);
exit;
}
// Show login screen, then redirect to ?post=...
if (isset($_GET['post']))
{
- header('Location: ?do=login&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']):'')); // Redirect to login page, then back to post link.
+ header( // Redirect to login page, then back to post link.
+ 'Location: ?do=login&post='.urlencode($_GET['post']).
+ (!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').
+ (!empty($_GET['description'])?'&description='.urlencode($_GET['description']):'').
+ (!empty($_GET['tags'])?'&tags='.urlencode($_GET['tags']):'').
+ (!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'')
+ );
exit;
}
$conf->set('general.timezone', $tz);
$conf->set('general.title', escape($_POST['title']));
$conf->set('general.header_link', escape($_POST['titleLink']));
+ $conf->set('resource.theme', escape($_POST['theme']));
$conf->set('redirector.url', escape($_POST['redirector']));
$conf->set('security.session_protection_disabled', !empty($_POST['disablesessionprotection']));
$conf->set('privacy.default_private_links', !empty($_POST['privateLinkByDefault']));
$conf->set('feed.rss_permalinks', !empty($_POST['enableRssPermalinks']));
$conf->set('updates.check_updates', !empty($_POST['updateCheck']));
$conf->set('privacy.hide_public_links', !empty($_POST['hidePublicLinks']));
- $conf->set('api.enabled', !empty($_POST['apiEnabled']));
+ $conf->set('api.enabled', !empty($_POST['enableApi']));
$conf->set('api.secret', escape($_POST['apiSecret']));
try {
$conf->write(isLoggedIn());
+ $history->updateSettings();
+ invalidateCaches($conf->get('resource.page_cache'));
}
catch(Exception $e) {
error_log(
else // Show the configuration form.
{
$PAGE->assign('title', $conf->get('general.title'));
+ $PAGE->assign('theme', $conf->get('resource.theme'));
+ $PAGE->assign('theme_available', ThemeUtils::getThemes($conf->get('resource.raintpl_tpl')));
$PAGE->assign('redirector', $conf->get('redirector.url'));
- list($timezone_form, $timezone_js) = generateTimeZoneForm($conf->get('general.timezone'));
- $PAGE->assign('timezone_form', $timezone_form);
- $PAGE->assign('timezone_js',$timezone_js);
+ list($continents, $cities) = generateTimeZoneData(
+ timezone_identifiers_list(),
+ $conf->get('general.timezone')
+ );
+ $PAGE->assign('continents', $continents);
+ $PAGE->assign('cities', $cities);
$PAGE->assign('private_links_default', $conf->get('privacy.default_private_links', false));
$PAGE->assign('session_protection_disabled', $conf->get('security.session_protection_disabled', false));
$PAGE->assign('enable_rss_permalinks', $conf->get('feed.rss_permalinks', false));
if ($targetPage == Router::$PAGE_CHANGETAG)
{
if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) {
- $PAGE->assign('tags', $LINKSDB->allTags());
+ $PAGE->assign('fromtag', ! empty($_GET['fromtag']) ? escape($_GET['fromtag']) : '');
$PAGE->renderPage('changetag');
exit;
}
unset($tags[array_search($needle,$tags)]); // Remove tag.
$value['tags']=trim(implode(' ',$tags));
$LINKSDB[$key]=$value;
+ $history->updateLink($LINKSDB[$key]);
}
$LINKSDB->save($conf->get('resource.page_cache'));
- echo '<script>alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?\';</script>';
+ echo '<script>alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?do=changetag\';</script>';
exit;
}
$needle = trim($_POST['fromtag']);
// True for case-sensitive tag search.
$linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true);
- foreach($linksToAlter as $key=>$value)
- {
- $tags = explode(' ',trim($value['tags']));
- $tags[array_search($needle,$tags)] = trim($_POST['totag']); // Replace tags value.
- $value['tags']=trim(implode(' ',$tags));
- $LINKSDB[$key]=$value;
+ foreach($linksToAlter as $key=>$value) {
+ $tags = preg_split('/\s+/', trim($value['tags']));
+ // Replace tags value.
+ $tags[array_search($needle, $tags)] = trim($_POST['totag']);
+ $value['tags'] = implode(' ', array_unique($tags));
+ $LINKSDB[$key] = $value;
+ $history->updateLink($LINKSDB[$key]);
}
$LINKSDB->save($conf->get('resource.page_cache')); // Save to disk.
- echo '<script>alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode($_POST['totag']).'\';</script>';
+ echo '<script>alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode(escape($_POST['totag'])).'\';</script>';
exit;
}
}
}
// lf_id should only be present if the link exists.
- $id = !empty($_POST['lf_id']) ? intval(escape($_POST['lf_id'])) : $LINKSDB->getNextId();
+ $id = isset($_POST['lf_id']) ? intval(escape($_POST['lf_id'])) : $LINKSDB->getNextId();
// Linkdate is kept here to:
// - use the same permalink for notes as they're displayed when creating them
// - let users hack creation date of their posts
$created = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $linkdate);
$updated = new DateTime();
$shortUrl = $LINKSDB[$id]['shorturl'];
+ $new = false;
} else {
// New link
$created = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $linkdate);
$updated = null;
$shortUrl = link_small_hash($created, $id);
+ $new = true;
}
// Remove multiple spaces.
$LINKSDB[$id] = $link;
$LINKSDB->save($conf->get('resource.page_cache'));
+ if ($new) {
+ $history->addLink($link);
+ } else {
+ $history->updateLink($link);
+ }
// If we are called from the bookmarklet, we must close the popup:
if (isset($_GET['source']) && ($_GET['source']=='bookmarklet' || $_GET['source']=='firefoxsocialapi')) {
// -------- User clicked the "Cancel" button when editing a link.
if (isset($_POST['cancel_edit']))
{
+ $id = isset($_POST['lf_id']) ? (int) escape($_POST['lf_id']) : false;
+ if (! isset($LINKSDB[$id])) {
+ header('Location: ?');
+ }
// 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; }
- $link = $LINKSDB[(int) escape($_POST['lf_id'])];
+ $link = $LINKSDB[$id];
$returnurl = ( isset($_POST['returnurl']) ? $_POST['returnurl'] : '?' );
// Scroll to the link which has been edited.
$returnurl .= '#'. $link['shorturl'];
}
// -------- User clicked the "Delete" button when editing a link: Delete link from database.
- if (isset($_POST['delete_link']))
+ if ($targetPage == Router::$PAGE_DELETELINK)
{
- if (!tokenOk($_POST['token'])) die('Wrong token.');
-
- // We do not need to ask for confirmation:
- // - confirmation is handled by JavaScript
- // - we are protected from XSRF by the token.
-
- // FIXME! We keep `lf_linkdate` for consistency before a proper API. To be removed.
- $id = isset($_POST['lf_id']) ? intval(escape($_POST['lf_id'])) : intval(escape($_POST['lf_linkdate']));
-
- $pluginManager->executeHooks('delete_link', $LINKSDB[$id]);
+ if (! tokenOk($_GET['token'])) {
+ die('Wrong token.');
+ }
- unset($LINKSDB[$id]);
- $LINKSDB->save('resource.page_cache'); // save to disk
+ if (strpos($_GET['lf_linkdate'], ' ') !== false) {
+ $ids = array_values(array_filter(preg_split('/\s+/', escape($_GET['lf_linkdate']))));
+ } else {
+ $ids = [$_GET['lf_linkdate']];
+ }
+ foreach ($ids as $id) {
+ $id = (int) escape($id);
+ $link = $LINKSDB[$id];
+ $pluginManager->executeHooks('delete_link', $link);
+ unset($LINKSDB[$id]);
+ }
+ $LINKSDB->save($conf->get('resource.page_cache')); // save to disk
+ $history->deleteLink($link);
// 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; }
- // 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
- } else {
- $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('delete_link'));
- }
+
+ $location = '?';
+ if (isset($_SERVER['HTTP_REFERER'])) {
+ // Don't redirect to where we were previously if it was a permalink or an edit_link, because it would 404.
+ $location = generateLocation(
+ $_SERVER['HTTP_REFERER'],
+ $_SERVER['HTTP_HOST'],
+ ['delete_link', 'edit_link', $link['shorturl']]
+ );
}
header('Location: ' . $location); // After deleting the link, redirect to appropriate location
'link' => $link,
'link_is_new' => false,
'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''),
- 'tags' => $LINKSDB->allTags(),
+ 'tags' => $LINKSDB->linksCountPerTag(),
);
$pluginManager->executeHooks('render_editlink', $data);
'link_is_new' => $link_is_new,
'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''),
'source' => (isset($_GET['source']) ? $_GET['source'] : ''),
- 'tags' => $LINKSDB->allTags(),
+ 'tags' => $LINKSDB->linksCountPerTag(),
'default_private_links' => $conf->get('privacy.default_private_links', false),
);
$pluginManager->executeHooks('render_editlink', $data);
if (! isset($_POST['token']) || ! isset($_FILES['filetoupload'])) {
// Show import dialog
- $PAGE->assign('maxfilesize', getMaxFileSize());
+ $PAGE->assign(
+ 'maxfilesize',
+ get_max_upload_size(
+ ini_get('post_max_size'),
+ ini_get('upload_max_filesize'),
+ false
+ )
+ );
+ $PAGE->assign(
+ 'maxfilesizeHuman',
+ get_max_upload_size(
+ ini_get('post_max_size'),
+ ini_get('upload_max_filesize'),
+ true
+ )
+ );
$PAGE->renderPage('import');
exit;
}
// The file is too big or some form field may be missing.
echo '<script>alert("The file you are trying to upload is probably'
.' bigger than what this webserver can accept ('
- .getMaxFileSize().' bytes).'
+ .get_max_upload_size(ini_get('post_max_size'), ini_get('upload_max_filesize')).').'
.' Please upload in smaller chunks.");document.location=\'?do='
.Router::$PAGE_IMPORT .'\';</script>';
exit;
$_POST,
$_FILES,
$LINKSDB,
- $conf->get('resource.page_cache')
+ $conf,
+ $history
);
echo '<script>alert("'.$status.'");document.location=\'?do='
.Router::$PAGE_IMPORT .'\';</script>';
$conf->set('general.enabled_plugins', save_plugin_config($_POST));
}
$conf->write(isLoggedIn());
+ $history->updateSettings();
}
catch (Exception $e) {
error_log(
exit;
}
+ // Get a fresh token
+ if ($targetPage == Router::$GET_TOKEN) {
+ header('Content-Type:text/plain');
+ echo getToken($conf);
+ exit;
+ }
+
// -------- Otherwise, simply display search form and links:
showLinkList($PAGE, $LINKSDB, $conf, $pluginManager);
exit;
function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
{
// Used in templates
- $searchtags = !empty($_GET['searchtags']) ? escape(normalize_spaces($_GET['searchtags'])) : '';
+ if (isset($_GET['searchtags'])) {
+ if (! empty($_GET['searchtags'])) {
+ $searchtags = escape(normalize_spaces($_GET['searchtags']));
+ } else {
+ $searchtags = false;
+ }
+ } else {
+ $searchtags = '';
+ }
$searchterm = !empty($_GET['searchterm']) ? escape(normalize_spaces($_GET['searchterm'])) : '';
// Smallhash filter
}
} else {
// Filter links according search parameters.
- $privateonly = !empty($_SESSION['privateonly']);
- $linksToDisplay = $LINKSDB->filterSearch($_GET, false, $privateonly);
+ $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all';
+ $request = [
+ 'searchtags' => $searchtags,
+ 'searchterm' => $searchterm,
+ ];
+ $linksToDisplay = $LINKSDB->filterSearch($request, false, $visibility);
}
// ---- Handle paging.
}
// Compute paging navigation
- $searchtagsUrl = empty($searchtags) ? '' : '&searchtags=' . urlencode($searchtags);
+ $searchtagsUrl = $searchtags === '' ? '' : '&searchtags=' . urlencode($searchtags);
$searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm);
$previous_page_url = '';
if ($i != count($keys)) {
'result_count' => count($linksToDisplay),
'search_term' => $searchterm,
'search_tags' => $searchtags,
+ 'visibility' => ! empty($_SESSION['privateonly']) ? 'private' : '',
'redirector' => $conf->get('redirector.url'), // Optional redirector URL.
'links' => $linkDisp,
- 'tags' => $LINKSDB->allTags(),
);
// If there is only a single link, we change on-the-fly the title of the page.
exit;
}
- // Display config form:
- list($timezone_form, $timezone_js) = generateTimeZoneForm();
- $timezone_html = '';
- if ($timezone_form != '') {
- $timezone_html = '<tr><td><b>Timezone:</b></td><td>'.$timezone_form.'</td></tr>';
- }
-
$PAGE = new PageBuilder($conf);
- $PAGE->assign('timezone_html',$timezone_html);
- $PAGE->assign('timezone_js',$timezone_js);
+ list($continents, $cities) = generateTimeZoneData(timezone_identifiers_list(), date_default_timezone_get());
+ $PAGE->assign('continents', $continents);
+ $PAGE->assign('cities', $cities);
$PAGE->renderPage('install');
exit;
}
$conf->get('redirector.encode_url')
);
+try {
+ $history = new History($conf->get('resource.history'));
+} catch(Exception $e) {
+ die($e->getMessage());
+}
+
$container = new \Slim\Container();
$container['conf'] = $conf;
$container['plugins'] = $pluginManager;
+$container['history'] = $history;
$app = new \Slim\App($container);
// REST API routes
$app->group('/api/v1', function() {
- $this->get('/info', '\Shaarli\Api\Controllers\Info:getInfo');
+ $this->get('/info', '\Shaarli\Api\Controllers\Info:getInfo')->setName('getInfo');
+ $this->get('/links', '\Shaarli\Api\Controllers\Links:getLinks')->setName('getLinks');
+ $this->get('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:getLink')->setName('getLink');
+ $this->post('/links', '\Shaarli\Api\Controllers\Links:postLink')->setName('postLink');
+ $this->put('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:putLink')->setName('putLink');
+ $this->delete('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:deleteLink')->setName('deleteLink');
+ $this->get('/history', '\Shaarli\Api\Controllers\History:getHistory')->setName('getHistory');
})->add('\Shaarli\Api\ApiMiddleware');
$response = $app->run(true);
// Hack to make Slim and Shaarli router work together:
-// If a Slim route isn't found, we call renderPage().
-if ($response->getStatusCode() == 404) {
+// If a Slim route isn't found and NOT API call, we call renderPage().
+if ($response->getStatusCode() == 404 && strpos($_SERVER['REQUEST_URI'], '/api/v1') === false) {
// We use UTF-8 for proper international characters handling.
header('Content-Type: text/html; charset=utf-8');
- renderPage($conf, $pluginManager, $linkDb);
+ renderPage($conf, $pluginManager, $linkDb, $history);
} else {
$app->respond($response);
}