aboutsummaryrefslogtreecommitdiffhomepage
path: root/index.php
diff options
context:
space:
mode:
Diffstat (limited to 'index.php')
-rw-r--r--index.php165
1 files changed, 90 insertions, 75 deletions
diff --git a/index.php b/index.php
index f116a87b..dd3ec3a4 100644
--- a/index.php
+++ b/index.php
@@ -98,7 +98,7 @@ header("Pragma: no-cache");
98if (!is_writable(realpath(dirname(__FILE__)))) die('<pre>ERROR: Shaarli does not have the right to write in its own directory.</pre>'); 98if (!is_writable(realpath(dirname(__FILE__)))) die('<pre>ERROR: Shaarli does not have the right to write in its own directory.</pre>');
99 99
100// Handling of old config file which do not have the new parameters. 100// Handling of old config file which do not have the new parameters.
101if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.htmlspecialchars(indexUrl()); 101if (empty($GLOBALS['title'])) $GLOBALS['title']='Shared links on '.escape(indexUrl());
102if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get(); 102if (empty($GLOBALS['timezone'])) $GLOBALS['timezone']=date_default_timezone_get();
103if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']=''; 103if (empty($GLOBALS['redirector'])) $GLOBALS['redirector']='';
104if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false; 104if (empty($GLOBALS['disablesessionprotection'])) $GLOBALS['disablesessionprotection']=false;
@@ -111,6 +111,9 @@ if (empty($GLOBALS['titleLink'])) $GLOBALS['titleLink']='?';
111if (!is_file($GLOBALS['config']['CONFIG_FILE'])) install(); 111if (!is_file($GLOBALS['config']['CONFIG_FILE'])) install();
112 112
113require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS. 113require $GLOBALS['config']['CONFIG_FILE']; // Read login/password hash into $GLOBALS.
114$GLOBALS['title'] = !empty($GLOBALS['title']) ? escape($GLOBALS['title']) : '';
115$GLOBALS['titleLink'] = !empty($GLOBALS['titleLink']) ? escape($GLOBALS['titleLink']) : '';
116$GLOBALS['redirector'] = !empty($GLOBALS['redirector']) ? escape($GLOBALS['redirector']) : '';
114 117
115// a token depending of deployment salt, user password, and the current ip 118// a token depending of deployment salt, user password, and the current ip
116define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GLOBALS['salt'])); 119define('STAY_SIGNED_IN_TOKEN', sha1($GLOBALS['hash'].$_SERVER["REMOTE_ADDR"].$GLOBALS['salt']));
@@ -272,6 +275,17 @@ function nl2br_escaped($html)
272 return str_replace('>','&gt;',str_replace('<','&lt;',nl2br($html))); 275 return str_replace('>','&gt;',str_replace('<','&lt;',nl2br($html)));
273} 276}
274 277
278function escape($str) {
279 return htmlspecialchars($str, ENT_COMPAT, 'UTF-8', false);
280}
281
282function sanitizeLink(&$link) {
283 $link['url'] = escape($link['url']); // useful?
284 $link['title'] = escape($link['title']);
285 $link['description'] = escape($link['description']);
286 $link['tags'] = escape($link['tags']);
287}
288
275// In a string, converts URLs to clickable links. 289// In a string, converts URLs to clickable links.
276// Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 290// Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722
277function text2clickable($url) 291function text2clickable($url)
@@ -651,8 +665,8 @@ class pageBuilder
651 private function initialize() 665 private function initialize()
652 { 666 {
653 $this->tpl = new RainTPL; 667 $this->tpl = new RainTPL;
654 $this->tpl->assign('newversion',checkUpdate()); 668 $this->tpl->assign('newversion',escape(checkUpdate()));
655 $this->tpl->assign('feedurl',htmlspecialchars(indexUrl())); 669 $this->tpl->assign('feedurl',escape(indexUrl()));
656 $searchcrits=''; // Search criteria 670 $searchcrits=''; // Search criteria
657 if (!empty($_GET['searchtags'])) $searchcrits.='&searchtags='.urlencode($_GET['searchtags']); 671 if (!empty($_GET['searchtags'])) $searchcrits.='&searchtags='.urlencode($_GET['searchtags']);
658 elseif (!empty($_GET['searchterm'])) $searchcrits.='&searchterm='.urlencode($_GET['searchterm']); 672 elseif (!empty($_GET['searchterm'])) $searchcrits.='&searchterm='.urlencode($_GET['searchterm']);
@@ -720,15 +734,15 @@ function showRSS()
720 $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; 734 $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
721 } 735 }
722 736
723 $pageaddr=htmlspecialchars(indexUrl()); 737 $pageaddr=escape(indexUrl());
724 echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">'; 738 echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">';
725 echo '<channel><title>'.htmlspecialchars($GLOBALS['title']).'</title><link>'.$pageaddr.'</link>'; 739 echo '<channel><title>'.$GLOBALS['title'].'</title><link>'.$pageaddr.'</link>';
726 echo '<description>Shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n\n"; 740 echo '<description>Shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n\n";
727 if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) 741 if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
728 { 742 {
729 echo '<!-- PubSubHubbub Discovery -->'; 743 echo '<!-- PubSubHubbub Discovery -->';
730 echo '<link rel="hub" href="'.htmlspecialchars($GLOBALS['config']['PUBSUBHUB_URL']).'" xmlns="http://www.w3.org/2005/Atom" />'; 744 echo '<link rel="hub" href="'.escape($GLOBALS['config']['PUBSUBHUB_URL']).'" xmlns="http://www.w3.org/2005/Atom" />';
731 echo '<link rel="self" href="'.htmlspecialchars($pageaddr).'?do=rss" xmlns="http://www.w3.org/2005/Atom" />'; 745 echo '<link rel="self" href="'.$pageaddr.'?do=rss" xmlns="http://www.w3.org/2005/Atom" />';
732 echo '<!-- End Of PubSubHubbub Discovery -->'; 746 echo '<!-- End Of PubSubHubbub Discovery -->';
733 } 747 }
734 $i=0; 748 $i=0;
@@ -738,16 +752,16 @@ function showRSS()
738 $link = $linksToDisplay[$keys[$i]]; 752 $link = $linksToDisplay[$keys[$i]];
739 $guid = $pageaddr.'?'.smallHash($link['linkdate']); 753 $guid = $pageaddr.'?'.smallHash($link['linkdate']);
740 $rfc822date = linkdate2rfc822($link['linkdate']); 754 $rfc822date = linkdate2rfc822($link['linkdate']);
741 $absurl = htmlspecialchars($link['url']); 755 $absurl = $link['url'];
742 if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute 756 if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute
743 if ($usepermalinks===true) 757 if ($usepermalinks===true)
744 echo '<item><title>'.htmlspecialchars($link['title']).'</title><guid isPermaLink="true">'.$guid.'</guid><link>'.$guid.'</link>'; 758 echo '<item><title>'.$link['title'].'</title><guid isPermaLink="true">'.$guid.'</guid><link>'.$guid.'</link>';
745 else 759 else
746 echo '<item><title>'.htmlspecialchars($link['title']).'</title><guid isPermaLink="false">'.$guid.'</guid><link>'.$absurl.'</link>'; 760 echo '<item><title>'.$link['title'].'</title><guid isPermaLink="false">'.$guid.'</guid><link>'.$absurl.'</link>';
747 if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo '<pubDate>'.htmlspecialchars($rfc822date)."</pubDate>\n"; 761 if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo '<pubDate>'.escape($rfc822date)."</pubDate>\n";
748 if ($link['tags']!='') // Adding tags to each RSS entry (as mentioned in RSS specification) 762 if ($link['tags']!='') // Adding tags to each RSS entry (as mentioned in RSS specification)
749 { 763 {
750 foreach(explode(' ',$link['tags']) as $tag) { echo '<category domain="'.htmlspecialchars($pageaddr).'">'.htmlspecialchars($tag).'</category>'."\n"; } 764 foreach(explode(' ',$link['tags']) as $tag) { echo '<category domain="'.$pageaddr.'">'.$tag.'</category>'."\n"; }
751 } 765 }
752 766
753 // Add permalink in description 767 // Add permalink in description
@@ -755,10 +769,10 @@ function showRSS()
755 // If user wants permalinks first, put the final link in description 769 // If user wants permalinks first, put the final link in description
756 if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)'; 770 if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)';
757 if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink; 771 if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink;
758 echo '<description><![CDATA['.nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))).$descriptionlink.']]></description>'."\n</item>\n"; 772 echo '<description><![CDATA['.nl2br(keepMultipleSpaces(text2clickable($link['description']))).$descriptionlink.']]></description>'."\n</item>\n";
759 $i++; 773 $i++;
760 } 774 }
761 echo '</channel></rss><!-- Cached version of '.htmlspecialchars(pageUrl()).' -->'; 775 echo '</channel></rss><!-- Cached version of '.escape(pageUrl()).' -->';
762 776
763 $cache->cache(ob_get_contents()); 777 $cache->cache(ob_get_contents());
764 ob_end_flush(); 778 ob_end_flush();
@@ -781,6 +795,7 @@ function showATOM()
781 $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; } 795 $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; }
782 // If cached was not found (or not usable), then read the database and build the response: 796 // If cached was not found (or not usable), then read the database and build the response:
783 797
798// Read links from database (and filter private links if used it not logged in).
784 $LINKSDB = new LinkDB( 799 $LINKSDB = new LinkDB(
785 isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'], 800 isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'],
786 $GLOBALS['config']['HIDE_PUBLIC_LINKS'] 801 $GLOBALS['config']['HIDE_PUBLIC_LINKS']
@@ -798,7 +813,7 @@ function showATOM()
798 $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; 813 $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
799 } 814 }
800 815
801 $pageaddr=htmlspecialchars(indexUrl()); 816 $pageaddr=escape(indexUrl());
802 $latestDate = ''; 817 $latestDate = '';
803 $entries=''; 818 $entries='';
804 $i=0; 819 $i=0;
@@ -809,44 +824,44 @@ function showATOM()
809 $guid = $pageaddr.'?'.smallHash($link['linkdate']); 824 $guid = $pageaddr.'?'.smallHash($link['linkdate']);
810 $iso8601date = linkdate2iso8601($link['linkdate']); 825 $iso8601date = linkdate2iso8601($link['linkdate']);
811 $latestDate = max($latestDate,$iso8601date); 826 $latestDate = max($latestDate,$iso8601date);
812 $absurl = htmlspecialchars($link['url']); 827 $absurl = $link['url'];
813 if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute 828 if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute
814 $entries.='<entry><title>'.htmlspecialchars($link['title']).'</title>'; 829 $entries.='<entry><title>'.$link['title'].'</title>';
815 if ($usepermalinks===true) 830 if ($usepermalinks===true)
816 $entries.='<link href="'.$guid.'" /><id>'.$guid.'</id>'; 831 $entries.='<link href="'.$guid.'" /><id>'.$guid.'</id>';
817 else 832 else
818 $entries.='<link href="'.$absurl.'" /><id>'.$guid.'</id>'; 833 $entries.='<link href="'.$absurl.'" /><id>'.$guid.'</id>';
819 if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $entries.='<updated>'.htmlspecialchars($iso8601date).'</updated>'; 834 if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $entries.='<updated>'.escape($iso8601date).'</updated>';
820 835
821 // Add permalink in description 836 // Add permalink in description
822 $descriptionlink = htmlspecialchars('(<a href="'.$guid.'">Permalink</a>)'); 837 $descriptionlink = '(<a href="'.$guid.'">Permalink</a>)';
823 // If user wants permalinks first, put the final link in description 838 // If user wants permalinks first, put the final link in description
824 if ($usepermalinks===true) $descriptionlink = htmlspecialchars('(<a href="'.$absurl.'">Link</a>)'); 839 if ($usepermalinks===true) $descriptionlink = '(<a href="'.$absurl.'">Link</a>)';
825 if (strlen($link['description'])>0) $descriptionlink = '&lt;br&gt;'.$descriptionlink; 840 if (strlen($link['description'])>0) $descriptionlink = '<br>'.$descriptionlink;
826 841
827 $entries.='<content type="html">'.htmlspecialchars(nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))))).$descriptionlink."</content>\n"; 842 $entries.='<content type="html"><![CDATA['.nl2br(keepMultipleSpaces(text2clickable($link['description']))).$descriptionlink."]]></content>\n";
828 if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification) 843 if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification)
829 { 844 {
830 foreach(explode(' ',$link['tags']) as $tag) 845 foreach(explode(' ',$link['tags']) as $tag)
831 { $entries.='<category scheme="'.htmlspecialchars($pageaddr,ENT_QUOTES).'" term="'.htmlspecialchars($tag,ENT_QUOTES).'" />'."\n"; } 846 { $entries.='<category scheme="'.$pageaddr.'" term="'.$tag.'" />'."\n"; }
832 } 847 }
833 $entries.="</entry>\n"; 848 $entries.="</entry>\n";
834 $i++; 849 $i++;
835 } 850 }
836 $feed='<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">'; 851 $feed='<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom">';
837 $feed.='<title>'.htmlspecialchars($GLOBALS['title']).'</title>'; 852 $feed.='<title>'.$GLOBALS['title'].'</title>';
838 if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.='<updated>'.htmlspecialchars($latestDate).'</updated>'; 853 if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.='<updated>'.escape($latestDate).'</updated>';
839 $feed.='<link rel="self" href="'.htmlspecialchars(serverUrl().$_SERVER["REQUEST_URI"]).'" />'; 854 $feed.='<link rel="self" href="'.escape(serverUrl().$_SERVER["REQUEST_URI"]).'" />';
840 if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) 855 if (!empty($GLOBALS['config']['PUBSUBHUB_URL']))
841 { 856 {
842 $feed.='<!-- PubSubHubbub Discovery -->'; 857 $feed.='<!-- PubSubHubbub Discovery -->';
843 $feed.='<link rel="hub" href="'.htmlspecialchars($GLOBALS['config']['PUBSUBHUB_URL']).'" />'; 858 $feed.='<link rel="hub" href="'.escape($GLOBALS['config']['PUBSUBHUB_URL']).'" />';
844 $feed.='<!-- End Of PubSubHubbub Discovery -->'; 859 $feed.='<!-- End Of PubSubHubbub Discovery -->';
845 } 860 }
846 $feed.='<author><name>'.htmlspecialchars($pageaddr).'</name><uri>'.htmlspecialchars($pageaddr).'</uri></author>'; 861 $feed.='<author><name>'.$pageaddr.'</name><uri>'.$pageaddr.'</uri></author>';
847 $feed.='<id>'.htmlspecialchars($pageaddr).'</id>'."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do. 862 $feed.='<id>'.$pageaddr.'</id>'."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do.
848 $feed.=$entries; 863 $feed.=$entries;
849 $feed.='</feed><!-- Cached version of '.htmlspecialchars(pageUrl()).' -->'; 864 $feed.='</feed><!-- Cached version of '.escape(pageUrl()).' -->';
850 echo $feed; 865 echo $feed;
851 866
852 $cache->cache(ob_get_contents()); 867 $cache->cache(ob_get_contents());
@@ -866,6 +881,7 @@ function showDailyRSS()
866 $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; } 881 $cached = $cache->cachedVersion(); if (!empty($cached)) { echo $cached; exit; }
867 // If cached was not found (or not usable), then read the database and build the response: 882 // If cached was not found (or not usable), then read the database and build the response:
868 883
884// Read links from database (and filter private links if used it not logged in).
869 $LINKSDB = new LinkDB( 885 $LINKSDB = new LinkDB(
870 isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'], 886 isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI'],
871 $GLOBALS['config']['HIDE_PUBLIC_LINKS'] 887 $GLOBALS['config']['HIDE_PUBLIC_LINKS']
@@ -892,18 +908,18 @@ function showDailyRSS()
892 908
893 // Build the RSS feed. 909 // Build the RSS feed.
894 header('Content-Type: application/rss+xml; charset=utf-8'); 910 header('Content-Type: application/rss+xml; charset=utf-8');
895 $pageaddr=htmlspecialchars(indexUrl()); 911 $pageaddr=escape(indexUrl());
896 echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">'; 912 echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">';
897 echo '<channel><title>Daily - '.htmlspecialchars($GLOBALS['title']).'</title><link>'.$pageaddr.'</link>'; 913 echo '<channel><title>Daily - '.$GLOBALS['title'].'</title><link>'.$pageaddr.'</link>';
898 echo '<description>Daily shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n"; 914 echo '<description>Daily shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n";
899 915
900 foreach($days as $day=>$linkdates) // For each day. 916 foreach($days as $day=>$linkdates) // For each day.
901 { 917 {
902 $daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date 918 $daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date
903 $rfc822date = linkdate2rfc822($day.'_000000'); 919 $rfc822date = linkdate2rfc822($day.'_000000');
904 $absurl=htmlspecialchars(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page. 920 $absurl=escape(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page.
905 echo '<item><title>'.htmlspecialchars($GLOBALS['title'].' - '.$daydate).'</title><guid>'.$absurl.'</guid><link>'.$absurl.'</link>'; 921 echo '<item><title>'.$GLOBALS['title'].' - '.$daydate.'</title><guid>'.$absurl.'</guid><link>'.$absurl.'</link>';
906 echo '<pubDate>'.htmlspecialchars($rfc822date)."</pubDate>"; 922 echo '<pubDate>'.escape($rfc822date)."</pubDate>";
907 923
908 // Build the HTML body of this RSS entry. 924 // Build the HTML body of this RSS entry.
909 $html=''; 925 $html='';
@@ -913,7 +929,7 @@ function showDailyRSS()
913 foreach($linkdates as $linkdate) 929 foreach($linkdates as $linkdate)
914 { 930 {
915 $l = $LINKSDB[$linkdate]; 931 $l = $LINKSDB[$linkdate];
916 $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($l['description'])))); 932 $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable($l['description'])));
917 $l['thumbnail'] = thumbnail($l['url']); 933 $l['thumbnail'] = thumbnail($l['url']);
918 $l['timestamp'] = linkdate2timestamp($l['linkdate']); 934 $l['timestamp'] = linkdate2timestamp($l['linkdate']);
919 if (startsWith($l['url'],'?')) $l['url']=indexUrl().$l['url']; // make permalink URL absolute 935 if (startsWith($l['url'],'?')) $l['url']=indexUrl().$l['url']; // make permalink URL absolute
@@ -927,7 +943,7 @@ function showDailyRSS()
927 echo '<description><![CDATA['.$html.']]></description>'."\n</item>\n\n"; 943 echo '<description><![CDATA['.$html.']]></description>'."\n</item>\n\n";
928 944
929 } 945 }
930 echo '</channel></rss><!-- Cached version of '.htmlspecialchars(pageUrl()).' -->'; 946 echo '</channel></rss><!-- Cached version of '.escape(pageUrl()).' -->';
931 947
932 $cache->cache(ob_get_contents()); 948 $cache->cache(ob_get_contents());
933 ob_end_flush(); 949 ob_end_flush();
@@ -960,10 +976,11 @@ function showDaily()
960 // We pre-format some fields for proper output. 976 // We pre-format some fields for proper output.
961 foreach($linksToDisplay as $key=>$link) 977 foreach($linksToDisplay as $key=>$link)
962 { 978 {
979
963 $taglist = explode(' ',$link['tags']); 980 $taglist = explode(' ',$link['tags']);
964 uasort($taglist, 'strcasecmp'); 981 uasort($taglist, 'strcasecmp');
965 $linksToDisplay[$key]['taglist']=$taglist; 982 $linksToDisplay[$key]['taglist']=$taglist;
966 $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))); 983 $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable($link['description'])));
967 $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']); 984 $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']);
968 $linksToDisplay[$key]['timestamp'] = linkdate2timestamp($link['linkdate']); 985 $linksToDisplay[$key]['timestamp'] = linkdate2timestamp($link['linkdate']);
969 } 986 }
@@ -1017,7 +1034,7 @@ function renderPage()
1017 $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful. 1034 $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful.
1018 $PAGE = new pageBuilder; 1035 $PAGE = new pageBuilder;
1019 $PAGE->assign('token',$token); 1036 $PAGE->assign('token',$token);
1020 $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER']:'')); 1037 $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']):''));
1021 $PAGE->renderPage('loginform'); 1038 $PAGE->renderPage('loginform');
1022 exit; 1039 exit;
1023 } 1040 }
@@ -1045,7 +1062,7 @@ function renderPage()
1045 // Get only links which have a thumbnail. 1062 // Get only links which have a thumbnail.
1046 foreach($links as $link) 1063 foreach($links as $link)
1047 { 1064 {
1048 $permalink='?'.htmlspecialchars(smallhash($link['linkdate']),ENT_QUOTES); 1065 $permalink='?'.escape(smallhash($link['linkdate']));
1049 $thumb=lazyThumbnail($link['url'],$permalink); 1066 $thumb=lazyThumbnail($link['url'],$permalink);
1050 if ($thumb!='') // Only output links which have a thumbnail. 1067 if ($thumb!='') // Only output links which have a thumbnail.
1051 { 1068 {
@@ -1254,8 +1271,8 @@ function renderPage()
1254 $PAGE = new pageBuilder; 1271 $PAGE = new pageBuilder;
1255 $PAGE->assign('linkcount',count($LINKSDB)); 1272 $PAGE->assign('linkcount',count($LINKSDB));
1256 $PAGE->assign('token',getToken()); 1273 $PAGE->assign('token',getToken());
1257 $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES)); 1274 $PAGE->assign('title', empty($GLOBALS['title']) ? '' : $GLOBALS['title'] );
1258 $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES)); 1275 $PAGE->assign('redirector', empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] );
1259 list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']); 1276 list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']);
1260 $PAGE->assign('timezone_form',$timezone_form); // FIXME: Put entire tz form generation in template? 1277 $PAGE->assign('timezone_form',$timezone_form); // FIXME: Put entire tz form generation in template?
1261 $PAGE->assign('timezone_js',$timezone_js); 1278 $PAGE->assign('timezone_js',$timezone_js);
@@ -1415,7 +1432,7 @@ function renderPage()
1415 $PAGE->assign('link',$link); 1432 $PAGE->assign('link',$link);
1416 $PAGE->assign('link_is_new',false); 1433 $PAGE->assign('link_is_new',false);
1417 $PAGE->assign('token',getToken()); // XSRF protection. 1434 $PAGE->assign('token',getToken()); // XSRF protection.
1418 $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); 1435 $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''));
1419 $PAGE->assign('tags', $LINKSDB->allTags()); 1436 $PAGE->assign('tags', $LINKSDB->allTags());
1420 $PAGE->renderPage('editlink'); 1437 $PAGE->renderPage('editlink');
1421 exit; 1438 exit;
@@ -1539,10 +1556,10 @@ HTML;
1539 ($exportWhat=='private' && $link['private']!=0) || 1556 ($exportWhat=='private' && $link['private']!=0) ||
1540 ($exportWhat=='public' && $link['private']==0)) 1557 ($exportWhat=='public' && $link['private']==0))
1541 { 1558 {
1542 echo '<DT><A HREF="'.htmlspecialchars($link['url']).'" ADD_DATE="'.linkdate2timestamp($link['linkdate']).'" PRIVATE="'.$link['private'].'"'; 1559 echo '<DT><A HREF="'.$link['url'].'" ADD_DATE="'.linkdate2timestamp($link['linkdate']).'" PRIVATE="'.$link['private'].'"';
1543 if ($link['tags']!='') echo ' TAGS="'.htmlspecialchars(str_replace(' ',',',$link['tags'])).'"'; 1560 if ($link['tags']!='') echo ' TAGS="'.str_replace(' ',',',$link['tags']).'"';
1544 echo '>'.htmlspecialchars($link['title'])."</A>\n"; 1561 echo '>'.$link['title']."</A>\n";
1545 if ($link['description']!='') echo '<DD>'.htmlspecialchars($link['description'])."\n"; 1562 if ($link['description']!='') echo '<DD>'.$link['description']."\n";
1546 } 1563 }
1547 } 1564 }
1548 exit; 1565 exit;
@@ -1555,7 +1572,7 @@ HTML;
1555 if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0)) 1572 if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0))
1556 { 1573 {
1557 $returnurl = ( empty($_SERVER['HTTP_REFERER']) ? '?' : $_SERVER['HTTP_REFERER'] ); 1574 $returnurl = ( empty($_SERVER['HTTP_REFERER']) ? '?' : $_SERVER['HTTP_REFERER'] );
1558 echo '<script>alert("The file you are trying to upload is probably bigger than what this webserver can accept ('.getMaxFileSize().' bytes). Please upload in smaller chunks.");document.location=\''.htmlspecialchars($returnurl).'\';</script>'; 1575 echo '<script>alert("The file you are trying to upload is probably bigger than what this webserver can accept ('.getMaxFileSize().' bytes). Please upload in smaller chunks.");document.location=\''.escape($returnurl).'\';</script>';
1559 exit; 1576 exit;
1560 } 1577 }
1561 if (!tokenOk($_POST['token'])) die('Wrong token.'); 1578 if (!tokenOk($_POST['token'])) die('Wrong token.');
@@ -1681,13 +1698,13 @@ function buildLinkList($PAGE,$LINKSDB)
1681 if (isset($_GET['searchterm'])) // Fulltext search 1698 if (isset($_GET['searchterm'])) // Fulltext search
1682 { 1699 {
1683 $linksToDisplay = $LINKSDB->filterFulltext(trim($_GET['searchterm'])); 1700 $linksToDisplay = $LINKSDB->filterFulltext(trim($_GET['searchterm']));
1684 $search_crits=htmlspecialchars(trim($_GET['searchterm'])); 1701 $search_crits=escape(trim($_GET['searchterm']));
1685 $search_type='fulltext'; 1702 $search_type='fulltext';
1686 } 1703 }
1687 elseif (isset($_GET['searchtags'])) // Search by tag 1704 elseif (isset($_GET['searchtags'])) // Search by tag
1688 { 1705 {
1689 $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); 1706 $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
1690 $search_crits=explode(' ',trim($_GET['searchtags'])); 1707 $search_crits=explode(' ',escape(trim($_GET['searchtags'])));
1691 $search_type='tags'; 1708 $search_type='tags';
1692 } 1709 }
1693 elseif (isset($_SERVER['QUERY_STRING']) && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/',$_SERVER['QUERY_STRING'])) // Detect smallHashes in URL 1710 elseif (isset($_SERVER['QUERY_STRING']) && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/',$_SERVER['QUERY_STRING'])) // Detect smallHashes in URL
@@ -1724,10 +1741,8 @@ function buildLinkList($PAGE,$LINKSDB)
1724 */ 1741 */
1725 $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // Stupid and ugly. Thanks PHP. 1742 $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // Stupid and ugly. Thanks PHP.
1726 1743
1727 // If it's a permalink, we change on-the-fly the title of the page. 1744 // If there is only a single link, we change on-the-fly the title of the page.
1728 if(!empty($search_type && $search_type == 'permalink')) { 1745 if (count($linksToDisplay)==1) $GLOBALS['pagetitle'] = $linksToDisplay[$keys[0]]['title'].' - '.$GLOBALS['title'];
1729 $GLOBALS['pagetitle'] = $linksToDisplay[$keys[0]]['title'] . ' - ' . $GLOBALS['title'];
1730 }
1731 1746
1732 // Select articles according to paging. 1747 // Select articles according to paging.
1733 $pagecount = ceil(count($keys)/$_SESSION['LINKS_PER_PAGE']); 1748 $pagecount = ceil(count($keys)/$_SESSION['LINKS_PER_PAGE']);
@@ -1741,7 +1756,7 @@ function buildLinkList($PAGE,$LINKSDB)
1741 while ($i<$end && $i<count($keys)) 1756 while ($i<$end && $i<count($keys))
1742 { 1757 {
1743 $link = $linksToDisplay[$keys[$i]]; 1758 $link = $linksToDisplay[$keys[$i]];
1744 $link['description']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description'])))); 1759 $link['description']=nl2br(keepMultipleSpaces(text2clickable($link['description'])));
1745 $title=$link['title']; 1760 $title=$link['title'];
1746 $classLi = $i%2!=0 ? '' : 'publicLinkHightLight'; 1761 $classLi = $i%2!=0 ? '' : 'publicLinkHightLight';
1747 $link['class'] = ($link['private']==0 ? $classLi : 'private'); 1762 $link['class'] = ($link['private']==0 ? $classLi : 'private');
@@ -1887,7 +1902,7 @@ function computeThumbnail($url,$href=false)
1887 if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL. 1902 if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL.
1888 } 1903 }
1889 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) 1904 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation)
1890 return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url), 1905 return array('src'=>indexUrl().'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url),
1891 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); 1906 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail');
1892 } 1907 }
1893 1908
@@ -1898,7 +1913,7 @@ function computeThumbnail($url,$href=false)
1898 if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') 1913 if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif')
1899 { 1914 {
1900 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) 1915 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation)
1901 return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url), 1916 return array('src'=>indexUrl().'?do=genthumbnail&hmac='.$sign.'&url='.urlencode($url),
1902 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail'); 1917 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail');
1903 } 1918 }
1904 return array(); // No thumbnail. 1919 return array(); // No thumbnail.
@@ -1917,11 +1932,11 @@ function thumbnail($url,$href=false)
1917 $t = computeThumbnail($url,$href); 1932 $t = computeThumbnail($url,$href);
1918 if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. 1933 if (count($t)==0) return ''; // Empty array = no thumbnail for this URL.
1919 1934
1920 $html='<a href="'.htmlspecialchars($t['href']).'"><img src="'.htmlspecialchars($t['src']).'"'; 1935 $html='<a href="'.escape($t['href']).'"><img src="'.escape($t['src']).'"';
1921 if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"'; 1936 if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"';
1922 if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"'; 1937 if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"';
1923 if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"'; 1938 if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"';
1924 if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"'; 1939 if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"';
1925 $html.='></a>'; 1940 $html.='></a>';
1926 return $html; 1941 return $html;
1927} 1942}
@@ -1937,23 +1952,23 @@ function lazyThumbnail($url,$href=false)
1937 $t = computeThumbnail($url,$href); 1952 $t = computeThumbnail($url,$href);
1938 if (count($t)==0) return ''; // Empty array = no thumbnail for this URL. 1953 if (count($t)==0) return ''; // Empty array = no thumbnail for this URL.
1939 1954
1940 $html='<a href="'.htmlspecialchars($t['href']).'">'; 1955 $html='<a href="'.escape($t['href']).'">';
1941 1956
1942 // Lazy image 1957 // Lazy image
1943 $html.='<img class="b-lazy" src="#" data-src="'.htmlspecialchars($t['src']).'"'; 1958 $html.='<img class="b-lazy" src="#" data-src="'.escape($t['src']).'"';
1944 1959
1945 if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"'; 1960 if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"';
1946 if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"'; 1961 if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"';
1947 if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"'; 1962 if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"';
1948 if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"'; 1963 if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"';
1949 $html.='>'; 1964 $html.='>';
1950 1965
1951 // No-JavaScript fallback. 1966 // No-JavaScript fallback.
1952 $html.='<noscript><img src="'.htmlspecialchars($t['src']).'"'; 1967 $html.='<noscript><img src="'.escape($t['src']).'"';
1953 if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"'; 1968 if (!empty($t['width'])) $html.=' width="'.escape($t['width']).'"';
1954 if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"'; 1969 if (!empty($t['height'])) $html.=' height="'.escape($t['height']).'"';
1955 if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"'; 1970 if (!empty($t['style'])) $html.=' style="'.escape($t['style']).'"';
1956 if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"'; 1971 if (!empty($t['alt'])) $html.=' alt="'.escape($t['alt']).'"';
1957 $html.='></noscript></a>'; 1972 $html.='></noscript></a>';
1958 1973
1959 return $html; 1974 return $html;
@@ -2003,7 +2018,7 @@ function install()
2003 $GLOBALS['login'] = $_POST['setlogin']; 2018 $GLOBALS['login'] = $_POST['setlogin'];
2004 $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. 2019 $GLOBALS['salt'] = sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless.
2005 $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']); 2020 $GLOBALS['hash'] = sha1($_POST['setpassword'].$GLOBALS['login'].$GLOBALS['salt']);
2006 $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.htmlspecialchars(indexUrl()) : $_POST['title'] ); 2021 $GLOBALS['title'] = (empty($_POST['title']) ? 'Shared links on '.escape(indexUrl()) : $_POST['title'] );
2007 $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']); 2022 $GLOBALS['config']['ENABLE_UPDATECHECK'] = !empty($_POST['updateCheck']);
2008 writeConfig(); 2023 writeConfig();
2009 echo '<script>alert("Shaarli is now configured. Please enter your login/password and start shaaring your links!");document.location=\'?do=login\';</script>'; 2024 echo '<script>alert("Shaarli is now configured. Please enter your login/password and start shaaring your links!");document.location=\'?do=login\';</script>';
@@ -2230,7 +2245,7 @@ function genThumbnail()
2230 // This is more complex: we have to perform a HTTP request, then parse the result. 2245 // This is more complex: we have to perform a HTTP request, then parse the result.
2231 // Maybe we should deport this to JavaScript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098 2246 // Maybe we should deport this to JavaScript ? Example: http://stackoverflow.com/questions/1361149/get-img-thumbnails-from-vimeo/4285098#4285098
2232 $vid = substr(parse_url($url,PHP_URL_PATH),1); 2247 $vid = substr(parse_url($url,PHP_URL_PATH),1);
2233 list($httpstatus,$headers,$data) = getHTTP('https://vimeo.com/api/v2/video/'.htmlspecialchars($vid).'.php',5); 2248 list($httpstatus,$headers,$data) = getHTTP('https://vimeo.com/api/v2/video/'.escape($vid).'.php',5);
2234 if (strpos($httpstatus,'200 OK')!==false) 2249 if (strpos($httpstatus,'200 OK')!==false)
2235 { 2250 {
2236 $t = unserialize($data); 2251 $t = unserialize($data);