diff options
author | ArthurHoaro <arthur@hoa.ro> | 2016-10-12 13:58:35 +0200 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2016-10-12 13:58:35 +0200 |
commit | bc22c9a0acb095970e9494cbe8954f0612e05dc0 (patch) | |
tree | 4e3a94b7469f5b2e3eaf946756235730429bf9d4 /index.php | |
parent | 890afc32f744859d11b97eb26ed5c030af9b4145 (diff) | |
parent | ebd67c6e1b40aebdd3a52285ce9ff9412b2a3038 (diff) | |
download | Shaarli-bc22c9a0acb095970e9494cbe8954f0612e05dc0.tar.gz Shaarli-bc22c9a0acb095970e9494cbe8954f0612e05dc0.tar.zst Shaarli-bc22c9a0acb095970e9494cbe8954f0612e05dc0.zip |
Merge tag 'v0.7.0' of github.com:shaarli/Shaarli into stable
Release v0.7.0
Diffstat (limited to 'index.php')
-rw-r--r-- | index.php | 665 |
1 files changed, 166 insertions, 499 deletions
@@ -1,6 +1,6 @@ | |||
1 | <?php | 1 | <?php |
2 | /** | 2 | /** |
3 | * Shaarli v0.6.5 - Shaare your links... | 3 | * Shaarli v0.7.0 - 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 | * |
@@ -100,6 +100,7 @@ $GLOBALS['config']['ENABLE_LOCALCACHE'] = true; | |||
100 | $GLOBALS['config']['UPDATECHECK_BRANCH'] = 'stable'; | 100 | $GLOBALS['config']['UPDATECHECK_BRANCH'] = 'stable'; |
101 | $GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400; | 101 | $GLOBALS['config']['UPDATECHECK_INTERVAL'] = 86400; |
102 | 102 | ||
103 | $GLOBALS['config']['REDIRECTOR_URLENCODE'] = true; | ||
103 | 104 | ||
104 | /* | 105 | /* |
105 | * Plugin configuration | 106 | * Plugin configuration |
@@ -125,7 +126,7 @@ $GLOBALS['config']['PUBSUBHUB_URL'] = ''; | |||
125 | /* | 126 | /* |
126 | * PHP configuration | 127 | * PHP configuration |
127 | */ | 128 | */ |
128 | define('shaarli_version', '0.6.5'); | 129 | define('shaarli_version', '0.7.0'); |
129 | 130 | ||
130 | // http://server.com/x/shaarli --> /shaarli/ | 131 | // http://server.com/x/shaarli --> /shaarli/ |
131 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); | 132 | define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); |
@@ -154,11 +155,14 @@ if (is_file($GLOBALS['config']['CONFIG_FILE'])) { | |||
154 | require_once 'application/ApplicationUtils.php'; | 155 | require_once 'application/ApplicationUtils.php'; |
155 | require_once 'application/Cache.php'; | 156 | require_once 'application/Cache.php'; |
156 | require_once 'application/CachedPage.php'; | 157 | require_once 'application/CachedPage.php'; |
158 | require_once 'application/FeedBuilder.php'; | ||
157 | require_once 'application/FileUtils.php'; | 159 | require_once 'application/FileUtils.php'; |
158 | require_once 'application/HttpUtils.php'; | 160 | require_once 'application/HttpUtils.php'; |
159 | require_once 'application/LinkDB.php'; | 161 | require_once 'application/LinkDB.php'; |
160 | require_once 'application/LinkFilter.php'; | 162 | require_once 'application/LinkFilter.php'; |
161 | require_once 'application/LinkUtils.php'; | 163 | require_once 'application/LinkUtils.php'; |
164 | require_once 'application/NetscapeBookmarkUtils.php'; | ||
165 | require_once 'application/PageBuilder.php'; | ||
162 | require_once 'application/TimeZone.php'; | 166 | require_once 'application/TimeZone.php'; |
163 | require_once 'application/Url.php'; | 167 | require_once 'application/Url.php'; |
164 | require_once 'application/Utils.php'; | 168 | require_once 'application/Utils.php'; |
@@ -483,7 +487,7 @@ if (isset($_POST['login'])) | |||
483 | if (isset($_POST['returnurl'])) { | 487 | if (isset($_POST['returnurl'])) { |
484 | // Prevent loops over login screen. | 488 | // Prevent loops over login screen. |
485 | if (strpos($_POST['returnurl'], 'do=login') === false) { | 489 | if (strpos($_POST['returnurl'], 'do=login') === false) { |
486 | header('Location: '. escape($_POST['returnurl'])); | 490 | header('Location: '. generateLocation($_POST['returnurl'], $_SERVER['HTTP_HOST'])); |
487 | exit; | 491 | exit; |
488 | } | 492 | } |
489 | } | 493 | } |
@@ -492,9 +496,9 @@ if (isset($_POST['login'])) | |||
492 | else | 496 | else |
493 | { | 497 | { |
494 | ban_loginFailed(); | 498 | ban_loginFailed(); |
495 | $redir = ''; | 499 | $redir = '&username='. $_POST['login']; |
496 | if (isset($_GET['post'])) { | 500 | if (isset($_GET['post'])) { |
497 | $redir = '?post=' . urlencode($_GET['post']); | 501 | $redir .= '&post=' . urlencode($_GET['post']); |
498 | foreach (array('description', 'source', 'title') as $param) { | 502 | foreach (array('description', 'source', 'title') as $param) { |
499 | if (!empty($_GET[$param])) { | 503 | if (!empty($_GET[$param])) { |
500 | $redir .= '&' . $param . '=' . urlencode($_GET[$param]); | 504 | $redir .= '&' . $param . '=' . urlencode($_GET[$param]); |
@@ -560,337 +564,12 @@ function tokenOk($token) | |||
560 | } | 564 | } |
561 | 565 | ||
562 | // ------------------------------------------------------------------------------------------ | 566 | // ------------------------------------------------------------------------------------------ |
563 | /* This class is in charge of building the final page. | ||
564 | (This is basically a wrapper around RainTPL which pre-fills some fields.) | ||
565 | p = new pageBuilder; | ||
566 | p.assign('myfield','myvalue'); | ||
567 | p.renderPage('mytemplate'); | ||
568 | |||
569 | */ | ||
570 | class pageBuilder | ||
571 | { | ||
572 | private $tpl; // RainTPL template | ||
573 | |||
574 | function __construct() | ||
575 | { | ||
576 | $this->tpl = false; | ||
577 | } | ||
578 | |||
579 | /** | ||
580 | * Initialize all default tpl tags. | ||
581 | */ | ||
582 | private function initialize() | ||
583 | { | ||
584 | $this->tpl = new RainTPL; | ||
585 | |||
586 | try { | ||
587 | $version = ApplicationUtils::checkUpdate( | ||
588 | shaarli_version, | ||
589 | $GLOBALS['config']['UPDATECHECK_FILENAME'], | ||
590 | $GLOBALS['config']['UPDATECHECK_INTERVAL'], | ||
591 | $GLOBALS['config']['ENABLE_UPDATECHECK'], | ||
592 | isLoggedIn(), | ||
593 | $GLOBALS['config']['UPDATECHECK_BRANCH'] | ||
594 | ); | ||
595 | $this->tpl->assign('newVersion', escape($version)); | ||
596 | $this->tpl->assign('versionError', ''); | ||
597 | |||
598 | } catch (Exception $exc) { | ||
599 | logm($GLOBALS['config']['LOG_FILE'], $_SERVER['REMOTE_ADDR'], $exc->getMessage()); | ||
600 | $this->tpl->assign('newVersion', ''); | ||
601 | $this->tpl->assign('versionError', escape($exc->getMessage())); | ||
602 | } | ||
603 | |||
604 | $this->tpl->assign('feedurl', escape(index_url($_SERVER))); | ||
605 | $searchcrits = ''; // Search criteria | ||
606 | if (!empty($_GET['searchtags'])) { | ||
607 | $searchcrits .= '&searchtags=' . urlencode($_GET['searchtags']); | ||
608 | } | ||
609 | if (!empty($_GET['searchterm'])) { | ||
610 | $searchcrits .= '&searchterm=' . urlencode($_GET['searchterm']); | ||
611 | } | ||
612 | $this->tpl->assign('searchcrits', $searchcrits); | ||
613 | $this->tpl->assign('source', index_url($_SERVER)); | ||
614 | $this->tpl->assign('version', shaarli_version); | ||
615 | $this->tpl->assign('scripturl', index_url($_SERVER)); | ||
616 | $this->tpl->assign('pagetitle', 'Shaarli'); | ||
617 | $this->tpl->assign('privateonly', !empty($_SESSION['privateonly'])); // Show only private links? | ||
618 | if (!empty($GLOBALS['title'])) { | ||
619 | $this->tpl->assign('pagetitle', $GLOBALS['title']); | ||
620 | } | ||
621 | if (!empty($GLOBALS['titleLink'])) { | ||
622 | $this->tpl->assign('titleLink', $GLOBALS['titleLink']); | ||
623 | } | ||
624 | if (!empty($GLOBALS['pagetitle'])) { | ||
625 | $this->tpl->assign('pagetitle', $GLOBALS['pagetitle']); | ||
626 | } | ||
627 | $this->tpl->assign('shaarlititle', empty($GLOBALS['title']) ? 'Shaarli': $GLOBALS['title']); | ||
628 | if (!empty($GLOBALS['plugin_errors'])) { | ||
629 | $this->tpl->assign('plugin_errors', $GLOBALS['plugin_errors']); | ||
630 | } | ||
631 | } | ||
632 | |||
633 | // The following assign() method is basically the same as RainTPL (except that it's lazy) | ||
634 | public function assign($what,$where) | ||
635 | { | ||
636 | if ($this->tpl===false) $this->initialize(); // Lazy initialization | ||
637 | $this->tpl->assign($what,$where); | ||
638 | } | ||
639 | |||
640 | // Render a specific page (using a template). | ||
641 | // e.g. pb.renderPage('picwall') | ||
642 | public function renderPage($page) | ||
643 | { | ||
644 | if ($this->tpl===false) $this->initialize(); // Lazy initialization | ||
645 | $this->tpl->draw($page); | ||
646 | } | ||
647 | |||
648 | /** | ||
649 | * Render a 404 page (uses the template : tpl/404.tpl) | ||
650 | * | ||
651 | * usage : $PAGE->render404('The link was deleted') | ||
652 | * @param string $message A messate to display what is not found | ||
653 | */ | ||
654 | public function render404($message='The page you are trying to reach does not exist or has been deleted.') { | ||
655 | header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); | ||
656 | $this->tpl->assign('error_message', $message); | ||
657 | $this->renderPage('404'); | ||
658 | } | ||
659 | } | ||
660 | |||
661 | // ------------------------------------------------------------------------------------------ | ||
662 | // Output the last N links in RSS 2.0 format. | ||
663 | function showRSS() | ||
664 | { | ||
665 | header('Content-Type: application/rss+xml; charset=utf-8'); | ||
666 | |||
667 | // $usepermalink : If true, use permalink instead of final link. | ||
668 | // User just has to add 'permalink' in URL parameters. e.g. http://mysite.com/shaarli/?do=rss&permalinks | ||
669 | // Also enabled through a config option | ||
670 | $usepermalinks = isset($_GET['permalinks']) || !$GLOBALS['config']['ENABLE_RSS_PERMALINKS']; | ||
671 | |||
672 | // Cache system | ||
673 | $query = $_SERVER["QUERY_STRING"]; | ||
674 | $cache = new CachedPage( | ||
675 | $GLOBALS['config']['PAGECACHE'], | ||
676 | page_url($_SERVER), | ||
677 | startsWith($query,'do=rss') && !isLoggedIn() | ||
678 | ); | ||
679 | $cached = $cache->cachedVersion(); | ||
680 | if (! empty($cached)) { | ||
681 | echo $cached; | ||
682 | exit; | ||
683 | } | ||
684 | |||
685 | // If cached was not found (or not usable), then read the database and build the response: | ||
686 | $LINKSDB = new LinkDB( | ||
687 | $GLOBALS['config']['DATASTORE'], | ||
688 | isLoggedIn(), | ||
689 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], | ||
690 | $GLOBALS['redirector'] | ||
691 | ); | ||
692 | // Read links from database (and filter private links if user it not logged in). | ||
693 | |||
694 | // Optionally filter the results: | ||
695 | $searchtags = !empty($_GET['searchtags']) ? escape($_GET['searchtags']) : ''; | ||
696 | $searchterm = !empty($_GET['searchterm']) ? escape($_GET['searchterm']) : ''; | ||
697 | if (! empty($searchtags) && ! empty($searchterm)) { | ||
698 | $linksToDisplay = $LINKSDB->filter( | ||
699 | LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT, | ||
700 | array($searchtags, $searchterm) | ||
701 | ); | ||
702 | } | ||
703 | elseif ($searchtags) { | ||
704 | $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_TAG, $searchtags); | ||
705 | } | ||
706 | elseif ($searchterm) { | ||
707 | $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_TEXT, $searchterm); | ||
708 | } | ||
709 | else { | ||
710 | $linksToDisplay = $LINKSDB; | ||
711 | } | ||
712 | |||
713 | $nblinksToDisplay = 50; // Number of links to display. | ||
714 | // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. | ||
715 | if (!empty($_GET['nb'])) { | ||
716 | $nblinksToDisplay = $_GET['nb'] == 'all' ? count($linksToDisplay) : max(intval($_GET['nb']), 1); | ||
717 | } | ||
718 | |||
719 | $pageaddr = escape(index_url($_SERVER)); | ||
720 | echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">'; | ||
721 | echo '<channel><title>'.$GLOBALS['title'].'</title><link>'.$pageaddr.'</link>'; | ||
722 | echo '<description>Shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n\n"; | ||
723 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) | ||
724 | { | ||
725 | echo '<!-- PubSubHubbub Discovery -->'; | ||
726 | echo '<link rel="hub" href="'.escape($GLOBALS['config']['PUBSUBHUB_URL']).'" xmlns="http://www.w3.org/2005/Atom" />'; | ||
727 | echo '<link rel="self" href="'.$pageaddr.'?do=rss" xmlns="http://www.w3.org/2005/Atom" />'; | ||
728 | echo '<!-- End Of PubSubHubbub Discovery -->'; | ||
729 | } | ||
730 | $i=0; | ||
731 | $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // No, I can't use array_keys(). | ||
732 | while ($i<$nblinksToDisplay && $i<count($keys)) | ||
733 | { | ||
734 | $link = $linksToDisplay[$keys[$i]]; | ||
735 | $guid = $pageaddr.'?'.smallHash($link['linkdate']); | ||
736 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | ||
737 | $absurl = $link['url']; | ||
738 | if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute | ||
739 | if ($usepermalinks===true) | ||
740 | echo '<item><title>'.$link['title'].'</title><guid isPermaLink="true">'.$guid.'</guid><link>'.$guid.'</link>'; | ||
741 | else | ||
742 | echo '<item><title>'.$link['title'].'</title><guid isPermaLink="false">'.$guid.'</guid><link>'.$absurl.'</link>'; | ||
743 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) { | ||
744 | echo '<pubDate>'.escape($date->format(DateTime::RSS))."</pubDate>\n"; | ||
745 | } | ||
746 | if ($link['tags']!='') // Adding tags to each RSS entry (as mentioned in RSS specification) | ||
747 | { | ||
748 | foreach(explode(' ',$link['tags']) as $tag) { echo '<category domain="'.$pageaddr.'">'.$tag.'</category>'."\n"; } | ||
749 | } | ||
750 | |||
751 | // Add permalink in description | ||
752 | $descriptionlink = '(<a href="'.$guid.'">Permalink</a>)'; | ||
753 | // If user wants permalinks first, put the final link in description | ||
754 | if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)'; | ||
755 | if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; | ||
756 | echo '<description><![CDATA['. | ||
757 | format_description($link['description'], $GLOBALS['redirector']) . | ||
758 | $descriptionlink . ']]></description>' . "\n</item>\n"; | ||
759 | $i++; | ||
760 | } | ||
761 | echo '</channel></rss><!-- Cached version of '.escape(page_url($_SERVER)).' -->'; | ||
762 | |||
763 | $cache->cache(ob_get_contents()); | ||
764 | ob_end_flush(); | ||
765 | exit; | ||
766 | } | ||
767 | |||
768 | // ------------------------------------------------------------------------------------------ | ||
769 | // Output the last N links in ATOM format. | ||
770 | function showATOM() | ||
771 | { | ||
772 | header('Content-Type: application/atom+xml; charset=utf-8'); | ||
773 | |||
774 | // $usepermalink : If true, use permalink instead of final link. | ||
775 | // User just has to add 'permalink' in URL parameters. e.g. http://mysite.com/shaarli/?do=atom&permalinks | ||
776 | $usepermalinks = isset($_GET['permalinks']) || !$GLOBALS['config']['ENABLE_RSS_PERMALINKS']; | ||
777 | |||
778 | // Cache system | ||
779 | $query = $_SERVER["QUERY_STRING"]; | ||
780 | $cache = new CachedPage( | ||
781 | $GLOBALS['config']['PAGECACHE'], | ||
782 | page_url($_SERVER), | ||
783 | startsWith($query,'do=atom') && !isLoggedIn() | ||
784 | ); | ||
785 | $cached = $cache->cachedVersion(); | ||
786 | if (!empty($cached)) { | ||
787 | echo $cached; | ||
788 | exit; | ||
789 | } | ||
790 | |||
791 | // If cached was not found (or not usable), then read the database and build the response: | ||
792 | // Read links from database (and filter private links if used it not logged in). | ||
793 | $LINKSDB = new LinkDB( | ||
794 | $GLOBALS['config']['DATASTORE'], | ||
795 | isLoggedIn(), | ||
796 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], | ||
797 | $GLOBALS['redirector'] | ||
798 | ); | ||
799 | |||
800 | // Optionally filter the results: | ||
801 | $searchtags = !empty($_GET['searchtags']) ? escape($_GET['searchtags']) : ''; | ||
802 | $searchterm = !empty($_GET['searchterm']) ? escape($_GET['searchterm']) : ''; | ||
803 | if (! empty($searchtags) && ! empty($searchterm)) { | ||
804 | $linksToDisplay = $LINKSDB->filter( | ||
805 | LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT, | ||
806 | array($searchtags, $searchterm) | ||
807 | ); | ||
808 | } | ||
809 | elseif ($searchtags) { | ||
810 | $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_TAG, $searchtags); | ||
811 | } | ||
812 | elseif ($searchterm) { | ||
813 | $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_TEXT, $searchterm); | ||
814 | } | ||
815 | else { | ||
816 | $linksToDisplay = $LINKSDB; | ||
817 | } | ||
818 | |||
819 | $nblinksToDisplay = 50; // Number of links to display. | ||
820 | // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. | ||
821 | if (!empty($_GET['nb'])) { | ||
822 | $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max(intval($_GET['nb']), 1); | ||
823 | } | ||
824 | |||
825 | $pageaddr=escape(index_url($_SERVER)); | ||
826 | $latestDate = ''; | ||
827 | $entries=''; | ||
828 | $i=0; | ||
829 | $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // No, I can't use array_keys(). | ||
830 | while ($i<$nblinksToDisplay && $i<count($keys)) | ||
831 | { | ||
832 | $link = $linksToDisplay[$keys[$i]]; | ||
833 | $guid = $pageaddr.'?'.smallHash($link['linkdate']); | ||
834 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | ||
835 | $iso8601date = $date->format(DateTime::ISO8601); | ||
836 | $latestDate = max($latestDate, $iso8601date); | ||
837 | $absurl = $link['url']; | ||
838 | if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute | ||
839 | $entries.='<entry><title>'.$link['title'].'</title>'; | ||
840 | if ($usepermalinks===true) | ||
841 | $entries.='<link href="'.$guid.'" /><id>'.$guid.'</id>'; | ||
842 | else | ||
843 | $entries.='<link href="'.$absurl.'" /><id>'.$guid.'</id>'; | ||
844 | |||
845 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) { | ||
846 | $entries.='<updated>'.escape($iso8601date).'</updated>'; | ||
847 | } | ||
848 | |||
849 | // Add permalink in description | ||
850 | $descriptionlink = '(<a href="'.$guid.'">Permalink</a>)'; | ||
851 | // If user wants permalinks first, put the final link in description | ||
852 | if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)'; | ||
853 | if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; | ||
854 | |||
855 | $entries .= '<content type="html"><![CDATA['. | ||
856 | format_description($link['description'], $GLOBALS['redirector']) . | ||
857 | $descriptionlink . "]]></content>\n"; | ||
858 | if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification) | ||
859 | { | ||
860 | foreach(explode(' ',$link['tags']) as $tag) | ||
861 | { $entries.='<category scheme="'.$pageaddr.'" term="'.$tag.'" />'."\n"; } | ||
862 | } | ||
863 | $entries.="</entry>\n"; | ||
864 | $i++; | ||
865 | } | ||
866 | $feed='<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">'; | ||
867 | $feed.='<title>'.$GLOBALS['title'].'</title>'; | ||
868 | if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.='<updated>'.escape($latestDate).'</updated>'; | ||
869 | $feed.='<link rel="self" href="'.escape(server_url($_SERVER).$_SERVER["REQUEST_URI"]).'" />'; | ||
870 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) | ||
871 | { | ||
872 | $feed.='<!-- PubSubHubbub Discovery -->'; | ||
873 | $feed.='<link rel="hub" href="'.escape($GLOBALS['config']['PUBSUBHUB_URL']).'" />'; | ||
874 | $feed.='<!-- End Of PubSubHubbub Discovery -->'; | ||
875 | } | ||
876 | $feed.='<author><name>'.$pageaddr.'</name><uri>'.$pageaddr.'</uri></author>'; | ||
877 | $feed.='<id>'.$pageaddr.'</id>'."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do. | ||
878 | $feed.=$entries; | ||
879 | $feed.='</feed><!-- Cached version of '.escape(page_url($_SERVER)).' -->'; | ||
880 | echo $feed; | ||
881 | |||
882 | $cache->cache(ob_get_contents()); | ||
883 | ob_end_flush(); | ||
884 | exit; | ||
885 | } | ||
886 | |||
887 | // ------------------------------------------------------------------------------------------ | ||
888 | // Daily RSS feed: 1 RSS entry per day giving all the links on that day. | 567 | // Daily RSS feed: 1 RSS entry per day giving all the links on that day. |
889 | // Gives the last 7 days (which have links). | 568 | // Gives the last 7 days (which have links). |
890 | // This RSS feed cannot be filtered. | 569 | // This RSS feed cannot be filtered. |
891 | function showDailyRSS() { | 570 | function showDailyRSS() { |
892 | // Cache system | 571 | // Cache system |
893 | $query = $_SERVER["QUERY_STRING"]; | 572 | $query = $_SERVER['QUERY_STRING']; |
894 | $cache = new CachedPage( | 573 | $cache = new CachedPage( |
895 | $GLOBALS['config']['PAGECACHE'], | 574 | $GLOBALS['config']['PAGECACHE'], |
896 | page_url($_SERVER), | 575 | page_url($_SERVER), |
@@ -908,7 +587,8 @@ function showDailyRSS() { | |||
908 | $GLOBALS['config']['DATASTORE'], | 587 | $GLOBALS['config']['DATASTORE'], |
909 | isLoggedIn(), | 588 | isLoggedIn(), |
910 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], | 589 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], |
911 | $GLOBALS['redirector'] | 590 | $GLOBALS['redirector'], |
591 | $GLOBALS['config']['REDIRECTOR_URLENCODE'] | ||
912 | ); | 592 | ); |
913 | 593 | ||
914 | /* Some Shaarlies may have very few links, so we need to look | 594 | /* Some Shaarlies may have very few links, so we need to look |
@@ -993,16 +673,10 @@ function showDailyRSS() { | |||
993 | * Show the 'Daily' page. | 673 | * Show the 'Daily' page. |
994 | * | 674 | * |
995 | * @param PageBuilder $pageBuilder Template engine wrapper. | 675 | * @param PageBuilder $pageBuilder Template engine wrapper. |
676 | * @param LinkDB $LINKSDB LinkDB instance. | ||
996 | */ | 677 | */ |
997 | function showDaily($pageBuilder) | 678 | function showDaily($pageBuilder, $LINKSDB) |
998 | { | 679 | { |
999 | $LINKSDB = new LinkDB( | ||
1000 | $GLOBALS['config']['DATASTORE'], | ||
1001 | isLoggedIn(), | ||
1002 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], | ||
1003 | $GLOBALS['redirector'] | ||
1004 | ); | ||
1005 | |||
1006 | $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. | 680 | $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. |
1007 | if (isset($_GET['day'])) $day=$_GET['day']; | 681 | if (isset($_GET['day'])) $day=$_GET['day']; |
1008 | 682 | ||
@@ -1018,7 +692,7 @@ function showDaily($pageBuilder) | |||
1018 | } | 692 | } |
1019 | 693 | ||
1020 | try { | 694 | try { |
1021 | $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_DAY, $day); | 695 | $linksToDisplay = $LINKSDB->filterDay($day); |
1022 | } catch (Exception $exc) { | 696 | } catch (Exception $exc) { |
1023 | error_log($exc); | 697 | error_log($exc); |
1024 | $linksToDisplay = array(); | 698 | $linksToDisplay = array(); |
@@ -1062,7 +736,6 @@ function showDaily($pageBuilder) | |||
1062 | $dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000'); | 736 | $dayDate = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $day.'_000000'); |
1063 | $data = array( | 737 | $data = array( |
1064 | 'linksToDisplay' => $linksToDisplay, | 738 | 'linksToDisplay' => $linksToDisplay, |
1065 | 'linkcount' => count($LINKSDB), | ||
1066 | 'cols' => $columns, | 739 | 'cols' => $columns, |
1067 | 'day' => $dayDate->getTimestamp(), | 740 | 'day' => $dayDate->getTimestamp(), |
1068 | 'previousday' => $previousday, | 741 | 'previousday' => $previousday, |
@@ -1094,7 +767,8 @@ function renderPage() | |||
1094 | $GLOBALS['config']['DATASTORE'], | 767 | $GLOBALS['config']['DATASTORE'], |
1095 | isLoggedIn(), | 768 | isLoggedIn(), |
1096 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], | 769 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], |
1097 | $GLOBALS['redirector'] | 770 | $GLOBALS['redirector'], |
771 | $GLOBALS['config']['REDIRECTOR_URLENCODE'] | ||
1098 | ); | 772 | ); |
1099 | 773 | ||
1100 | $updater = new Updater( | 774 | $updater = new Updater( |
@@ -1116,7 +790,9 @@ function renderPage() | |||
1116 | die($e->getMessage()); | 790 | die($e->getMessage()); |
1117 | } | 791 | } |
1118 | 792 | ||
1119 | $PAGE = new pageBuilder; | 793 | $PAGE = new PageBuilder(); |
794 | $PAGE->assign('linkcount', count($LINKSDB)); | ||
795 | $PAGE->assign('privateLinkcount', count_private($LINKSDB)); | ||
1120 | 796 | ||
1121 | // Determine which page will be rendered. | 797 | // Determine which page will be rendered. |
1122 | $query = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : ''; | 798 | $query = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : ''; |
@@ -1147,12 +823,15 @@ function renderPage() | |||
1147 | if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; } // No need to login for open Shaarli | 823 | if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; } // No need to login for open Shaarli |
1148 | $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful. | 824 | $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful. |
1149 | $PAGE->assign('token',$token); | 825 | $PAGE->assign('token',$token); |
826 | if (isset($_GET['username'])) { | ||
827 | $PAGE->assign('username', escape($_GET['username'])); | ||
828 | } | ||
1150 | $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']):'')); | 829 | $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']):'')); |
1151 | $PAGE->renderPage('loginform'); | 830 | $PAGE->renderPage('loginform'); |
1152 | exit; | 831 | exit; |
1153 | } | 832 | } |
1154 | // -------- User wants to logout. | 833 | // -------- User wants to logout. |
1155 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=logout')) | 834 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) |
1156 | { | 835 | { |
1157 | invalidateCaches($GLOBALS['config']['PAGECACHE']); | 836 | invalidateCaches($GLOBALS['config']['PAGECACHE']); |
1158 | logout(); | 837 | logout(); |
@@ -1164,24 +843,7 @@ function renderPage() | |||
1164 | if ($targetPage == Router::$PAGE_PICWALL) | 843 | if ($targetPage == Router::$PAGE_PICWALL) |
1165 | { | 844 | { |
1166 | // Optionally filter the results: | 845 | // Optionally filter the results: |
1167 | $searchtags = !empty($_GET['searchtags']) ? escape($_GET['searchtags']) : ''; | 846 | $links = $LINKSDB->filterSearch($_GET); |
1168 | $searchterm = !empty($_GET['searchterm']) ? escape($_GET['searchterm']) : ''; | ||
1169 | if (! empty($searchtags) && ! empty($searchterm)) { | ||
1170 | $links = $LINKSDB->filter( | ||
1171 | LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT, | ||
1172 | array($searchtags, $searchterm) | ||
1173 | ); | ||
1174 | } | ||
1175 | elseif ($searchtags) { | ||
1176 | $links = $LINKSDB->filter(LinkFilter::$FILTER_TAG, $searchtags); | ||
1177 | } | ||
1178 | elseif ($searchterm) { | ||
1179 | $links = $LINKSDB->filter(LinkFilter::$FILTER_TEXT, $searchterm); | ||
1180 | } | ||
1181 | else { | ||
1182 | $links = $LINKSDB; | ||
1183 | } | ||
1184 | |||
1185 | $linksToDisplay = array(); | 847 | $linksToDisplay = array(); |
1186 | 848 | ||
1187 | // Get only links which have a thumbnail. | 849 | // Get only links which have a thumbnail. |
@@ -1197,7 +859,6 @@ function renderPage() | |||
1197 | } | 859 | } |
1198 | 860 | ||
1199 | $data = array( | 861 | $data = array( |
1200 | 'linkcount' => count($LINKSDB), | ||
1201 | 'linksToDisplay' => $linksToDisplay, | 862 | 'linksToDisplay' => $linksToDisplay, |
1202 | ); | 863 | ); |
1203 | $pluginManager->executeHooks('render_picwall', $data, array('loggedin' => isLoggedIn())); | 864 | $pluginManager->executeHooks('render_picwall', $data, array('loggedin' => isLoggedIn())); |
@@ -1234,15 +895,19 @@ function renderPage() | |||
1234 | return strcasecmp($a, $b); | 895 | return strcasecmp($a, $b); |
1235 | }); | 896 | }); |
1236 | 897 | ||
1237 | $tagList=array(); | 898 | $tagList = array(); |
1238 | foreach($tags as $key=>$value) | 899 | foreach($tags as $key => $value) { |
1239 | // Tag font size scaling: default 15 and 30 logarithm bases affect scaling, 22 and 6 are arbitrary font sizes for max and min sizes. | 900 | // Tag font size scaling: |
1240 | { | 901 | // default 15 and 30 logarithm bases affect scaling, |
1241 | $tagList[$key] = array('count'=>$value,'size'=>log($value, 15) / log($maxcount, 30) * (22-6) + 6); | 902 | // 22 and 6 are arbitrary font sizes for max and min sizes. |
903 | $size = log($value, 15) / log($maxcount, 30) * 2.2 + 0.8; | ||
904 | $tagList[$key] = array( | ||
905 | 'count' => $value, | ||
906 | 'size' => number_format($size, 2, '.', ''), | ||
907 | ); | ||
1242 | } | 908 | } |
1243 | 909 | ||
1244 | $data = array( | 910 | $data = array( |
1245 | 'linkcount' => count($LINKSDB), | ||
1246 | 'tags' => $tagList, | 911 | 'tags' => $tagList, |
1247 | ); | 912 | ); |
1248 | $pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => isLoggedIn())); | 913 | $pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => isLoggedIn())); |
@@ -1257,7 +922,50 @@ function renderPage() | |||
1257 | 922 | ||
1258 | // Daily page. | 923 | // Daily page. |
1259 | if ($targetPage == Router::$PAGE_DAILY) { | 924 | if ($targetPage == Router::$PAGE_DAILY) { |
1260 | showDaily($PAGE); | 925 | showDaily($PAGE, $LINKSDB); |
926 | } | ||
927 | |||
928 | // ATOM and RSS feed. | ||
929 | if ($targetPage == Router::$PAGE_FEED_ATOM || $targetPage == Router::$PAGE_FEED_RSS) { | ||
930 | $feedType = $targetPage == Router::$PAGE_FEED_RSS ? FeedBuilder::$FEED_RSS : FeedBuilder::$FEED_ATOM; | ||
931 | header('Content-Type: application/'. $feedType .'+xml; charset=utf-8'); | ||
932 | |||
933 | // Cache system | ||
934 | $query = $_SERVER['QUERY_STRING']; | ||
935 | $cache = new CachedPage( | ||
936 | $GLOBALS['config']['PAGECACHE'], | ||
937 | page_url($_SERVER), | ||
938 | startsWith($query,'do='. $targetPage) && !isLoggedIn() | ||
939 | ); | ||
940 | $cached = $cache->cachedVersion(); | ||
941 | if (!empty($cached)) { | ||
942 | echo $cached; | ||
943 | exit; | ||
944 | } | ||
945 | |||
946 | // Generate data. | ||
947 | $feedGenerator = new FeedBuilder($LINKSDB, $feedType, $_SERVER, $_GET, isLoggedIn()); | ||
948 | $feedGenerator->setLocale(strtolower(setlocale(LC_COLLATE, 0))); | ||
949 | $feedGenerator->setHideDates($GLOBALS['config']['HIDE_TIMESTAMPS'] && !isLoggedIn()); | ||
950 | $feedGenerator->setUsePermalinks(isset($_GET['permalinks']) || !$GLOBALS['config']['ENABLE_RSS_PERMALINKS']); | ||
951 | if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) { | ||
952 | $feedGenerator->setPubsubhubUrl($GLOBALS['config']['PUBSUBHUB_URL']); | ||
953 | } | ||
954 | $data = $feedGenerator->buildData(); | ||
955 | |||
956 | // Process plugin hook. | ||
957 | $pluginManager = PluginManager::getInstance(); | ||
958 | $pluginManager->executeHooks('render_feed', $data, array( | ||
959 | 'loggedin' => isLoggedIn(), | ||
960 | 'target' => $targetPage, | ||
961 | )); | ||
962 | |||
963 | // Render the template. | ||
964 | $PAGE->assignAll($data); | ||
965 | $PAGE->renderPage('feed.'. $feedType); | ||
966 | $cache->cache(ob_get_contents()); | ||
967 | ob_end_flush(); | ||
968 | exit; | ||
1261 | } | 969 | } |
1262 | 970 | ||
1263 | // Display openseach plugin (XML) | 971 | // Display openseach plugin (XML) |
@@ -1372,12 +1080,6 @@ function renderPage() | |||
1372 | exit; | 1080 | exit; |
1373 | } | 1081 | } |
1374 | 1082 | ||
1375 | // Same case as above except that user tried to access ?do=addlink without being logged in | ||
1376 | // Note: passing empty parameters makes Shaarli generate default URLs and descriptions. | ||
1377 | if (isset($_GET['do']) && $_GET['do'] === 'addlink') { | ||
1378 | header('Location: ?do=login&post='); | ||
1379 | exit; | ||
1380 | } | ||
1381 | showLinkList($PAGE, $LINKSDB); | 1083 | showLinkList($PAGE, $LINKSDB); |
1382 | if (isset($_GET['edit_link'])) { | 1084 | if (isset($_GET['edit_link'])) { |
1383 | header('Location: ?do=login&edit_link='. escape($_GET['edit_link'])); | 1085 | header('Location: ?do=login&edit_link='. escape($_GET['edit_link'])); |
@@ -1393,7 +1095,6 @@ function renderPage() | |||
1393 | if ($targetPage == Router::$PAGE_TOOLS) | 1095 | if ($targetPage == Router::$PAGE_TOOLS) |
1394 | { | 1096 | { |
1395 | $data = array( | 1097 | $data = array( |
1396 | 'linkcount' => count($LINKSDB), | ||
1397 | 'pageabsaddr' => index_url($_SERVER), | 1098 | 'pageabsaddr' => index_url($_SERVER), |
1398 | ); | 1099 | ); |
1399 | $pluginManager->executeHooks('render_tools', $data); | 1100 | $pluginManager->executeHooks('render_tools', $data); |
@@ -1438,7 +1139,6 @@ function renderPage() | |||
1438 | } | 1139 | } |
1439 | else // show the change password form. | 1140 | else // show the change password form. |
1440 | { | 1141 | { |
1441 | $PAGE->assign('linkcount',count($LINKSDB)); | ||
1442 | $PAGE->assign('token',getToken()); | 1142 | $PAGE->assign('token',getToken()); |
1443 | $PAGE->renderPage('changepassword'); | 1143 | $PAGE->renderPage('changepassword'); |
1444 | exit; | 1144 | exit; |
@@ -1450,11 +1150,15 @@ function renderPage() | |||
1450 | { | 1150 | { |
1451 | if (!empty($_POST['title']) ) | 1151 | if (!empty($_POST['title']) ) |
1452 | { | 1152 | { |
1453 | if (!tokenOk($_POST['token'])) die('Wrong token.'); // Go away! | 1153 | if (!tokenOk($_POST['token'])) { |
1154 | die('Wrong token.'); // Go away! | ||
1155 | } | ||
1454 | $tz = 'UTC'; | 1156 | $tz = 'UTC'; |
1455 | if (!empty($_POST['continent']) && !empty($_POST['city'])) | 1157 | if (!empty($_POST['continent']) && !empty($_POST['city']) |
1456 | if (isTimeZoneValid($_POST['continent'],$_POST['city'])) | 1158 | && isTimeZoneValid($_POST['continent'], $_POST['city']) |
1457 | $tz = $_POST['continent'].'/'.$_POST['city']; | 1159 | ) { |
1160 | $tz = $_POST['continent'] . '/' . $_POST['city']; | ||
1161 | } | ||
1458 | $GLOBALS['timezone'] = $tz; | 1162 | $GLOBALS['timezone'] = $tz; |
1459 | $GLOBALS['title']=$_POST['title']; | 1163 | $GLOBALS['title']=$_POST['title']; |
1460 | $GLOBALS['titleLink']=$_POST['titleLink']; | 1164 | $GLOBALS['titleLink']=$_POST['titleLink']; |
@@ -1482,7 +1186,6 @@ function renderPage() | |||
1482 | } | 1186 | } |
1483 | else // Show the configuration form. | 1187 | else // Show the configuration form. |
1484 | { | 1188 | { |
1485 | $PAGE->assign('linkcount',count($LINKSDB)); | ||
1486 | $PAGE->assign('token',getToken()); | 1189 | $PAGE->assign('token',getToken()); |
1487 | $PAGE->assign('title', empty($GLOBALS['title']) ? '' : $GLOBALS['title'] ); | 1190 | $PAGE->assign('title', empty($GLOBALS['title']) ? '' : $GLOBALS['title'] ); |
1488 | $PAGE->assign('redirector', empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] ); | 1191 | $PAGE->assign('redirector', empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] ); |
@@ -1498,7 +1201,6 @@ function renderPage() | |||
1498 | if ($targetPage == Router::$PAGE_CHANGETAG) | 1201 | if ($targetPage == Router::$PAGE_CHANGETAG) |
1499 | { | 1202 | { |
1500 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { | 1203 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { |
1501 | $PAGE->assign('linkcount', count($LINKSDB)); | ||
1502 | $PAGE->assign('token', getToken()); | 1204 | $PAGE->assign('token', getToken()); |
1503 | $PAGE->assign('tags', $LINKSDB->allTags()); | 1205 | $PAGE->assign('tags', $LINKSDB->allTags()); |
1504 | $PAGE->renderPage('changetag'); | 1206 | $PAGE->renderPage('changetag'); |
@@ -1511,9 +1213,9 @@ function renderPage() | |||
1511 | 1213 | ||
1512 | // Delete a tag: | 1214 | // Delete a tag: |
1513 | if (isset($_POST['deletetag']) && !empty($_POST['fromtag'])) { | 1215 | if (isset($_POST['deletetag']) && !empty($_POST['fromtag'])) { |
1514 | $needle=trim($_POST['fromtag']); | 1216 | $needle = trim($_POST['fromtag']); |
1515 | // True for case-sensitive tag search. | 1217 | // True for case-sensitive tag search. |
1516 | $linksToAlter = $LINKSDB->filter(LinkFilter::$FILTER_TAG, $needle, true); | 1218 | $linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true); |
1517 | foreach($linksToAlter as $key=>$value) | 1219 | foreach($linksToAlter as $key=>$value) |
1518 | { | 1220 | { |
1519 | $tags = explode(' ',trim($value['tags'])); | 1221 | $tags = explode(' ',trim($value['tags'])); |
@@ -1528,9 +1230,9 @@ function renderPage() | |||
1528 | 1230 | ||
1529 | // Rename a tag: | 1231 | // Rename a tag: |
1530 | if (isset($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) { | 1232 | if (isset($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) { |
1531 | $needle=trim($_POST['fromtag']); | 1233 | $needle = trim($_POST['fromtag']); |
1532 | // True for case-sensitive tag search. | 1234 | // True for case-sensitive tag search. |
1533 | $linksToAlter = $LINKSDB->filter(LinkFilter::$FILTER_TAG, $needle, true); | 1235 | $linksToAlter = $LINKSDB->filterSearch(array('searchtags' => $needle), true); |
1534 | foreach($linksToAlter as $key=>$value) | 1236 | foreach($linksToAlter as $key=>$value) |
1535 | { | 1237 | { |
1536 | $tags = explode(' ',trim($value['tags'])); | 1238 | $tags = explode(' ',trim($value['tags'])); |
@@ -1547,7 +1249,6 @@ function renderPage() | |||
1547 | // -------- User wants to add a link without using the bookmarklet: Show form. | 1249 | // -------- User wants to add a link without using the bookmarklet: Show form. |
1548 | if ($targetPage == Router::$PAGE_ADDLINK) | 1250 | if ($targetPage == Router::$PAGE_ADDLINK) |
1549 | { | 1251 | { |
1550 | $PAGE->assign('linkcount',count($LINKSDB)); | ||
1551 | $PAGE->renderPage('addlink'); | 1252 | $PAGE->renderPage('addlink'); |
1552 | exit; | 1253 | exit; |
1553 | } | 1254 | } |
@@ -1673,7 +1374,6 @@ function renderPage() | |||
1673 | $link = $LINKSDB[$_GET['edit_link']]; // Read database | 1374 | $link = $LINKSDB[$_GET['edit_link']]; // Read database |
1674 | if (!$link) { header('Location: ?'); exit; } // Link not found in database. | 1375 | if (!$link) { header('Location: ?'); exit; } // Link not found in database. |
1675 | $data = array( | 1376 | $data = array( |
1676 | 'linkcount' => count($LINKSDB), | ||
1677 | 'link' => $link, | 1377 | 'link' => $link, |
1678 | 'link_is_new' => false, | 1378 | 'link_is_new' => false, |
1679 | 'token' => getToken(), | 1379 | 'token' => getToken(), |
@@ -1692,7 +1392,7 @@ function renderPage() | |||
1692 | 1392 | ||
1693 | // -------- User want to post a new link: Display link edit form. | 1393 | // -------- User want to post a new link: Display link edit form. |
1694 | if (isset($_GET['post'])) { | 1394 | if (isset($_GET['post'])) { |
1695 | $url = cleanup_url(escape($_GET['post'])); | 1395 | $url = cleanup_url($_GET['post']); |
1696 | 1396 | ||
1697 | $link_is_new = false; | 1397 | $link_is_new = false; |
1698 | // Check if URL is not already in database (in this case, we will edit the existing link) | 1398 | // Check if URL is not already in database (in this case, we will edit the existing link) |
@@ -1717,8 +1417,8 @@ function renderPage() | |||
1717 | // Extract title. | 1417 | // Extract title. |
1718 | $title = html_extract_title($content); | 1418 | $title = html_extract_title($content); |
1719 | // Re-encode title in utf-8 if necessary. | 1419 | // Re-encode title in utf-8 if necessary. |
1720 | if (! empty($title) && $charset != 'utf-8') { | 1420 | if (! empty($title) && strtolower($charset) != 'utf-8') { |
1721 | $title = mb_convert_encoding($title, $charset, 'utf-8'); | 1421 | $title = mb_convert_encoding($title, 'utf-8', $charset); |
1722 | } | 1422 | } |
1723 | } | 1423 | } |
1724 | } | 1424 | } |
@@ -1727,6 +1427,8 @@ function renderPage() | |||
1727 | $url = '?' . smallHash($linkdate); | 1427 | $url = '?' . smallHash($linkdate); |
1728 | $title = 'Note: '; | 1428 | $title = 'Note: '; |
1729 | } | 1429 | } |
1430 | $url = escape($url); | ||
1431 | $title = escape($title); | ||
1730 | 1432 | ||
1731 | $link = array( | 1433 | $link = array( |
1732 | 'linkdate' => $linkdate, | 1434 | 'linkdate' => $linkdate, |
@@ -1739,7 +1441,6 @@ function renderPage() | |||
1739 | } | 1441 | } |
1740 | 1442 | ||
1741 | $data = array( | 1443 | $data = array( |
1742 | 'linkcount' => count($LINKSDB), | ||
1743 | 'link' => $link, | 1444 | 'link' => $link, |
1744 | 'link_is_new' => $link_is_new, | 1445 | 'link_is_new' => $link_is_new, |
1745 | 'token' => getToken(), // XSRF protection. | 1446 | 'token' => getToken(), // XSRF protection. |
@@ -1757,49 +1458,52 @@ function renderPage() | |||
1757 | exit; | 1458 | exit; |
1758 | } | 1459 | } |
1759 | 1460 | ||
1760 | // -------- Export as Netscape Bookmarks HTML file. | 1461 | if ($targetPage == Router::$PAGE_EXPORT) { |
1761 | if ($targetPage == Router::$PAGE_EXPORT) | 1462 | // Export links as a Netscape Bookmarks file |
1762 | { | 1463 | |
1763 | if (empty($_GET['what'])) | 1464 | if (empty($_GET['selection'])) { |
1764 | { | ||
1765 | $PAGE->assign('linkcount',count($LINKSDB)); | ||
1766 | $PAGE->renderPage('export'); | 1465 | $PAGE->renderPage('export'); |
1767 | exit; | 1466 | exit; |
1768 | } | 1467 | } |
1769 | $exportWhat=$_GET['what']; | ||
1770 | if (!array_intersect(array('all','public','private'),array($exportWhat))) die('What are you trying to export???'); | ||
1771 | 1468 | ||
1772 | header('Content-Type: text/html; charset=utf-8'); | 1469 | // export as bookmarks_(all|private|public)_YYYYmmdd_HHMMSS.html |
1773 | header('Content-disposition: attachment; filename=bookmarks_'.$exportWhat.'_'.strval(date('Ymd_His')).'.html'); | 1470 | $selection = $_GET['selection']; |
1774 | $currentdate=date('Y/m/d H:i:s'); | 1471 | if (isset($_GET['prepend_note_url'])) { |
1775 | echo <<<HTML | 1472 | $prependNoteUrl = $_GET['prepend_note_url']; |
1776 | <!DOCTYPE NETSCAPE-Bookmark-file-1> | 1473 | } else { |
1777 | <!-- This is an automatically generated file. | 1474 | $prependNoteUrl = false; |
1778 | It will be read and overwritten. | ||
1779 | DO NOT EDIT! --> | ||
1780 | <!-- Shaarli {$exportWhat} bookmarks export on {$currentdate} --> | ||
1781 | <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"> | ||
1782 | <TITLE>Bookmarks</TITLE> | ||
1783 | <H1>Bookmarks</H1> | ||
1784 | HTML; | ||
1785 | foreach($LINKSDB as $link) | ||
1786 | { | ||
1787 | if ($exportWhat=='all' || | ||
1788 | ($exportWhat=='private' && $link['private']!=0) || | ||
1789 | ($exportWhat=='public' && $link['private']==0)) | ||
1790 | { | ||
1791 | $date = DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, $link['linkdate']); | ||
1792 | echo '<DT><A HREF="'.$link['url'].'" ADD_DATE="'.$date->getTimestamp().'" PRIVATE="'.$link['private'].'"'; | ||
1793 | if ($link['tags']!='') echo ' TAGS="'.str_replace(' ',',',$link['tags']).'"'; | ||
1794 | echo '>'.$link['title']."</A>\n"; | ||
1795 | if ($link['description']!='') echo '<DD>'.$link['description']."\n"; | ||
1796 | } | ||
1797 | } | 1475 | } |
1798 | exit; | 1476 | |
1477 | try { | ||
1478 | $PAGE->assign( | ||
1479 | 'links', | ||
1480 | NetscapeBookmarkUtils::filterAndFormat( | ||
1481 | $LINKSDB, | ||
1482 | $selection, | ||
1483 | $prependNoteUrl, | ||
1484 | index_url($_SERVER) | ||
1485 | ) | ||
1486 | ); | ||
1487 | } catch (Exception $exc) { | ||
1488 | header('Content-Type: text/plain; charset=utf-8'); | ||
1489 | echo $exc->getMessage(); | ||
1490 | exit; | ||
1491 | } | ||
1492 | $now = new DateTime(); | ||
1493 | header('Content-Type: text/html; charset=utf-8'); | ||
1494 | header( | ||
1495 | 'Content-disposition: attachment; filename=bookmarks_' | ||
1496 | .$selection.'_'.$now->format(LinkDB::LINK_DATE_FORMAT).'.html' | ||
1497 | ); | ||
1498 | $PAGE->assign('date', $now->format(DateTime::RFC822)); | ||
1499 | $PAGE->assign('eol', PHP_EOL); | ||
1500 | $PAGE->assign('selection', $selection); | ||
1501 | $PAGE->renderPage('export.bookmarks'); | ||
1502 | exit; | ||
1799 | } | 1503 | } |
1800 | 1504 | ||
1801 | // -------- User is uploading a file for import | 1505 | // -------- User is uploading a file for import |
1802 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=upload')) | 1506 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=upload')) |
1803 | { | 1507 | { |
1804 | // If file is too big, some form field may be missing. | 1508 | // If file is too big, some form field may be missing. |
1805 | if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0)) | 1509 | if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0)) |
@@ -1809,14 +1513,13 @@ HTML; | |||
1809 | exit; | 1513 | exit; |
1810 | } | 1514 | } |
1811 | if (!tokenOk($_POST['token'])) die('Wrong token.'); | 1515 | if (!tokenOk($_POST['token'])) die('Wrong token.'); |
1812 | importFile(); | 1516 | importFile($LINKSDB); |
1813 | exit; | 1517 | exit; |
1814 | } | 1518 | } |
1815 | 1519 | ||
1816 | // -------- Show upload/import dialog: | 1520 | // -------- Show upload/import dialog: |
1817 | if ($targetPage == Router::$PAGE_IMPORT) | 1521 | if ($targetPage == Router::$PAGE_IMPORT) |
1818 | { | 1522 | { |
1819 | $PAGE->assign('linkcount',count($LINKSDB)); | ||
1820 | $PAGE->assign('token',getToken()); | 1523 | $PAGE->assign('token',getToken()); |
1821 | $PAGE->assign('maxfilesize',getMaxFileSize()); | 1524 | $PAGE->assign('maxfilesize',getMaxFileSize()); |
1822 | $PAGE->renderPage('import'); | 1525 | $PAGE->renderPage('import'); |
@@ -1878,15 +1581,10 @@ HTML; | |||
1878 | 1581 | ||
1879 | // ----------------------------------------------------------------------------------------------- | 1582 | // ----------------------------------------------------------------------------------------------- |
1880 | // Process the import file form. | 1583 | // Process the import file form. |
1881 | function importFile() | 1584 | function importFile($LINKSDB) |
1882 | { | 1585 | { |
1883 | if (!isLoggedIn()) { die('Not allowed.'); } | 1586 | if (!isLoggedIn()) { die('Not allowed.'); } |
1884 | $LINKSDB = new LinkDB( | 1587 | |
1885 | $GLOBALS['config']['DATASTORE'], | ||
1886 | isLoggedIn(), | ||
1887 | $GLOBALS['config']['HIDE_PUBLIC_LINKS'], | ||
1888 | $GLOBALS['redirector'] | ||
1889 | ); | ||
1890 | $filename=$_FILES['filetoupload']['name']; | 1588 | $filename=$_FILES['filetoupload']['name']; |
1891 | $filesize=$_FILES['filetoupload']['size']; | 1589 | $filesize=$_FILES['filetoupload']['size']; |
1892 | $data=file_get_contents($_FILES['filetoupload']['tmp_name']); | 1590 | $data=file_get_contents($_FILES['filetoupload']['tmp_name']); |
@@ -1907,7 +1605,7 @@ function importFile() | |||
1907 | { | 1605 | { |
1908 | $link = array('linkdate'=>'','title'=>'','url'=>'','description'=>'','tags'=>'','private'=>0); | 1606 | $link = array('linkdate'=>'','title'=>'','url'=>'','description'=>'','tags'=>'','private'=>0); |
1909 | $d = explode('<DD>',$html); | 1607 | $d = explode('<DD>',$html); |
1910 | if (startswith($d[0],'<A ')) | 1608 | if (startsWith($d[0], '<A ')) |
1911 | { | 1609 | { |
1912 | $link['description'] = (isset($d[1]) ? html_entity_decode(trim($d[1]),ENT_QUOTES,'UTF-8') : ''); // Get description (optional) | 1610 | $link['description'] = (isset($d[1]) ? html_entity_decode(trim($d[1]),ENT_QUOTES,'UTF-8') : ''); // Get description (optional) |
1913 | preg_match('!<A .*?>(.*?)</A>!i',$d[0],$matches); $link['title'] = (isset($matches[1]) ? trim($matches[1]) : ''); // Get title | 1611 | preg_match('!<A .*?>(.*?)</A>!i',$d[0],$matches); $link['title'] = (isset($matches[1]) ? trim($matches[1]) : ''); // Get title |
@@ -1966,60 +1664,32 @@ function importFile() | |||
1966 | } | 1664 | } |
1967 | } | 1665 | } |
1968 | 1666 | ||
1969 | // ----------------------------------------------------------------------------------------------- | 1667 | /** |
1970 | // Template for the list of links (<div id="linklist">) | 1668 | * Template for the list of links (<div id="linklist">) |
1971 | // This function fills all the necessary fields in the $PAGE for the template 'linklist.html' | 1669 | * This function fills all the necessary fields in the $PAGE for the template 'linklist.html' |
1670 | * | ||
1671 | * @param pageBuilder $PAGE pageBuilder instance. | ||
1672 | * @param LinkDB $LINKSDB LinkDB instance. | ||
1673 | */ | ||
1972 | function buildLinkList($PAGE,$LINKSDB) | 1674 | function buildLinkList($PAGE,$LINKSDB) |
1973 | { | 1675 | { |
1974 | // Filter link database according to parameters. | 1676 | // Used in templates |
1975 | $searchtags = !empty($_GET['searchtags']) ? escape($_GET['searchtags']) : ''; | 1677 | $searchtags = !empty($_GET['searchtags']) ? escape($_GET['searchtags']) : ''; |
1976 | $searchterm = !empty($_GET['searchterm']) ? escape(trim($_GET['searchterm'])) : ''; | 1678 | $searchterm = !empty($_GET['searchterm']) ? escape($_GET['searchterm']) : ''; |
1977 | $privateonly = !empty($_SESSION['privateonly']) ? true : false; | ||
1978 | |||
1979 | // Search tags + fullsearch. | ||
1980 | if (! empty($searchtags) && ! empty($searchterm)) { | ||
1981 | $linksToDisplay = $LINKSDB->filter( | ||
1982 | LinkFilter::$FILTER_TAG | LinkFilter::$FILTER_TEXT, | ||
1983 | array($searchtags, $searchterm), | ||
1984 | false, | ||
1985 | $privateonly | ||
1986 | ); | ||
1987 | } | ||
1988 | // Search by tags. | ||
1989 | elseif (! empty($searchtags)) { | ||
1990 | $linksToDisplay = $LINKSDB->filter( | ||
1991 | LinkFilter::$FILTER_TAG, | ||
1992 | $searchtags, | ||
1993 | false, | ||
1994 | $privateonly | ||
1995 | ); | ||
1996 | } | ||
1997 | // Fulltext search. | ||
1998 | elseif (! empty($searchterm)) { | ||
1999 | $linksToDisplay = $LINKSDB->filter( | ||
2000 | LinkFilter::$FILTER_TEXT, | ||
2001 | $searchterm, | ||
2002 | false, | ||
2003 | $privateonly | ||
2004 | ); | ||
2005 | } | ||
2006 | // Detect smallHashes in URL. | ||
2007 | elseif (! empty($_SERVER['QUERY_STRING']) | ||
2008 | && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/', $_SERVER['QUERY_STRING']) | ||
2009 | ) { | ||
2010 | $linksToDisplay = $LINKSDB->filter( | ||
2011 | LinkFilter::$FILTER_HASH, | ||
2012 | substr(trim($_SERVER["QUERY_STRING"], '/'), 0, 6) | ||
2013 | ); | ||
2014 | 1679 | ||
2015 | if (count($linksToDisplay) == 0) { | 1680 | // Smallhash filter |
2016 | $PAGE->render404('The link you are trying to reach does not exist or has been deleted.'); | 1681 | if (! empty($_SERVER['QUERY_STRING']) |
1682 | && preg_match('/^[a-zA-Z0-9-_@]{6}($|&|#)/', $_SERVER['QUERY_STRING'])) { | ||
1683 | try { | ||
1684 | $linksToDisplay = $LINKSDB->filterHash($_SERVER['QUERY_STRING']); | ||
1685 | } catch (LinkNotFoundException $e) { | ||
1686 | $PAGE->render404($e->getMessage()); | ||
2017 | exit; | 1687 | exit; |
2018 | } | 1688 | } |
2019 | } | 1689 | } else { |
2020 | // Otherwise, display without filtering. | 1690 | // Filter links according search parameters. |
2021 | else { | 1691 | $privateonly = !empty($_SESSION['privateonly']); |
2022 | $linksToDisplay = $LINKSDB->filter('', '', false, $privateonly); | 1692 | $linksToDisplay = $LINKSDB->filterSearch($_GET, false, $privateonly); |
2023 | } | 1693 | } |
2024 | 1694 | ||
2025 | // ---- Handle paging. | 1695 | // ---- Handle paging. |
@@ -2081,7 +1751,6 @@ function buildLinkList($PAGE,$LINKSDB) | |||
2081 | 1751 | ||
2082 | // Fill all template fields. | 1752 | // Fill all template fields. |
2083 | $data = array( | 1753 | $data = array( |
2084 | 'linkcount' => count($LINKSDB), | ||
2085 | 'previous_page_url' => $previous_page_url, | 1754 | 'previous_page_url' => $previous_page_url, |
2086 | 'next_page_url' => $next_page_url, | 1755 | 'next_page_url' => $next_page_url, |
2087 | 'page_current' => $page, | 1756 | 'page_current' => $page, |
@@ -2320,10 +1989,10 @@ function install() | |||
2320 | if (!empty($_POST['setlogin']) && !empty($_POST['setpassword'])) | 1989 | if (!empty($_POST['setlogin']) && !empty($_POST['setpassword'])) |
2321 | { | 1990 | { |
2322 | $tz = 'UTC'; | 1991 | $tz = 'UTC'; |
2323 | if (!empty($_POST['continent']) && !empty($_POST['city'])) { | 1992 | if (!empty($_POST['continent']) && !empty($_POST['city']) |
2324 | if (isTimeZoneValid($_POST['continent'], $_POST['city'])) { | 1993 | && isTimeZoneValid($_POST['continent'], $_POST['city']) |
2325 | $tz = $_POST['continent'].'/'.$_POST['city']; | 1994 | ) { |
2326 | } | 1995 | $tz = $_POST['continent'].'/'.$_POST['city']; |
2327 | } | 1996 | } |
2328 | $GLOBALS['timezone'] = $tz; | 1997 | $GLOBALS['timezone'] = $tz; |
2329 | // Everything is ok, let's create config file. | 1998 | // Everything is ok, let's create config file. |
@@ -2356,7 +2025,7 @@ function install() | |||
2356 | $timezone_html = '<tr><td><b>Timezone:</b></td><td>'.$timezone_form.'</td></tr>'; | 2025 | $timezone_html = '<tr><td><b>Timezone:</b></td><td>'.$timezone_form.'</td></tr>'; |
2357 | } | 2026 | } |
2358 | 2027 | ||
2359 | $PAGE = new pageBuilder; | 2028 | $PAGE = new PageBuilder(); |
2360 | $PAGE->assign('timezone_html',$timezone_html); | 2029 | $PAGE->assign('timezone_html',$timezone_html); |
2361 | $PAGE->assign('timezone_js',$timezone_js); | 2030 | $PAGE->assign('timezone_js',$timezone_js); |
2362 | $PAGE->renderPage('install'); | 2031 | $PAGE->renderPage('install'); |
@@ -2406,7 +2075,7 @@ function genThumbnail() | |||
2406 | 2075 | ||
2407 | // Is this a link to an image, or to a flickr page ? | 2076 | // Is this a link to an image, or to a flickr page ? |
2408 | $imageurl=''; | 2077 | $imageurl=''; |
2409 | if (endswith(parse_url($url,PHP_URL_PATH),'.jpg')) | 2078 | if (endsWith(parse_url($url, PHP_URL_PATH), '.jpg')) |
2410 | { // This is a direct link to an image. e.g. http://farm1.staticflickr.com/5/5921913_ac83ed27bd_o.jpg | 2079 | { // This is a direct link to an image. e.g. http://farm1.staticflickr.com/5/5921913_ac83ed27bd_o.jpg |
2411 | preg_match('!(http://farm\d+\.staticflickr\.com/\d+/\d+_\w+_)\w.jpg!',$url,$matches); | 2080 | preg_match('!(http://farm\d+\.staticflickr\.com/\d+/\d+_\w+_)\w.jpg!',$url,$matches); |
2412 | if (!empty($matches[1])) $imageurl=$matches[1].'m.jpg'; | 2081 | if (!empty($matches[1])) $imageurl=$matches[1].'m.jpg'; |
@@ -2583,10 +2252,8 @@ function resizeImage($filepath) | |||
2583 | return true; | 2252 | return true; |
2584 | } | 2253 | } |
2585 | 2254 | ||
2586 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=genthumbnail')) { genThumbnail(); exit; } // Thumbnail generation/cache does not need the link database. | 2255 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=genthumbnail')) { genThumbnail(); exit; } // Thumbnail generation/cache does not need the link database. |
2587 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; } | 2256 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=dailyrss')) { showDailyRSS(); exit; } |
2588 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; } | ||
2589 | if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=dailyrss')) { showDailyRSS(); exit; } | ||
2590 | if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=$GLOBALS['config']['LINKS_PER_PAGE']; | 2257 | if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=$GLOBALS['config']['LINKS_PER_PAGE']; |
2591 | renderPage(); | 2258 | renderPage(); |
2592 | ?> | 2259 | ?> |