aboutsummaryrefslogtreecommitdiffhomepage
path: root/index.php
diff options
context:
space:
mode:
Diffstat (limited to 'index.php')
-rw-r--r--index.php204
1 files changed, 109 insertions, 95 deletions
diff --git a/index.php b/index.php
index ab1e30da..b4c4347a 100644
--- a/index.php
+++ b/index.php
@@ -225,27 +225,6 @@ function setup_login_state($conf)
225} 225}
226$userIsLoggedIn = setup_login_state($conf); 226$userIsLoggedIn = setup_login_state($conf);
227 227
228/**
229 * PubSubHubbub protocol support (if enabled) [UNTESTED]
230 * (Source: http://aldarone.fr/les-flux-rss-shaarli-et-pubsubhubbub/ )
231 *
232 * @param ConfigManager $conf Configuration Manager instance.
233 */
234function pubsubhub($conf)
235{
236 $pshUrl = $conf->get('config.PUBSUBHUB_URL');
237 if (!empty($pshUrl))
238 {
239 include_once './publisher.php';
240 $p = new Publisher($pshUrl);
241 $topic_url = array (
242 index_url($_SERVER).'?do=atom',
243 index_url($_SERVER).'?do=rss'
244 );
245 $p->publish_update($topic_url);
246 }
247}
248
249// ------------------------------------------------------------------------------------------ 228// ------------------------------------------------------------------------------------------
250// Session management 229// Session management
251 230
@@ -308,6 +287,7 @@ function logout() {
308 unset($_SESSION['ip']); 287 unset($_SESSION['ip']);
309 unset($_SESSION['username']); 288 unset($_SESSION['username']);
310 unset($_SESSION['privateonly']); 289 unset($_SESSION['privateonly']);
290 unset($_SESSION['untaggedonly']);
311 } 291 }
312 setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH); 292 setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH);
313} 293}
@@ -706,6 +686,7 @@ function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager) {
706 * @param ConfigManager $conf Configuration Manager instance. 686 * @param ConfigManager $conf Configuration Manager instance.
707 * @param PluginManager $pluginManager Plugin Manager instance, 687 * @param PluginManager $pluginManager Plugin Manager instance,
708 * @param LinkDB $LINKSDB 688 * @param LinkDB $LINKSDB
689 * @param History $history instance
709 */ 690 */
710function renderPage($conf, $pluginManager, $LINKSDB, $history) 691function renderPage($conf, $pluginManager, $LINKSDB, $history)
711{ 692{
@@ -811,7 +792,9 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
811 // -------- Tag cloud 792 // -------- Tag cloud
812 if ($targetPage == Router::$PAGE_TAGCLOUD) 793 if ($targetPage == Router::$PAGE_TAGCLOUD)
813 { 794 {
814 $tags= $LINKSDB->allTags(); 795 $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all';
796 $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : [];
797 $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility);
815 798
816 // We sort tags alphabetically, then choose a font size according to count. 799 // We sort tags alphabetically, then choose a font size according to count.
817 // First, find max value. 800 // First, find max value.
@@ -820,20 +803,13 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
820 $maxcount = max($maxcount, $value); 803 $maxcount = max($maxcount, $value);
821 } 804 }
822 805
823 // Sort tags alphabetically: case insensitive, support locale if available. 806 alphabetical_sort($tags, true, true);
824 uksort($tags, function($a, $b) {
825 // Collator is part of PHP intl.
826 if (class_exists('Collator')) {
827 $c = new Collator(setlocale(LC_COLLATE, 0));
828 if (!intl_is_failure(intl_get_error_code())) {
829 return $c->compare($a, $b);
830 }
831 }
832 return strcasecmp($a, $b);
833 });
834 807
835 $tagList = array(); 808 $tagList = array();
836 foreach($tags as $key => $value) { 809 foreach($tags as $key => $value) {
810 if (in_array($key, $filteringTags)) {
811 continue;
812 }
837 // Tag font size scaling: 813 // Tag font size scaling:
838 // default 15 and 30 logarithm bases affect scaling, 814 // default 15 and 30 logarithm bases affect scaling,
839 // 22 and 6 are arbitrary font sizes for max and min sizes. 815 // 22 and 6 are arbitrary font sizes for max and min sizes.
@@ -845,6 +821,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
845 } 821 }
846 822
847 $data = array( 823 $data = array(
824 'search_tags' => implode(' ', $filteringTags),
848 'tags' => $tagList, 825 'tags' => $tagList,
849 ); 826 );
850 $pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => isLoggedIn())); 827 $pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => isLoggedIn()));
@@ -853,7 +830,37 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
853 $PAGE->assign($key, $value); 830 $PAGE->assign($key, $value);
854 } 831 }
855 832
856 $PAGE->renderPage('tagcloud'); 833 $PAGE->renderPage('tag.cloud');
834 exit;
835 }
836
837 // -------- Tag list
838 if ($targetPage == Router::$PAGE_TAGLIST)
839 {
840 $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all';
841 $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : [];
842 $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility);
843 foreach ($filteringTags as $tag) {
844 if (array_key_exists($tag, $tags)) {
845 unset($tags[$tag]);
846 }
847 }
848
849 if (! empty($_GET['sort']) && $_GET['sort'] === 'alpha') {
850 alphabetical_sort($tags, false, true);
851 }
852
853 $data = [
854 'search_tags' => implode(' ', $filteringTags),
855 'tags' => $tags,
856 ];
857 $pluginManager->executeHooks('render_taglist', $data, ['loggedin' => isLoggedIn()]);
858
859 foreach ($data as $key => $value) {
860 $PAGE->assign($key, $value);
861 }
862
863 $PAGE->renderPage('tag.list');
857 exit; 864 exit;
858 } 865 }
859 866
@@ -1012,6 +1019,19 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1012 exit; 1019 exit;
1013 } 1020 }
1014 1021
1022 // -------- User wants to see only untagged links (toggle)
1023 if (isset($_GET['untaggedonly'])) {
1024 $_SESSION['untaggedonly'] = empty($_SESSION['untaggedonly']);
1025
1026 if (! empty($_SERVER['HTTP_REFERER'])) {
1027 $location = generateLocation($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST'], array('untaggedonly'));
1028 } else {
1029 $location = '?';
1030 }
1031 header('Location: '. $location);
1032 exit;
1033 }
1034
1015 // -------- Handle other actions allowed for non-logged in users: 1035 // -------- Handle other actions allowed for non-logged in users:
1016 if (!isLoggedIn()) 1036 if (!isLoggedIn())
1017 { 1037 {
@@ -1170,6 +1190,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1170 if ($targetPage == Router::$PAGE_CHANGETAG) 1190 if ($targetPage == Router::$PAGE_CHANGETAG)
1171 { 1191 {
1172 if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { 1192 if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) {
1193 $PAGE->assign('fromtag', ! empty($_GET['fromtag']) ? escape($_GET['fromtag']) : '');
1173 $PAGE->renderPage('changetag'); 1194 $PAGE->renderPage('changetag');
1174 exit; 1195 exit;
1175 } 1196 }
@@ -1178,41 +1199,18 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1178 die('Wrong token.'); 1199 die('Wrong token.');
1179 } 1200 }
1180 1201
1181 // Delete a tag: 1202 $alteredLinks = $LINKSDB->renameTag(escape($_POST['fromtag']), escape($_POST['totag']));
1182 if (isset($_POST['deletetag']) && !empty($_POST['fromtag'])) { 1203 $LINKSDB->save($conf->get('resource.page_cache'));
1183 $needle = trim($_POST['fromtag']); 1204 foreach ($alteredLinks as $link) {
1184 // True for case-sensitive tag search. 1205 $history->updateLink($link);
1185 $linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true);
1186 foreach($linksToAlter as $key=>$value)
1187 {
1188 $tags = explode(' ',trim($value['tags']));
1189 unset($tags[array_search($needle,$tags)]); // Remove tag.
1190 $value['tags']=trim(implode(' ',$tags));
1191 $LINKSDB[$key]=$value;
1192 $history->updateLink($LINKSDB[$key]);
1193 }
1194 $LINKSDB->save($conf->get('resource.page_cache'));
1195 echo '<script>alert("Tag was removed from '.count($linksToAlter).' links.");document.location=\'?do=changetag\';</script>';
1196 exit;
1197 }
1198
1199 // Rename a tag:
1200 if (isset($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) {
1201 $needle = trim($_POST['fromtag']);
1202 // True for case-sensitive tag search.
1203 $linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true);
1204 foreach($linksToAlter as $key=>$value) {
1205 $tags = preg_split('/\s+/', trim($value['tags']));
1206 // Replace tags value.
1207 $tags[array_search($needle, $tags)] = trim($_POST['totag']);
1208 $value['tags'] = implode(' ', array_unique($tags));
1209 $LINKSDB[$key] = $value;
1210 $history->updateLink($LINKSDB[$key]);
1211 }
1212 $LINKSDB->save($conf->get('resource.page_cache')); // Save to disk.
1213 echo '<script>alert("Tag was renamed in '.count($linksToAlter).' links.");document.location=\'?searchtags='.urlencode(escape($_POST['totag'])).'\';</script>';
1214 exit;
1215 } 1206 }
1207 $delete = empty($_POST['totag']);
1208 $redirect = $delete ? 'do=changetag' : 'searchtags='. urlencode(escape($_POST['totag']));
1209 $alert = $delete
1210 ? sprintf(t('The tag was removed from %d links.'), count($alteredLinks))
1211 : sprintf(t('The tag was renamed in %d links.'), count($alteredLinks));
1212 echo '<script>alert("'. $alert .'");document.location=\'?'. $redirect .'\';</script>';
1213 exit;
1216 } 1214 }
1217 1215
1218 // -------- User wants to add a link without using the bookmarklet: Show form. 1216 // -------- User wants to add a link without using the bookmarklet: Show form.
@@ -1258,13 +1256,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1258 // Remove duplicates. 1256 // Remove duplicates.
1259 $tags = implode(' ', array_unique(explode(' ', $tags))); 1257 $tags = implode(' ', array_unique(explode(' ', $tags)));
1260 1258
1261 $url = trim($_POST['lf_url']); 1259 $url = whitelist_protocols(trim($_POST['lf_url']), $conf->get('security.allowed_protocols'));
1262 if (! startsWith($url, 'http:') && ! startsWith($url, 'https:')
1263 && ! startsWith($url, 'ftp:') && ! startsWith($url, 'magnet:')
1264 && ! startsWith($url, '?') && ! startsWith($url, 'javascript:')
1265 ) {
1266 $url = 'http://' . $url;
1267 }
1268 1260
1269 $link = array( 1261 $link = array(
1270 'id' => $id, 1262 'id' => $id,
@@ -1329,18 +1321,21 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1329 // -------- User clicked the "Delete" button when editing a link: Delete link from database. 1321 // -------- User clicked the "Delete" button when editing a link: Delete link from database.
1330 if ($targetPage == Router::$PAGE_DELETELINK) 1322 if ($targetPage == Router::$PAGE_DELETELINK)
1331 { 1323 {
1332 // We do not need to ask for confirmation:
1333 // - confirmation is handled by JavaScript
1334 // - we are protected from XSRF by the token.
1335
1336 if (! tokenOk($_GET['token'])) { 1324 if (! tokenOk($_GET['token'])) {
1337 die('Wrong token.'); 1325 die('Wrong token.');
1338 } 1326 }
1339 1327
1340 $id = intval(escape($_GET['lf_linkdate'])); 1328 if (strpos($_GET['lf_linkdate'], ' ') !== false) {
1341 $link = $LINKSDB[$id]; 1329 $ids = array_values(array_filter(preg_split('/\s+/', escape($_GET['lf_linkdate']))));
1342 $pluginManager->executeHooks('delete_link', $link); 1330 } else {
1343 unset($LINKSDB[$id]); 1331 $ids = [$_GET['lf_linkdate']];
1332 }
1333 foreach ($ids as $id) {
1334 $id = (int) escape($id);
1335 $link = $LINKSDB[$id];
1336 $pluginManager->executeHooks('delete_link', $link);
1337 unset($LINKSDB[$id]);
1338 }
1344 $LINKSDB->save($conf->get('resource.page_cache')); // save to disk 1339 $LINKSDB->save($conf->get('resource.page_cache')); // save to disk
1345 $history->deleteLink($link); 1340 $history->deleteLink($link);
1346 1341
@@ -1372,7 +1367,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1372 'link' => $link, 1367 'link' => $link,
1373 'link_is_new' => false, 1368 'link_is_new' => false,
1374 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), 1369 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''),
1375 'tags' => $LINKSDB->allTags(), 1370 'tags' => $LINKSDB->linksCountPerTag(),
1376 ); 1371 );
1377 $pluginManager->executeHooks('render_editlink', $data); 1372 $pluginManager->executeHooks('render_editlink', $data);
1378 1373
@@ -1430,7 +1425,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1430 'url' => $url, 1425 'url' => $url,
1431 'description' => $description, 1426 'description' => $description,
1432 'tags' => $tags, 1427 'tags' => $tags,
1433 'private' => $private 1428 'private' => $private,
1434 ); 1429 );
1435 } else { 1430 } else {
1436 $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); 1431 $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT);
@@ -1441,7 +1436,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1441 'link_is_new' => $link_is_new, 1436 'link_is_new' => $link_is_new,
1442 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), 1437 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''),
1443 'source' => (isset($_GET['source']) ? $_GET['source'] : ''), 1438 'source' => (isset($_GET['source']) ? $_GET['source'] : ''),
1444 'tags' => $LINKSDB->allTags(), 1439 'tags' => $LINKSDB->linksCountPerTag(),
1445 'default_private_links' => $conf->get('privacy.default_private_links', false), 1440 'default_private_links' => $conf->get('privacy.default_private_links', false),
1446 ); 1441 );
1447 $pluginManager->executeHooks('render_editlink', $data); 1442 $pluginManager->executeHooks('render_editlink', $data);
@@ -1597,6 +1592,13 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1597 exit; 1592 exit;
1598 } 1593 }
1599 1594
1595 // Get a fresh token
1596 if ($targetPage == Router::$GET_TOKEN) {
1597 header('Content-Type:text/plain');
1598 echo getToken($conf);
1599 exit;
1600 }
1601
1600 // -------- Otherwise, simply display search form and links: 1602 // -------- Otherwise, simply display search form and links:
1601 showLinkList($PAGE, $LINKSDB, $conf, $pluginManager); 1603 showLinkList($PAGE, $LINKSDB, $conf, $pluginManager);
1602 exit; 1604 exit;
@@ -1614,7 +1616,15 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history)
1614function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) 1616function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
1615{ 1617{
1616 // Used in templates 1618 // Used in templates
1617 $searchtags = !empty($_GET['searchtags']) ? escape(normalize_spaces($_GET['searchtags'])) : ''; 1619 if (isset($_GET['searchtags'])) {
1620 if (! empty($_GET['searchtags'])) {
1621 $searchtags = escape(normalize_spaces($_GET['searchtags']));
1622 } else {
1623 $searchtags = false;
1624 }
1625 } else {
1626 $searchtags = '';
1627 }
1618 $searchterm = !empty($_GET['searchterm']) ? escape(normalize_spaces($_GET['searchterm'])) : ''; 1628 $searchterm = !empty($_GET['searchterm']) ? escape(normalize_spaces($_GET['searchterm'])) : '';
1619 1629
1620 // Smallhash filter 1630 // Smallhash filter
@@ -1629,7 +1639,11 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
1629 } else { 1639 } else {
1630 // Filter links according search parameters. 1640 // Filter links according search parameters.
1631 $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all'; 1641 $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all';
1632 $linksToDisplay = $LINKSDB->filterSearch($_GET, false, $visibility); 1642 $request = [
1643 'searchtags' => $searchtags,
1644 'searchterm' => $searchterm,
1645 ];
1646 $linksToDisplay = $LINKSDB->filterSearch($request, false, $visibility, !empty($_SESSION['untaggedonly']));
1633 } 1647 }
1634 1648
1635 // ---- Handle paging. 1649 // ---- Handle paging.
@@ -1676,7 +1690,7 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager)
1676 } 1690 }
1677 1691
1678 // Compute paging navigation 1692 // Compute paging navigation
1679 $searchtagsUrl = empty($searchtags) ? '' : '&searchtags=' . urlencode($searchtags); 1693 $searchtagsUrl = $searchtags === '' ? '' : '&searchtags=' . urlencode($searchtags);
1680 $searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm); 1694 $searchtermUrl = empty($searchterm) ? '' : '&searchterm=' . urlencode($searchterm);
1681 $previous_page_url = ''; 1695 $previous_page_url = '';
1682 if ($i != count($keys)) { 1696 if ($i != count($keys)) {
@@ -2223,6 +2237,12 @@ if (!isset($_SESSION['LINKS_PER_PAGE'])) {
2223 $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20); 2237 $_SESSION['LINKS_PER_PAGE'] = $conf->get('general.links_per_page', 20);
2224} 2238}
2225 2239
2240try {
2241 $history = new History($conf->get('resource.history'));
2242} catch(Exception $e) {
2243 die($e->getMessage());
2244}
2245
2226$linkDb = new LinkDB( 2246$linkDb = new LinkDB(
2227 $conf->get('resource.datastore'), 2247 $conf->get('resource.datastore'),
2228 isLoggedIn(), 2248 isLoggedIn(),
@@ -2231,12 +2251,6 @@ $linkDb = new LinkDB(
2231 $conf->get('redirector.encode_url') 2251 $conf->get('redirector.encode_url')
2232); 2252);
2233 2253
2234try {
2235 $history = new History($conf->get('resource.history'));
2236} catch(Exception $e) {
2237 die($e->getMessage());
2238}
2239
2240$container = new \Slim\Container(); 2254$container = new \Slim\Container();
2241$container['conf'] = $conf; 2255$container['conf'] = $conf;
2242$container['plugins'] = $pluginManager; 2256$container['plugins'] = $pluginManager;