diff options
Diffstat (limited to 'index.php')
-rw-r--r-- | index.php | 350 |
1 files changed, 181 insertions, 169 deletions
@@ -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 | */ |
122 | define('shaarli_version', '0.6.1'); | 122 | define('shaarli_version', '0.6.2'); |
123 | 123 | ||
124 | // http://server.com/x/shaarli --> /shaarli/ | 124 | // http://server.com/x/shaarli --> /shaarli/ |
125 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); | 125 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); |
@@ -151,6 +151,8 @@ require_once 'application/CachedPage.php'; | |||
151 | require_once 'application/FileUtils.php'; | 151 | require_once 'application/FileUtils.php'; |
152 | require_once 'application/HttpUtils.php'; | 152 | require_once 'application/HttpUtils.php'; |
153 | require_once 'application/LinkDB.php'; | 153 | require_once 'application/LinkDB.php'; |
154 | require_once 'application/LinkFilter.php'; | ||
155 | require_once 'application/LinkUtils.php'; | ||
154 | require_once 'application/TimeZone.php'; | 156 | require_once 'application/TimeZone.php'; |
155 | require_once 'application/Url.php'; | 157 | require_once 'application/Url.php'; |
156 | require_once 'application/Utils.php'; | 158 | require_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 | ||
312 | function 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.) | ||
582 | function 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() | |||
1865 | function buildLinkList($PAGE,$LINKSDB) | 1871 | function 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'); |