aboutsummaryrefslogtreecommitdiffhomepage
path: root/index.php
diff options
context:
space:
mode:
Diffstat (limited to 'index.php')
-rw-r--r--index.php350
1 files changed, 181 insertions, 169 deletions
diff --git a/index.php b/index.php
index d0876d95..beba9c32 100644
--- a/index.php
+++ b/index.php
@@ -1,6 +1,6 @@
1<?php 1<?php
2/** 2/**
3 * Shaarli v0.6.1 - Shaare your links... 3 * Shaarli v0.6.2 - Shaare your links...
4 * 4 *
5 * The personal, minimalist, super-fast, no-database Delicious clone. 5 * The personal, minimalist, super-fast, no-database Delicious clone.
6 * 6 *
@@ -119,7 +119,7 @@ $GLOBALS['config']['PUBSUBHUB_URL'] = '';
119/* 119/*
120 * PHP configuration 120 * PHP configuration
121 */ 121 */
122define('shaarli_version', '0.6.1'); 122define('shaarli_version', '0.6.2');
123 123
124// http://server.com/x/shaarli --> /shaarli/ 124// http://server.com/x/shaarli --> /shaarli/
125define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); 125define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0)));
@@ -151,6 +151,8 @@ require_once 'application/CachedPage.php';
151require_once 'application/FileUtils.php'; 151require_once 'application/FileUtils.php';
152require_once 'application/HttpUtils.php'; 152require_once 'application/HttpUtils.php';
153require_once 'application/LinkDB.php'; 153require_once 'application/LinkDB.php';
154require_once 'application/LinkFilter.php';
155require_once 'application/LinkUtils.php';
154require_once 'application/TimeZone.php'; 156require_once 'application/TimeZone.php';
155require_once 'application/Url.php'; 157require_once 'application/Url.php';
156require_once 'application/Utils.php'; 158require_once 'application/Utils.php';
@@ -307,14 +309,6 @@ function setup_login_state() {
307$userIsLoggedIn = setup_login_state(); 309$userIsLoggedIn = setup_login_state();
308 310
309 311
310// -----------------------------------------------------------------------------------------------
311// Log to text file
312function logm($message)
313{
314 $t = strval(date('Y/m/d_H:i:s')).' - '.$_SERVER["REMOTE_ADDR"].' - '.strval($message)."\n";
315 file_put_contents($GLOBALS['config']['LOG_FILE'], $t, FILE_APPEND);
316}
317
318// ------------------------------------------------------------------------------------------ 312// ------------------------------------------------------------------------------------------
319// Sniff browser language to display dates in the right format automatically. 313// Sniff browser language to display dates in the right format automatically.
320// (Note that is may not work on your server if the corresponding local is not installed.) 314// (Note that is may not work on your server if the corresponding local is not installed.)
@@ -378,10 +372,10 @@ function check_auth($login,$password)
378 if ($login==$GLOBALS['login'] && $hash==$GLOBALS['hash']) 372 if ($login==$GLOBALS['login'] && $hash==$GLOBALS['hash'])
379 { // Login/password is correct. 373 { // Login/password is correct.
380 fillSessionInfo(); 374 fillSessionInfo();
381 logm('Login successful'); 375 logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], 'Login successful');
382 return True; 376 return True;
383 } 377 }
384 logm('Login failed for user '.$login); 378 logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], 'Login failed for user '.$login);
385 return False; 379 return False;
386} 380}
387 381
@@ -418,7 +412,7 @@ function ban_loginFailed()
418 if ($gb['FAILURES'][$ip]>($GLOBALS['config']['BAN_AFTER']-1)) 412 if ($gb['FAILURES'][$ip]>($GLOBALS['config']['BAN_AFTER']-1))
419 { 413 {
420 $gb['BANS'][$ip]=time()+$GLOBALS['config']['BAN_DURATION']; 414 $gb['BANS'][$ip]=time()+$GLOBALS['config']['BAN_DURATION'];
421 logm('IP address banned from login'); 415 logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], 'IP address banned from login');
422 } 416 }
423 $GLOBALS['IPBANS'] = $gb; 417 $GLOBALS['IPBANS'] = $gb;
424 file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); 418 file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>");
@@ -442,7 +436,7 @@ function ban_canLogin()
442 // User is banned. Check if the ban has expired: 436 // User is banned. Check if the ban has expired:
443 if ($gb['BANS'][$ip]<=time()) 437 if ($gb['BANS'][$ip]<=time())
444 { // Ban expired, user can try to login again. 438 { // Ban expired, user can try to login again.
445 logm('Ban lifted.'); 439 logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], 'Ban lifted.');
446 unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]); 440 unset($gb['FAILURES'][$ip]); unset($gb['BANS'][$ip]);
447 file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>"); 441 file_put_contents($GLOBALS['config']['IPBANS_FILENAME'], "<?php\n\$GLOBALS['IPBANS']=".var_export($gb,true).";\n?>");
448 return true; // Ban has expired, user can login. 442 return true; // Ban has expired, user can login.
@@ -478,7 +472,7 @@ if (isset($_POST['login']))
478 session_set_cookie_params(0,$cookiedir,$_SERVER['SERVER_NAME']); // 0 means "When browser closes" 472 session_set_cookie_params(0,$cookiedir,$_SERVER['SERVER_NAME']); // 0 means "When browser closes"
479 session_regenerate_id(true); 473 session_regenerate_id(true);
480 } 474 }
481 475
482 // Optional redirect after login: 476 // Optional redirect after login:
483 if (isset($_GET['post'])) { 477 if (isset($_GET['post'])) {
484 $uri = '?post='. urlencode($_GET['post']); 478 $uri = '?post='. urlencode($_GET['post']);
@@ -577,13 +571,6 @@ function linkdate2iso8601($linkdate)
577 return date('c',linkdate2timestamp($linkdate)); // 'c' is for ISO 8601 date format. 571 return date('c',linkdate2timestamp($linkdate)); // 'c' is for ISO 8601 date format.
578} 572}
579 573
580// Extract title from an HTML document.
581// (Returns an empty string if not found.)
582function html_extract_title($html)
583{
584 return preg_match('!<title>(.*?)</title>!is', $html, $matches) ? trim(str_replace("\n",' ', $matches[1])) : '' ;
585}
586
587// ------------------------------------------------------------------------------------------ 574// ------------------------------------------------------------------------------------------
588// Token management for XSRF protection 575// Token management for XSRF protection
589// Token should be used in any form which acts on data (create,update,delete,import...). 576// Token should be used in any form which acts on data (create,update,delete,import...).
@@ -646,7 +633,7 @@ class pageBuilder
646 $this->tpl->assign('versionError', ''); 633 $this->tpl->assign('versionError', '');
647 634
648 } catch (Exception $exc) { 635 } catch (Exception $exc) {
649 logm($exc->getMessage()); 636 logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], $exc->getMessage());
650 $this->tpl->assign('newVersion', ''); 637 $this->tpl->assign('newVersion', '');
651 $this->tpl->assign('versionError', escape($exc->getMessage())); 638 $this->tpl->assign('versionError', escape($exc->getMessage()));
652 } 639 }
@@ -694,6 +681,18 @@ class pageBuilder
694 if ($this->tpl===false) $this->initialize(); // Lazy initialization 681 if ($this->tpl===false) $this->initialize(); // Lazy initialization
695 $this->tpl->draw($page); 682 $this->tpl->draw($page);
696 } 683 }
684
685 /**
686 * Render a 404 page (uses the template : tpl/404.tpl)
687 *
688 * usage : $PAGE->render404('The link was deleted')
689 * @param string $message A messate to display what is not found
690 */
691 public function render404($message='The page you are trying to reach does not exist or has been deleted.') {
692 header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found');
693 $this->tpl->assign('error_message', $message);
694 $this->renderPage('404');
695 }
697} 696}
698 697
699// ------------------------------------------------------------------------------------------ 698// ------------------------------------------------------------------------------------------
@@ -730,18 +729,23 @@ function showRSS()
730 // Read links from database (and filter private links if user it not logged in). 729 // Read links from database (and filter private links if user it not logged in).
731 730
732 // Optionally filter the results: 731 // Optionally filter the results:
733 $linksToDisplay=array(); 732 if (!empty($_GET['searchterm'])) {
734 if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); 733 $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_TEXT, $_GET['searchterm']);
735 else if (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); 734 }
736 else $linksToDisplay = $LINKSDB; 735 elseif (!empty($_GET['searchtags'])) {
736 $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_TAG, trim($_GET['searchtags']));
737 }
738 else {
739 $linksToDisplay = $LINKSDB;
740 }
737 741
738 $nblinksToDisplay = 50; // Number of links to display. 742 $nblinksToDisplay = 50; // Number of links to display.
739 if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. 743 // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.
740 { 744 if (!empty($_GET['nb'])) {
741 $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; 745 $nblinksToDisplay = $_GET['nb'] == 'all' ? count($linksToDisplay) : max(intval($_GET['nb']), 1);
742 } 746 }
743 747
744 $pageaddr=escape(index_url($_SERVER)); 748 $pageaddr = escape(index_url($_SERVER));
745 echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">'; 749 echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">';
746 echo '<channel><title>'.$GLOBALS['title'].'</title><link>'.$pageaddr.'</link>'; 750 echo '<channel><title>'.$GLOBALS['title'].'</title><link>'.$pageaddr.'</link>';
747 echo '<description>Shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n\n"; 751 echo '<description>Shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n\n";
@@ -821,15 +825,20 @@ function showATOM()
821 ); 825 );
822 826
823 // Optionally filter the results: 827 // Optionally filter the results:
824 $linksToDisplay=array(); 828 if (!empty($_GET['searchterm'])) {
825 if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); 829 $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_TEXT, $_GET['searchterm']);
826 else if (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); 830 }
827 else $linksToDisplay = $LINKSDB; 831 else if (!empty($_GET['searchtags'])) {
832 $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_TAG, trim($_GET['searchtags']));
833 }
834 else {
835 $linksToDisplay = $LINKSDB;
836 }
828 837
829 $nblinksToDisplay = 50; // Number of links to display. 838 $nblinksToDisplay = 50; // Number of links to display.
830 if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. 839 // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.
831 { 840 if (!empty($_GET['nb'])) {
832 $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; 841 $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max(intval($_GET['nb']), 1);
833 } 842 }
834 843
835 $pageaddr=escape(index_url($_SERVER)); 844 $pageaddr=escape(index_url($_SERVER));
@@ -1024,7 +1033,7 @@ function showDaily($pageBuilder)
1024 } 1033 }
1025 1034
1026 try { 1035 try {
1027 $linksToDisplay = $LINKSDB->filterDay($day); 1036 $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_DAY, $day);
1028 } catch (Exception $exc) { 1037 } catch (Exception $exc) {
1029 error_log($exc); 1038 error_log($exc);
1030 $linksToDisplay = array(); 1039 $linksToDisplay = array();
@@ -1149,13 +1158,17 @@ function renderPage()
1149 if ($targetPage == Router::$PAGE_PICWALL) 1158 if ($targetPage == Router::$PAGE_PICWALL)
1150 { 1159 {
1151 // Optionally filter the results: 1160 // Optionally filter the results:
1152 $links=array(); 1161 if (!empty($_GET['searchterm'])) {
1153 if (!empty($_GET['searchterm'])) $links = $LINKSDB->filterFulltext($_GET['searchterm']); 1162 $links = $LINKSDB->filter(LinkFilter::$FILTER_TEXT, $_GET['searchterm']);
1154 elseif (!empty($_GET['searchtags'])) $links = $LINKSDB->filterTags(trim($_GET['searchtags'])); 1163 }
1155 else $links = $LINKSDB; 1164 elseif (! empty($_GET['searchtags'])) {
1165 $links = $LINKSDB->filter(LinkFilter::$FILTER_TAG, trim($_GET['searchtags']));
1166 }
1167 else {
1168 $links = $LINKSDB;
1169 }
1156 1170
1157 $body=''; 1171 $linksToDisplay = array();
1158 $linksToDisplay=array();
1159 1172
1160 // Get only links which have a thumbnail. 1173 // Get only links which have a thumbnail.
1161 foreach($links as $link) 1174 foreach($links as $link)
@@ -1282,13 +1295,15 @@ function renderPage()
1282 } 1295 }
1283 1296
1284 if (isset($params['searchtags'])) { 1297 if (isset($params['searchtags'])) {
1285 $tags = explode(' ',$params['searchtags']); 1298 $tags = explode(' ', $params['searchtags']);
1286 $tags=array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags. 1299 // Remove value from array $tags.
1287 if (count($tags)==0) { 1300 $tags = array_diff($tags, array($_GET['removetag']));
1301 $params['searchtags'] = implode(' ',$tags);
1302
1303 if (empty($params['searchtags'])) {
1288 unset($params['searchtags']); 1304 unset($params['searchtags']);
1289 } else {
1290 $params['searchtags'] = implode(' ',$tags);
1291 } 1305 }
1306
1292 unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) 1307 unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different)
1293 } 1308 }
1294 header('Location: ?'.http_build_query($params)); 1309 header('Location: ?'.http_build_query($params));
@@ -1453,21 +1468,23 @@ function renderPage()
1453 // -------- User wants to rename a tag or delete it 1468 // -------- User wants to rename a tag or delete it
1454 if ($targetPage == Router::$PAGE_CHANGETAG) 1469 if ($targetPage == Router::$PAGE_CHANGETAG)
1455 { 1470 {
1456 if (empty($_POST['fromtag'])) 1471 if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) {
1457 { 1472 $PAGE->assign('linkcount', count($LINKSDB));
1458 $PAGE->assign('linkcount',count($LINKSDB)); 1473 $PAGE->assign('token', getToken());
1459 $PAGE->assign('token',getToken());
1460 $PAGE->assign('tags', $LINKSDB->allTags()); 1474 $PAGE->assign('tags', $LINKSDB->allTags());
1461 $PAGE->renderPage('changetag'); 1475 $PAGE->renderPage('changetag');
1462 exit; 1476 exit;
1463 } 1477 }
1464 if (!tokenOk($_POST['token'])) die('Wrong token.'); 1478
1479 if (!tokenOk($_POST['token'])) {
1480 die('Wrong token.');
1481 }
1465 1482
1466 // Delete a tag: 1483 // Delete a tag:
1467 if (!empty($_POST['deletetag']) && !empty($_POST['fromtag'])) 1484 if (isset($_POST['deletetag']) && !empty($_POST['fromtag'])) {
1468 {
1469 $needle=trim($_POST['fromtag']); 1485 $needle=trim($_POST['fromtag']);
1470 $linksToAlter = $LINKSDB->filterTags($needle,true); // True for case-sensitive tag search. 1486 // True for case-sensitive tag search.
1487 $linksToAlter = $LINKSDB->filter(LinkFilter::$FILTER_TAG, $needle, true);
1471 foreach($linksToAlter as $key=>$value) 1488 foreach($linksToAlter as $key=>$value)
1472 { 1489 {
1473 $tags = explode(' ',trim($value['tags'])); 1490 $tags = explode(' ',trim($value['tags']));
@@ -1481,10 +1498,10 @@ function renderPage()
1481 } 1498 }
1482 1499
1483 // Rename a tag: 1500 // Rename a tag:
1484 if (!empty($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) 1501 if (isset($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) {
1485 {
1486 $needle=trim($_POST['fromtag']); 1502 $needle=trim($_POST['fromtag']);
1487 $linksToAlter = $LINKSDB->filterTags($needle,true); // true for case-sensitive tag search. 1503 // True for case-sensitive tag search.
1504 $linksToAlter = $LINKSDB->filter(LinkFilter::$FILTER_TAG, $needle, true);
1488 foreach($linksToAlter as $key=>$value) 1505 foreach($linksToAlter as $key=>$value)
1489 { 1506 {
1490 $tags = explode(' ',trim($value['tags'])); 1507 $tags = explode(' ',trim($value['tags']));
@@ -1623,7 +1640,7 @@ function renderPage()
1623 1640
1624 // -------- User want to post a new link: Display link edit form. 1641 // -------- User want to post a new link: Display link edit form.
1625 if (isset($_GET['post'])) { 1642 if (isset($_GET['post'])) {
1626 $url = cleanup_url($_GET['post']); 1643 $url = cleanup_url(escape($_GET['post']));
1627 1644
1628 $link_is_new = false; 1645 $link_is_new = false;
1629 // Check if URL is not already in database (in this case, we will edit the existing link) 1646 // Check if URL is not already in database (in this case, we will edit the existing link)
@@ -1641,35 +1658,24 @@ function renderPage()
1641 // If this is an HTTP(S) link, we try go get the page to extract the title (otherwise we will to straight to the edit form.) 1658 // If this is an HTTP(S) link, we try go get the page to extract the title (otherwise we will to straight to the edit form.)
1642 if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) { 1659 if (empty($title) && strpos(get_url_scheme($url), 'http') !== false) {
1643 // Short timeout to keep the application responsive 1660 // Short timeout to keep the application responsive
1644 list($headers, $data) = get_http_url($url, 4); 1661 list($headers, $content) = get_http_response($url, 4);
1645 // FIXME: Decode charset according to specified in either 1) HTTP response headers or 2) <head> in html
1646 if (strpos($headers[0], '200 OK') !== false) { 1662 if (strpos($headers[0], '200 OK') !== false) {
1647 // Look for charset in html header. 1663 // Retrieve charset.
1648 preg_match('#<meta .*charset=.*>#Usi', $data, $meta); 1664 $charset = get_charset($headers, $content);
1649 1665 // Extract title.
1650 // If found, extract encoding. 1666 $title = html_extract_title($content);
1651 if (!empty($meta[0])) { 1667 // Re-encode title in utf-8 if necessary.
1652 // Get encoding specified in header. 1668 if (! empty($title) && $charset != 'utf-8') {
1653 preg_match('#charset="?(.*)"#si', $meta[0], $enc); 1669 $title = mb_convert_encoding($title, $charset, 'utf-8');
1654 // If charset not found, use utf-8.
1655 $html_charset = (!empty($enc[1])) ? strtolower($enc[1]) : 'utf-8';
1656 }
1657 else {
1658 $html_charset = 'utf-8';
1659 }
1660
1661 // Extract title
1662 $title = html_extract_title($data);
1663 if (!empty($title)) {
1664 // Re-encode title in utf-8 if necessary.
1665 $title = ($html_charset == 'iso-8859-1') ? utf8_encode($title) : $title;
1666 } 1670 }
1667 } 1671 }
1668 } 1672 }
1673
1669 if ($url == '') { 1674 if ($url == '') {
1670 $url = '?' . smallHash($linkdate); 1675 $url = '?' . smallHash($linkdate);
1671 $title = 'Note: '; 1676 $title = 'Note: ';
1672 } 1677 }
1678
1673 $link = array( 1679 $link = array(
1674 'linkdate' => $linkdate, 1680 'linkdate' => $linkdate,
1675 'title' => $title, 1681 'title' => $title,
@@ -1865,81 +1871,75 @@ function importFile()
1865function buildLinkList($PAGE,$LINKSDB) 1871function buildLinkList($PAGE,$LINKSDB)
1866{ 1872{
1867 // ---- Filter link database according to parameters 1873 // ---- Filter link database according to parameters
1868 $linksToDisplay=array(); 1874 $search_type = '';
1869 $search_type=''; 1875 $search_crits = '';
1870 $search_crits=''; 1876 $privateonly = !empty($_SESSION['privateonly']) ? true : false;
1871 if (isset($_GET['searchterm'])) // Fulltext search 1877
1872 { 1878 // Fulltext search
1873 $linksToDisplay = $LINKSDB->filterFulltext(trim($_GET['searchterm'])); 1879 if (isset($_GET['searchterm'])) {
1874 $search_crits=escape(trim($_GET['searchterm'])); 1880 $search_crits = escape(trim($_GET['searchterm']));
1875 $search_type='fulltext'; 1881 $search_type = LinkFilter::$FILTER_TEXT;
1876 } 1882 $linksToDisplay = $LINKSDB->filter($search_type, $search_crits, false, $privateonly);
1877 elseif (isset($_GET['searchtags'])) // Search by tag 1883 }
1878 { 1884 // Search by tag
1879 $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); 1885 elseif (isset($_GET['searchtags'])) {
1880 $search_crits=explode(' ',escape(trim($_GET['searchtags']))); 1886 $search_crits = explode(' ', escape(trim($_GET['searchtags'])));
1881 $search_type='tags'; 1887 $search_type = LinkFilter::$FILTER_TAG;
1882 } 1888 $linksToDisplay = $LINKSDB->filter($search_type, $search_crits, false, $privateonly);
1883 elseif (isset($_SERVER['QUERY_STRING']) && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/',$_SERVER['QUERY_STRING'])) // Detect smallHashes in URL 1889 }
1884 { 1890 // Detect smallHashes in URL.
1885 $linksToDisplay = $LINKSDB->filterSmallHash(substr(trim($_SERVER["QUERY_STRING"], '/'),0,6)); 1891 elseif (isset($_SERVER['QUERY_STRING'])
1886 if (count($linksToDisplay)==0) 1892 && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/', $_SERVER['QUERY_STRING'])) {
1887 { 1893 $search_type = LinkFilter::$FILTER_HASH;
1888 header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); 1894 $search_crits = substr(trim($_SERVER["QUERY_STRING"], '/'), 0, 6);
1889 echo '<h1>404 Not found.</h1>Oh crap. The link you are trying to reach does not exist or has been deleted.'; 1895 $linksToDisplay = $LINKSDB->filter($search_type, $search_crits);
1890 echo '<br>Would you mind <a href="?">clicking here</a>?'; 1896
1897 if (count($linksToDisplay) == 0) {
1898 $PAGE->render404('The link you are trying to reach does not exist or has been deleted.');
1891 exit; 1899 exit;
1892 } 1900 }
1893 $search_type='permalink';
1894 } 1901 }
1895 else 1902 // Otherwise, display without filtering.
1896 $linksToDisplay = $LINKSDB; // Otherwise, display without filtering. 1903 else {
1897 1904 $linksToDisplay = $LINKSDB->filter('', '', false, $privateonly);
1898
1899 // Option: Show only private links
1900 if (!empty($_SESSION['privateonly']))
1901 {
1902 $tmp = array();
1903 foreach($linksToDisplay as $linkdate=>$link)
1904 {
1905 if ($link['private']!=0) $tmp[$linkdate]=$link;
1906 }
1907 $linksToDisplay=$tmp;
1908 } 1905 }
1909 1906
1910 // ---- Handle paging. 1907 // ---- Handle paging.
1911 /* Can someone explain to me why you get the following error when using array_keys() on an object which implements the interface ArrayAccess??? 1908 $keys = array();
1912 "Warning: array_keys() expects parameter 1 to be array, object given in ... " 1909 foreach ($linksToDisplay as $key => $value) {
1913 If my class implements ArrayAccess, why won't array_keys() accept it ? ( $keys=array_keys($linksToDisplay); ) 1910 $keys[] = $key;
1914 */ 1911 }
1915 $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // Stupid and ugly. Thanks PHP.
1916 1912
1917 // If there is only a single link, we change on-the-fly the title of the page. 1913 // If there is only a single link, we change on-the-fly the title of the page.
1918 if (count($linksToDisplay)==1) $GLOBALS['pagetitle'] = $linksToDisplay[$keys[0]]['title'].' - '.$GLOBALS['title']; 1914 if (count($linksToDisplay) == 1) {
1915 $GLOBALS['pagetitle'] = $linksToDisplay[$keys[0]]['title'].' - '.$GLOBALS['title'];
1916 }
1919 1917
1920 // Select articles according to paging. 1918 // Select articles according to paging.
1921 $pagecount = ceil(count($keys)/$_SESSION['LINKS_PER_PAGE']); 1919 $pagecount = ceil(count($keys) / $_SESSION['LINKS_PER_PAGE']);
1922 $pagecount = ($pagecount==0 ? 1 : $pagecount); 1920 $pagecount = $pagecount == 0 ? 1 : $pagecount;
1923 $page=( empty($_GET['page']) ? 1 : intval($_GET['page'])); 1921 $page= empty($_GET['page']) ? 1 : intval($_GET['page']);
1924 $page = ( $page<1 ? 1 : $page ); 1922 $page = $page < 1 ? 1 : $page;
1925 $page = ( $page>$pagecount ? $pagecount : $page ); 1923 $page = $page > $pagecount ? $pagecount : $page;
1926 $i = ($page-1)*$_SESSION['LINKS_PER_PAGE']; // Start index. 1924 // Start index.
1927 $end = $i+$_SESSION['LINKS_PER_PAGE']; 1925 $i = ($page-1) * $_SESSION['LINKS_PER_PAGE'];
1928 $linkDisp=array(); // Links to display 1926 $end = $i + $_SESSION['LINKS_PER_PAGE'];
1927 $linkDisp = array();
1929 while ($i<$end && $i<count($keys)) 1928 while ($i<$end && $i<count($keys))
1930 { 1929 {
1931 $link = $linksToDisplay[$keys[$i]]; 1930 $link = $linksToDisplay[$keys[$i]];
1932 $link['description'] = format_description($link['description'], $GLOBALS['redirector']); 1931 $link['description'] = format_description($link['description'], $GLOBALS['redirector']);
1933 $classLi = $i%2!=0 ? '' : 'publicLinkHightLight'; 1932 $classLi = ($i % 2) != 0 ? '' : 'publicLinkHightLight';
1934 $link['class'] = ($link['private']==0 ? $classLi : 'private'); 1933 $link['class'] = $link['private'] == 0 ? $classLi : 'private';
1935 $link['timestamp']=linkdate2timestamp($link['linkdate']); 1934 $link['timestamp'] = linkdate2timestamp($link['linkdate']);
1936 $taglist = explode(' ',$link['tags']); 1935 $taglist = explode(' ', $link['tags']);
1937 uasort($taglist, 'strcasecmp'); 1936 uasort($taglist, 'strcasecmp');
1938 $link['taglist']=$taglist; 1937 $link['taglist'] = $taglist;
1939 $link['shorturl'] = smallHash($link['linkdate']); 1938 $link['shorturl'] = smallHash($link['linkdate']);
1940 if ($link["url"][0] === '?' && // Check for both signs of a note: starting with ? and 7 chars long. I doubt that you'll post any links that look like this. 1939 // Check for both signs of a note: starting with ? and 7 chars long.
1941 strlen($link["url"]) === 7) { 1940 if ($link['url'][0] === '?' &&
1942 $link["url"] = index_url($_SERVER) . $link["url"]; 1941 strlen($link['url']) === 7) {
1942 $link['url'] = index_url($_SERVER) . $link['url'];
1943 } 1943 }
1944 1944
1945 $linkDisp[$keys[$i]] = $link; 1945 $linkDisp[$keys[$i]] = $link;
@@ -1947,13 +1947,21 @@ function buildLinkList($PAGE,$LINKSDB)
1947 } 1947 }
1948 1948
1949 // Compute paging navigation 1949 // Compute paging navigation
1950 $searchterm= ( empty($_GET['searchterm']) ? '' : '&searchterm='.$_GET['searchterm'] ); 1950 $searchterm = empty($_GET['searchterm']) ? '' : '&searchterm=' . $_GET['searchterm'];
1951 $searchtags= ( empty($_GET['searchtags']) ? '' : '&searchtags='.$_GET['searchtags'] ); 1951 $searchtags = empty($_GET['searchtags']) ? '' : '&searchtags=' . $_GET['searchtags'];
1952 $paging=''; 1952 $previous_page_url = '';
1953 $previous_page_url=''; if ($i!=count($keys)) $previous_page_url='?page='.($page+1).$searchterm.$searchtags; 1953 if ($i != count($keys)) {
1954 $next_page_url='';if ($page>1) $next_page_url='?page='.($page-1).$searchterm.$searchtags; 1954 $previous_page_url = '?page=' . ($page+1) . $searchterm . $searchtags;
1955 }
1956 $next_page_url='';
1957 if ($page>1) {
1958 $next_page_url = '?page=' . ($page-1) . $searchterm . $searchtags;
1959 }
1955 1960
1956 $token = ''; if (isLoggedIn()) $token=getToken(); 1961 $token = '';
1962 if (isLoggedIn()) {
1963 $token = getToken();
1964 }
1957 1965
1958 // Fill all template fields. 1966 // Fill all template fields.
1959 $data = array( 1967 $data = array(
@@ -2290,11 +2298,11 @@ function genThumbnail()
2290 else // This is a flickr page (html) 2298 else // This is a flickr page (html)
2291 { 2299 {
2292 // Get the flickr html page. 2300 // Get the flickr html page.
2293 list($headers, $data) = get_http_url($url, 20); 2301 list($headers, $content) = get_http_response($url, 20);
2294 if (strpos($headers[0], '200 OK') !== false) 2302 if (strpos($headers[0], '200 OK') !== false)
2295 { 2303 {
2296 // flickr now nicely provides the URL of the thumbnail in each flickr page. 2304 // flickr now nicely provides the URL of the thumbnail in each flickr page.
2297 preg_match('!<link rel=\"image_src\" href=\"(.+?)\"!',$data,$matches); 2305 preg_match('!<link rel=\"image_src\" href=\"(.+?)\"!', $content, $matches);
2298 if (!empty($matches[1])) $imageurl=$matches[1]; 2306 if (!empty($matches[1])) $imageurl=$matches[1];
2299 2307
2300 // In albums (and some other pages), the link rel="image_src" is not provided, 2308 // In albums (and some other pages), the link rel="image_src" is not provided,
@@ -2302,7 +2310,7 @@ function genThumbnail()
2302 // <meta property="og:image" content="http://farm4.staticflickr.com/3398/3239339068_25d13535ff_z.jpg" /> 2310 // <meta property="og:image" content="http://farm4.staticflickr.com/3398/3239339068_25d13535ff_z.jpg" />
2303 if ($imageurl=='') 2311 if ($imageurl=='')
2304 { 2312 {
2305 preg_match('!<meta property=\"og:image\" content=\"(.+?)\"!',$data,$matches); 2313 preg_match('!<meta property=\"og:image\" content=\"(.+?)\"!', $content, $matches);
2306 if (!empty($matches[1])) $imageurl=$matches[1]; 2314 if (!empty($matches[1])) $imageurl=$matches[1];
2307 } 2315 }
2308 } 2316 }
@@ -2311,11 +2319,12 @@ function genThumbnail()
2311 if ($imageurl!='') 2319 if ($imageurl!='')
2312 { // Let's download the image. 2320 { // Let's download the image.
2313 // Image is 240x120, so 10 seconds to download should be enough. 2321 // Image is 240x120, so 10 seconds to download should be enough.
2314 list($headers, $data) = get_http_url($imageurl, 10); 2322 list($headers, $content) = get_http_response($imageurl, 10);
2315 if (strpos($headers[0], '200 OK') !== false) { 2323 if (strpos($headers[0], '200 OK') !== false) {
2316 file_put_contents($GLOBALS['config']['CACHEDIR'].'/'.$thumbname,$data); // Save image to cache. 2324 // Save image to cache.
2325 file_put_contents($GLOBALS['config']['CACHEDIR'].'/' . $thumbname, $content);
2317 header('Content-Type: image/jpeg'); 2326 header('Content-Type: image/jpeg');
2318 echo $data; 2327 echo $content;
2319 return; 2328 return;
2320 } 2329 }
2321 } 2330 }
@@ -2326,16 +2335,17 @@ function genThumbnail()
2326 // This is more complex: we have to perform a HTTP request, then parse the result. 2335 // This is more complex: we have to perform a HTTP request, then parse the result.
2327 // Maybe we should deport this to JavaScript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098 2336 // Maybe we should deport this to JavaScript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098
2328 $vid = substr(parse_url($url,PHP_URL_PATH),1); 2337 $vid = substr(parse_url($url,PHP_URL_PATH),1);
2329 list($headers, $data) = get_http_url('https://vimeo.com/api/v2/video/'.escape($vid).'.php', 5); 2338 list($headers, $content) = get_http_response('https://vimeo.com/api/v2/video/'.escape($vid).'.php', 5);
2330 if (strpos($headers[0], '200 OK') !== false) { 2339 if (strpos($headers[0], '200 OK') !== false) {
2331 $t = unserialize($data); 2340 $t = unserialize($content);
2332 $imageurl = $t[0]['thumbnail_medium']; 2341 $imageurl = $t[0]['thumbnail_medium'];
2333 // Then we download the image and serve it to our client. 2342 // Then we download the image and serve it to our client.
2334 list($headers, $data) = get_http_url($imageurl, 10); 2343 list($headers, $content) = get_http_response($imageurl, 10);
2335 if (strpos($headers[0], '200 OK') !== false) { 2344 if (strpos($headers[0], '200 OK') !== false) {
2336 file_put_contents($GLOBALS['config']['CACHEDIR'].'/'.$thumbname,$data); // Save image to cache. 2345 // Save image to cache.
2346 file_put_contents($GLOBALS['config']['CACHEDIR'] . '/' . $thumbname, $content);
2337 header('Content-Type: image/jpeg'); 2347 header('Content-Type: image/jpeg');
2338 echo $data; 2348 echo $content;
2339 return; 2349 return;
2340 } 2350 }
2341 } 2351 }
@@ -2346,18 +2356,18 @@ function genThumbnail()
2346 // The thumbnail for TED talks is located in the <link rel="image_src" [...]> tag on that page 2356 // The thumbnail for TED talks is located in the <link rel="image_src" [...]> tag on that page
2347 // http://www.ted.com/talks/mikko_hypponen_fighting_viruses_defending_the_net.html 2357 // http://www.ted.com/talks/mikko_hypponen_fighting_viruses_defending_the_net.html
2348 // <link rel="image_src" href="http://images.ted.com/images/ted/28bced335898ba54d4441809c5b1112ffaf36781_389x292.jpg" /> 2358 // <link rel="image_src" href="http://images.ted.com/images/ted/28bced335898ba54d4441809c5b1112ffaf36781_389x292.jpg" />
2349 list($headers, $data) = get_http_url($url, 5); 2359 list($headers, $content) = get_http_response($url, 5);
2350 if (strpos($headers[0], '200 OK') !== false) { 2360 if (strpos($headers[0], '200 OK') !== false) {
2351 // Extract the link to the thumbnail 2361 // Extract the link to the thumbnail
2352 preg_match('!link rel="image_src" href="(http://images.ted.com/images/ted/.+_\d+x\d+\.jpg)"!',$data,$matches); 2362 preg_match('!link rel="image_src" href="(http://images.ted.com/images/ted/.+_\d+x\d+\.jpg)"!', $content, $matches);
2353 if (!empty($matches[1])) 2363 if (!empty($matches[1]))
2354 { // Let's download the image. 2364 { // Let's download the image.
2355 $imageurl=$matches[1]; 2365 $imageurl=$matches[1];
2356 // No control on image size, so wait long enough 2366 // No control on image size, so wait long enough
2357 list($headers, $data) = get_http_url($imageurl, 20); 2367 list($headers, $content) = get_http_response($imageurl, 20);
2358 if (strpos($headers[0], '200 OK') !== false) { 2368 if (strpos($headers[0], '200 OK') !== false) {
2359 $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname; 2369 $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname;
2360 file_put_contents($filepath,$data); // Save image to cache. 2370 file_put_contents($filepath, $content); // Save image to cache.
2361 if (resizeImage($filepath)) 2371 if (resizeImage($filepath))
2362 { 2372 {
2363 header('Content-Type: image/jpeg'); 2373 header('Content-Type: image/jpeg');
@@ -2374,18 +2384,19 @@ function genThumbnail()
2374 // There is no thumbnail available for xkcd comics, so download the whole image and resize it. 2384 // There is no thumbnail available for xkcd comics, so download the whole image and resize it.
2375 // http://xkcd.com/327/ 2385 // http://xkcd.com/327/
2376 // <img src="http://imgs.xkcd.com/comics/exploits_of_a_mom.png" title="<BLABLA>" alt="<BLABLA>" /> 2386 // <img src="http://imgs.xkcd.com/comics/exploits_of_a_mom.png" title="<BLABLA>" alt="<BLABLA>" />
2377 list($headers, $data) = get_http_url($url, 5); 2387 list($headers, $content) = get_http_response($url, 5);
2378 if (strpos($headers[0], '200 OK') !== false) { 2388 if (strpos($headers[0], '200 OK') !== false) {
2379 // Extract the link to the thumbnail 2389 // Extract the link to the thumbnail
2380 preg_match('!<img src="(http://imgs.xkcd.com/comics/.*)" title="[^s]!',$data,$matches); 2390 preg_match('!<img src="(http://imgs.xkcd.com/comics/.*)" title="[^s]!', $content, $matches);
2381 if (!empty($matches[1])) 2391 if (!empty($matches[1]))
2382 { // Let's download the image. 2392 { // Let's download the image.
2383 $imageurl=$matches[1]; 2393 $imageurl=$matches[1];
2384 // No control on image size, so wait long enough 2394 // No control on image size, so wait long enough
2385 list($headers, $data) = get_http_url($imageurl, 20); 2395 list($headers, $content) = get_http_response($imageurl, 20);
2386 if (strpos($headers[0], '200 OK') !== false) { 2396 if (strpos($headers[0], '200 OK') !== false) {
2387 $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname; 2397 $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname;
2388 file_put_contents($filepath,$data); // Save image to cache. 2398 // Save image to cache.
2399 file_put_contents($filepath, $content);
2389 if (resizeImage($filepath)) 2400 if (resizeImage($filepath))
2390 { 2401 {
2391 header('Content-Type: image/jpeg'); 2402 header('Content-Type: image/jpeg');
@@ -2401,10 +2412,11 @@ function genThumbnail()
2401 { 2412 {
2402 // For all other domains, we try to download the image and make a thumbnail. 2413 // For all other domains, we try to download the image and make a thumbnail.
2403 // We allow 30 seconds max to download (and downloads are limited to 4 Mb) 2414 // We allow 30 seconds max to download (and downloads are limited to 4 Mb)
2404 list($headers, $data) = get_http_url($url, 30); 2415 list($headers, $content) = get_http_response($url, 30);
2405 if (strpos($headers[0], '200 OK') !== false) { 2416 if (strpos($headers[0], '200 OK') !== false) {
2406 $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname; 2417 $filepath=$GLOBALS['config']['CACHEDIR'].'/'.$thumbname;
2407 file_put_contents($filepath,$data); // Save image to cache. 2418 // Save image to cache.
2419 file_put_contents($filepath, $content);
2408 if (resizeImage($filepath)) 2420 if (resizeImage($filepath))
2409 { 2421 {
2410 header('Content-Type: image/jpeg'); 2422 header('Content-Type: image/jpeg');