X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=index.php;h=85486eb50d72ea16be69fe59e261612356e2a435;hb=d5d22a6d07917865c44148ad76f43c65a929a890;hp=76aa1ae0efbc1c9d5945b34b29c23ae576b06e34;hpb=f9ff7f1b69f19b42569ffa67280807ba56f5d48a;p=github%2Fshaarli%2FShaarli.git diff --git a/index.php b/index.php index 76aa1ae0..85486eb5 100644 --- a/index.php +++ b/index.php @@ -225,27 +225,6 @@ function setup_login_state($conf) } $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 @@ -707,7 +686,7 @@ function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager) { * @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')), @@ -728,13 +707,7 @@ function renderPage($conf, $pluginManager, $LINKSDB) die($e->getMessage()); } - try { - $history = new History($conf->get('resource.history')); - } catch(Exception $e) { - 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()); @@ -817,7 +790,9 @@ function renderPage($conf, $pluginManager, $LINKSDB) // -------- 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. @@ -826,20 +801,13 @@ function renderPage($conf, $pluginManager, $LINKSDB) $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) { + if (in_array($key, $filteringTags)) { + continue; + } // Tag font size scaling: // default 15 and 30 logarithm bases affect scaling, // 22 and 6 are arbitrary font sizes for max and min sizes. @@ -851,6 +819,7 @@ function renderPage($conf, $pluginManager, $LINKSDB) } $data = array( + 'search_tags' => implode(' ', $filteringTags), 'tags' => $tagList, ); $pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => isLoggedIn())); @@ -859,7 +828,37 @@ function renderPage($conf, $pluginManager, $LINKSDB) $PAGE->assign($key, $value); } - $PAGE->renderPage('tagcloud'); + $PAGE->renderPage('tag.cloud'); + exit; + } + + // -------- Tag list + if ($targetPage == Router::$PAGE_TAGLIST) + { + $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all'; + $filteringTags = isset($_GET['searchtags']) ? explode(' ', $_GET['searchtags']) : []; + $tags = $LINKSDB->linksCountPerTag($filteringTags, $visibility); + foreach ($filteringTags as $tag) { + if (array_key_exists($tag, $tags)) { + unset($tags[$tag]); + } + } + + 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; } @@ -1167,7 +1166,6 @@ function renderPage($conf, $pluginManager, $LINKSDB) $PAGE->assign('hide_public_links', $conf->get('privacy.hide_public_links', false)); $PAGE->assign('api_enabled', $conf->get('api.enabled', true)); $PAGE->assign('api_secret', $conf->get('api.secret')); - $history->updateSettings(); $PAGE->renderPage('configure'); exit; } @@ -1177,7 +1175,7 @@ function renderPage($conf, $pluginManager, $LINKSDB) 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; } @@ -1266,13 +1264,7 @@ function renderPage($conf, $pluginManager, $LINKSDB) // Remove duplicates. $tags = implode(' ', array_unique(explode(' ', $tags))); - $url = trim($_POST['lf_url']); - if (! startsWith($url, 'http:') && ! startsWith($url, 'https:') - && ! startsWith($url, 'ftp:') && ! startsWith($url, 'magnet:') - && ! startsWith($url, '?') && ! startsWith($url, 'javascript:') - ) { - $url = 'http://' . $url; - } + $url = whitelist_protocols(trim($_POST['lf_url']), $conf->get('security.allowed_protocols')); $link = array( 'id' => $id, @@ -1337,18 +1329,21 @@ function renderPage($conf, $pluginManager, $LINKSDB) // -------- User clicked the "Delete" button when editing a link: Delete link from database. if ($targetPage == Router::$PAGE_DELETELINK) { - // We do not need to ask for confirmation: - // - confirmation is handled by JavaScript - // - we are protected from XSRF by the token. - if (! tokenOk($_GET['token'])) { die('Wrong token.'); } - $id = intval(escape($_GET['lf_linkdate'])); - $link = $LINKSDB[$id]; - $pluginManager->executeHooks('delete_link', $link); - unset($LINKSDB[$id]); + 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); @@ -1380,7 +1375,7 @@ function renderPage($conf, $pluginManager, $LINKSDB) '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); @@ -1438,7 +1433,7 @@ function renderPage($conf, $pluginManager, $LINKSDB) 'url' => $url, 'description' => $description, 'tags' => $tags, - 'private' => $private + 'private' => $private, ); } else { $link['linkdate'] = $link['created']->format(LinkDB::LINK_DATE_FORMAT); @@ -1449,7 +1444,7 @@ function renderPage($conf, $pluginManager, $LINKSDB) '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); @@ -1578,7 +1573,6 @@ function renderPage($conf, $pluginManager, $LINKSDB) // Plugin administration form action if ($targetPage == Router::$PAGE_SAVE_PLUGINSADMIN) { - $history->updateSettings(); try { if (isset($_POST['parameters_form'])) { unset($_POST['parameters_form']); @@ -1590,6 +1584,7 @@ function renderPage($conf, $pluginManager, $LINKSDB) $conf->set('general.enabled_plugins', save_plugin_config($_POST)); } $conf->write(isLoggedIn()); + $history->updateSettings(); } catch (Exception $e) { error_log( @@ -1605,6 +1600,13 @@ function renderPage($conf, $pluginManager, $LINKSDB) 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; @@ -1622,7 +1624,15 @@ function renderPage($conf, $pluginManager, $LINKSDB) 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 @@ -1637,7 +1647,11 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) } else { // Filter links according search parameters. $visibility = ! empty($_SESSION['privateonly']) ? 'private' : 'all'; - $linksToDisplay = $LINKSDB->filterSearch($_GET, false, $visibility); + $request = [ + 'searchtags' => $searchtags, + 'searchterm' => $searchterm, + ]; + $linksToDisplay = $LINKSDB->filterSearch($request, false, $visibility); } // ---- Handle paging. @@ -1684,7 +1698,7 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) } // 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)) { @@ -1707,7 +1721,6 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) '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. @@ -2240,9 +2253,16 @@ $linkDb = new LinkDB( $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 @@ -2251,6 +2271,9 @@ $app->group('/api/v1', function() { $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); @@ -2259,7 +2282,7 @@ $response = $app->run(true); 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); }