aboutsummaryrefslogtreecommitdiffhomepage
path: root/index.php
diff options
context:
space:
mode:
Diffstat (limited to 'index.php')
-rw-r--r--index.php322
1 files changed, 243 insertions, 79 deletions
diff --git a/index.php b/index.php
index 9dd6483e..936d6129 100644
--- a/index.php
+++ b/index.php
@@ -1,5 +1,5 @@
1<?php 1<?php
2// Shaarli 0.0.36 beta - Shaare your links... 2// Shaarli 0.0.37 beta - Shaare your links...
3// The personal, minimalist, super-fast, no-database delicious clone. By sebsauvage.net 3// The personal, minimalist, super-fast, no-database delicious clone. By sebsauvage.net
4// http://sebsauvage.net/wiki/doku.php?id=php:shaarli 4// http://sebsauvage.net/wiki/doku.php?id=php:shaarli
5// Licence: http://www.opensource.org/licenses/zlib-license.php 5// Licence: http://www.opensource.org/licenses/zlib-license.php
@@ -58,7 +58,7 @@ header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
58header("Cache-Control: no-store, no-cache, must-revalidate"); 58header("Cache-Control: no-store, no-cache, must-revalidate");
59header("Cache-Control: post-check=0, pre-check=0", false); 59header("Cache-Control: post-check=0, pre-check=0", false);
60header("Pragma: no-cache"); 60header("Pragma: no-cache");
61define('shaarli_version','0.0.36 beta'); 61define('shaarli_version','0.0.37 beta');
62if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); } 62if (!is_dir($GLOBALS['config']['DATADIR'])) { mkdir($GLOBALS['config']['DATADIR'],0705); chmod($GLOBALS['config']['DATADIR'],0705); }
63if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['DATADIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. 63if (!is_file($GLOBALS['config']['DATADIR'].'/.htaccess')) { file_put_contents($GLOBALS['config']['DATADIR'].'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files.
64if ($GLOBALS['config']['ENABLE_LOCALCACHE']) 64if ($GLOBALS['config']['ENABLE_LOCALCACHE'])
@@ -153,8 +153,8 @@ function text2clickable($url)
153// even in the absence of <pre> (This is used in description to keep text formatting) 153// even in the absence of <pre> (This is used in description to keep text formatting)
154function keepMultipleSpaces($text) 154function keepMultipleSpaces($text)
155{ 155{
156 return str_replace(' ',' &nbsp;',$text); 156 return str_replace(' ',' &nbsp;',$text);
157 157
158} 158}
159// ------------------------------------------------------------------------------------------ 159// ------------------------------------------------------------------------------------------
160// Sniff browser language to display dates in the right format automatically. 160// Sniff browser language to display dates in the right format automatically.
@@ -850,6 +850,75 @@ function showATOM()
850} 850}
851 851
852// ------------------------------------------------------------------------------------------ 852// ------------------------------------------------------------------------------------------
853// Daily RSS feed: 1 RSS entry per day giving all the links on that day.
854// Gives the last 7 days (which have links).
855// This RSS feed cannot be filtered.
856function showDailyRSS()
857{
858 global $LINKSDB;
859
860 /* Some Shaarlies may have very few links, so we need to look
861 back in time (rsort()) until we have enough days ($nb_of_days).
862 */
863 $linkdates=array(); foreach($LINKSDB as $linkdate=>$value) { $linkdates[]=$linkdate; }
864 rsort($linkdates);
865 $nb_of_days=7; // We take 7 days.
866 $today=Date('Ymd');
867 $days=array();
868 foreach($linkdates as $linkdate)
869 {
870 $day=substr($linkdate,0,8); // Extract day (without time)
871 if (strcmp($day,$today)<0)
872 {
873 if (empty($days[$day])) $days[$day]=array();
874 $days[$day][]=$linkdate;
875 }
876 if (count($days)>$nb_of_days) break; // Have we collected enough days ?
877 }
878
879 // Build the RSS feed.
880 header('Content-Type: application/rss+xml; charset=utf-8');
881 $pageaddr=htmlspecialchars(indexUrl());
882 echo '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0">';
883 echo '<channel><title>Daily - '.htmlspecialchars($GLOBALS['title']).'</title><link>'.$pageaddr.'</link>';
884 echo '<description>Daily shared links</description><language>en-en</language><copyright>'.$pageaddr.'</copyright>'."\n";
885
886 foreach($days as $day=>$linkdates) // For each day.
887 {
888 $daydate = utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))); // Full text date
889 $rfc822date = linkdate2rfc822($day.'_000000');
890 $absurl=htmlspecialchars(indexUrl().'?do=daily&day='.$day); // Absolute URL of the corresponding "Daily" page.
891 echo '<item><title>'.htmlspecialchars($GLOBALS['title'].' - '.$daydate).'</title><guid>'.$absurl.'</guid><link>'.$absurl.'</link>';
892 echo '<pubDate>'.htmlspecialchars($rfc822date)."</pubDate>";
893
894 // Build the HTML body of this RSS entry.
895 $html='';
896 $href='';
897 $links=array();
898 // We pre-format some fields for proper output.
899 foreach($linkdates as $linkdate)
900 {
901 $l = $LINKSDB[$linkdate];
902 $l['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($l['description']))));
903 $l['thumbnail'] = thumbnail($l['url']);
904 $l['localdate']=linkdate2locale($l['linkdate']);
905 if (startsWith($l['url'],'?')) $l['url']=indexUrl().$l['url']; // make permalink URL absolute
906 $links[$linkdate]=$l;
907 }
908 // Then build the HTML for this day:
909 $tpl = new RainTPL;
910 $tpl->assign('links',$links);
911 $html = $tpl->draw('dailyrss',$return_string=true);
912 echo "\n";
913 echo '<description><![CDATA['.$html.']]></description>'."\n</item>\n\n";
914
915 }
916 echo '</channel></rss>';
917 exit;
918}
919
920
921// ------------------------------------------------------------------------------------------
853// Render HTML page (according to URL parameters and user rights) 922// Render HTML page (according to URL parameters and user rights)
854function renderPage() 923function renderPage()
855{ 924{
@@ -861,7 +930,7 @@ function renderPage()
861 if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; } // No need to login for open Shaarli 930 if ($GLOBALS['config']['OPEN_SHAARLI']) { header('Location: ?'); exit; } // No need to login for open Shaarli
862 $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful. 931 $token=''; if (ban_canLogin()) $token=getToken(); // Do not waste token generation if not useful.
863 $PAGE = new pageBuilder; 932 $PAGE = new pageBuilder;
864 $PAGE->assign('token',$token); 933 $PAGE->assign('token',$token);
865 $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER']:'')); 934 $PAGE->assign('returnurl',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER']:''));
866 $PAGE->renderPage('loginform'); 935 $PAGE->renderPage('loginform');
867 exit; 936 exit;
@@ -890,17 +959,17 @@ function renderPage()
890 foreach($links as $link) 959 foreach($links as $link)
891 { 960 {
892 $permalink='?'.htmlspecialchars(smallhash($link['linkdate']),ENT_QUOTES); 961 $permalink='?'.htmlspecialchars(smallhash($link['linkdate']),ENT_QUOTES);
893 $thumb=thumbnail($link['url'],$permalink); 962 $thumb=lazyThumbnail($link['url'],$permalink);
894 if ($thumb!='') // Only output links which have a thumbnail. 963 if ($thumb!='') // Only output links which have a thumbnail.
895 { 964 {
896 $link['thumbnail']=$thumb; // Thumbnail HTML code. 965 $link['thumbnail']=$thumb; // Thumbnail HTML code.
897 $link['permalink']=$permalink; 966 $link['permalink']=$permalink;
898 $linksToDisplay[]=$link; // Add to array. 967 $linksToDisplay[]=$link; // Add to array.
899 } 968 }
900 } 969 }
901 $PAGE = new pageBuilder; 970 $PAGE = new pageBuilder;
902 $PAGE->assign('linksToDisplay',$linksToDisplay); 971 $PAGE->assign('linksToDisplay',$linksToDisplay);
903 $PAGE->renderPage('picwall'); 972 $PAGE->renderPage('picwall');
904 exit; 973 exit;
905 } 974 }
906 975
@@ -915,12 +984,12 @@ function renderPage()
915 $tagList=array(); 984 $tagList=array();
916 foreach($tags as $key=>$value) 985 foreach($tags as $key=>$value)
917 { 986 {
918 $tagList[$key] = array('count'=>$value,'size'=>max(40*$value/$maxcount,8)); 987 $tagList[$key] = array('count'=>$value,'size'=>max(40*$value/$maxcount,8));
919 } 988 }
920 $PAGE = new pageBuilder; 989 $PAGE = new pageBuilder;
921 $PAGE->assign('tags',$tagList); 990 $PAGE->assign('tags',$tagList);
922 $PAGE->renderPage('tagcloud'); 991 $PAGE->renderPage('tagcloud');
923 exit; 992 exit;
924 } 993 }
925 994
926 // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...) 995 // -------- User clicks on a tag in a link: The tag is added to the list of searched tags (searchtags=...)
@@ -960,6 +1029,21 @@ function renderPage()
960 exit; 1029 exit;
961 } 1030 }
962 1031
1032 // -------- User wants to see only private links (toggle)
1033 if (isset($_GET['privateonly']))
1034 {
1035 if (empty($_SESSION['privateonly']))
1036 {
1037 $_SESSION['privateonly']=1; // See only private links
1038 }
1039 else
1040 {
1041 unset($_SESSION['privateonly']); // See all links
1042 }
1043 header('Location: '.(empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']));
1044 exit;
1045 }
1046
963 // --------- Daily (all links form a specific day) ---------------------- 1047 // --------- Daily (all links form a specific day) ----------------------
964 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=daily')) 1048 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=daily'))
965 { 1049 {
@@ -1000,7 +1084,7 @@ function renderPage()
1000 $fill[$index]+=$length; 1084 $fill[$index]+=$length;
1001 } 1085 }
1002 $PAGE = new pageBuilder; 1086 $PAGE = new pageBuilder;
1003 $PAGE->assign('linksToDisplay',$linksToDisplay); 1087 $PAGE->assign('linksToDisplay',$linksToDisplay);
1004 $PAGE->assign('col1',$columns[0]); 1088 $PAGE->assign('col1',$columns[0]);
1005 $PAGE->assign('col2',$columns[1]); 1089 $PAGE->assign('col2',$columns[1]);
1006 $PAGE->assign('col3',$columns[2]); 1090 $PAGE->assign('col3',$columns[2]);
@@ -1021,10 +1105,10 @@ function renderPage()
1021 header('Location: ?do=login&post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'')); // Redirect to login page, then back to post link. 1105 header('Location: ?do=login&post='.urlencode($_GET['post']).(!empty($_GET['title'])?'&title='.urlencode($_GET['title']):'').(!empty($_GET['source'])?'&source='.urlencode($_GET['source']):'')); // Redirect to login page, then back to post link.
1022 exit; 1106 exit;
1023 } 1107 }
1024 $PAGE = new pageBuilder; 1108 $PAGE = new pageBuilder;
1025 buildLinkList($PAGE); // Compute list of links to display 1109 buildLinkList($PAGE); // Compute list of links to display
1026 $PAGE->renderPage('linklist'); 1110 $PAGE->renderPage('linklist');
1027 exit; // Never remove this one ! All operations below are reserved for logged in user. 1111 exit; // Never remove this one ! All operations below are reserved for logged in user.
1028 } 1112 }
1029 1113
1030 // -------- All other functions are reserved for the registered user: 1114 // -------- All other functions are reserved for the registered user:
@@ -1032,9 +1116,9 @@ function renderPage()
1032 // -------- Display the Tools menu if requested (import/export/bookmarklet...) 1116 // -------- Display the Tools menu if requested (import/export/bookmarklet...)
1033 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=tools')) 1117 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=tools'))
1034 { 1118 {
1035 $PAGE = new pageBuilder; 1119 $PAGE = new pageBuilder;
1036 $PAGE->assign('pageabsaddr',indexUrl()); 1120 $PAGE->assign('pageabsaddr',indexUrl());
1037 $PAGE->renderPage('tools'); 1121 $PAGE->renderPage('tools');
1038 exit; 1122 exit;
1039 } 1123 }
1040 1124
@@ -1058,10 +1142,10 @@ function renderPage()
1058 } 1142 }
1059 else // show the change password form. 1143 else // show the change password form.
1060 { 1144 {
1061 $PAGE = new pageBuilder; 1145 $PAGE = new pageBuilder;
1062 $PAGE->assign('token',getToken()); 1146 $PAGE->assign('token',getToken());
1063 $PAGE->renderPage('changepassword'); 1147 $PAGE->renderPage('changepassword');
1064 exit; 1148 exit;
1065 } 1149 }
1066 } 1150 }
1067 1151
@@ -1084,15 +1168,15 @@ function renderPage()
1084 } 1168 }
1085 else // Show the configuration form. 1169 else // Show the configuration form.
1086 { 1170 {
1087 $PAGE = new pageBuilder; 1171 $PAGE = new pageBuilder;
1088 $PAGE->assign('token',getToken()); 1172 $PAGE->assign('token',getToken());
1089 $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES)); 1173 $PAGE->assign('title',htmlspecialchars( empty($GLOBALS['title']) ? '' : $GLOBALS['title'] , ENT_QUOTES));
1090 $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES)); 1174 $PAGE->assign('redirector',htmlspecialchars( empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'] , ENT_QUOTES));
1091 list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']); 1175 list($timezone_form,$timezone_js) = templateTZform($GLOBALS['timezone']);
1092 $PAGE->assign('timezone_form',$timezone_form); // FIXME: put entire tz form generation in template ? 1176 $PAGE->assign('timezone_form',$timezone_form); // FIXME: put entire tz form generation in template ?
1093 $PAGE->assign('timezone_js',$timezone_js); 1177 $PAGE->assign('timezone_js',$timezone_js);
1094 $PAGE->renderPage('configure'); 1178 $PAGE->renderPage('configure');
1095 exit; 1179 exit;
1096 } 1180 }
1097 } 1181 }
1098 1182
@@ -1101,10 +1185,10 @@ function renderPage()
1101 { 1185 {
1102 if (empty($_POST['fromtag'])) 1186 if (empty($_POST['fromtag']))
1103 { 1187 {
1104 $PAGE = new pageBuilder; 1188 $PAGE = new pageBuilder;
1105 $PAGE->assign('token',getToken()); 1189 $PAGE->assign('token',getToken());
1106 $PAGE->renderPage('changetag'); 1190 $PAGE->renderPage('changetag');
1107 exit; 1191 exit;
1108 } 1192 }
1109 if (!tokenOk($_POST['token'])) die('Wrong token.'); 1193 if (!tokenOk($_POST['token'])) die('Wrong token.');
1110 1194
@@ -1148,8 +1232,8 @@ function renderPage()
1148 // -------- User wants to add a link without using the bookmarklet: show form. 1232 // -------- User wants to add a link without using the bookmarklet: show form.
1149 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=addlink')) 1233 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=addlink'))
1150 { 1234 {
1151 $PAGE = new pageBuilder; 1235 $PAGE = new pageBuilder;
1152 $PAGE->renderPage('addlink'); 1236 $PAGE->renderPage('addlink');
1153 exit; 1237 exit;
1154 } 1238 }
1155 1239
@@ -1207,12 +1291,12 @@ function renderPage()
1207 { 1291 {
1208 $link = $LINKSDB[$_GET['edit_link']]; // Read database 1292 $link = $LINKSDB[$_GET['edit_link']]; // Read database
1209 if (!$link) { header('Location: ?'); exit; } // Link not found in database. 1293 if (!$link) { header('Location: ?'); exit; } // Link not found in database.
1210 $PAGE = new pageBuilder; 1294 $PAGE = new pageBuilder;
1211 $PAGE->assign('link',$link); 1295 $PAGE->assign('link',$link);
1212 $PAGE->assign('link_is_new',false); 1296 $PAGE->assign('link_is_new',false);
1213 $PAGE->assign('token',getToken()); // XSRF protection. 1297 $PAGE->assign('token',getToken()); // XSRF protection.
1214 $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); 1298 $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''));
1215 $PAGE->renderPage('editlink'); 1299 $PAGE->renderPage('editlink');
1216 exit; 1300 exit;
1217 } 1301 }
1218 1302
@@ -1246,12 +1330,12 @@ function renderPage()
1246 $link = array('linkdate'=>$linkdate,'title'=>$title,'url'=>$url,'description'=>$description,'tags'=>$tags,'private'=>0); 1330 $link = array('linkdate'=>$linkdate,'title'=>$title,'url'=>$url,'description'=>$description,'tags'=>$tags,'private'=>0);
1247 } 1331 }
1248 1332
1249 $PAGE = new pageBuilder; 1333 $PAGE = new pageBuilder;
1250 $PAGE->assign('link',$link); 1334 $PAGE->assign('link',$link);
1251 $PAGE->assign('link_is_new',$link_is_new); 1335 $PAGE->assign('link_is_new',$link_is_new);
1252 $PAGE->assign('token',getToken()); // XSRF protection. 1336 $PAGE->assign('token',getToken()); // XSRF protection.
1253 $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '')); 1337 $PAGE->assign('http_referer',(isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''));
1254 $PAGE->renderPage('editlink'); 1338 $PAGE->renderPage('editlink');
1255 exit; 1339 exit;
1256 } 1340 }
1257 1341
@@ -1260,9 +1344,9 @@ function renderPage()
1260 { 1344 {
1261 if (empty($_GET['what'])) 1345 if (empty($_GET['what']))
1262 { 1346 {
1263 $PAGE = new pageBuilder; 1347 $PAGE = new pageBuilder;
1264 $PAGE->renderPage('export'); 1348 $PAGE->renderPage('export');
1265 exit; 1349 exit;
1266 } 1350 }
1267 $exportWhat=$_GET['what']; 1351 $exportWhat=$_GET['what'];
1268 if (!array_intersect(array('all','public','private'),array($exportWhat))) die('What are you trying to export ???'); 1352 if (!array_intersect(array('all','public','private'),array($exportWhat))) die('What are you trying to export ???');
@@ -1313,10 +1397,10 @@ HTML;
1313 // -------- Show upload/import dialog: 1397 // -------- Show upload/import dialog:
1314 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=import')) 1398 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=import'))
1315 { 1399 {
1316 $PAGE = new pageBuilder; 1400 $PAGE = new pageBuilder;
1317 $PAGE->assign('token',getToken()); 1401 $PAGE->assign('token',getToken());
1318 $PAGE->assign('maxfilesize',getMaxFileSize()); 1402 $PAGE->assign('maxfilesize',getMaxFileSize());
1319 $PAGE->renderPage('import'); 1403 $PAGE->renderPage('import');
1320 exit; 1404 exit;
1321 } 1405 }
1322 1406
@@ -1430,14 +1514,24 @@ function buildLinkList($PAGE)
1430 $search_crits=explode(' ',trim($_GET['searchtags'])); 1514 $search_crits=explode(' ',trim($_GET['searchtags']));
1431 $search_type='tags'; 1515 $search_type='tags';
1432 } 1516 }
1433 elseif (isset($_SERVER["QUERY_STRING"]) && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/',$_SERVER["QUERY_STRING"])) // Detect smallHashes in URL 1517 elseif (isset($_SERVER['QUERY_STRING']) && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/',$_SERVER['QUERY_STRING'])) // Detect smallHashes in URL
1434 { 1518 {
1435 $linksToDisplay = $LINKSDB->filterSmallHash(substr(trim($_SERVER["QUERY_STRING"], '/'),0,6)); 1519 $linksToDisplay = $LINKSDB->filterSmallHash(substr(trim($_SERVER["QUERY_STRING"], '/'),0,6));
1436 $search_type='permalink'; 1520 $search_type='permalink';
1437 } 1521 }
1438 else 1522 else
1439 $linksToDisplay = $LINKSDB; // otherwise, display without filtering. 1523 $linksToDisplay = $LINKSDB; // otherwise, display without filtering.
1440 1524
1525 // Option: Show only private links
1526 if (!empty($_SESSION['privateonly']))
1527 {
1528 $tmp = array();
1529 foreach($linksToDisplay as $linkdate=>$link)
1530 {
1531 if ($link['private']!=0) $tmp[$linkdate]=$link;
1532 }
1533 $linksToDisplay=$tmp;
1534 }
1441 1535
1442 // ---- Handle paging. 1536 // ---- Handle paging.
1443 /* Can someone explain to me why you get the following error when using array_keys() on an object which implements the interface ArrayAccess ??? 1537 /* Can someone explain to me why you get the following error when using array_keys() on an object which implements the interface ArrayAccess ???
@@ -1494,16 +1588,18 @@ function buildLinkList($PAGE)
1494 return; 1588 return;
1495} 1589}
1496 1590
1497// Returns the HTML code to display a thumbnail for a link 1591// Compute the thumbnail for a link.
1592//
1498// with a link to the original URL. 1593// with a link to the original URL.
1499// Understands various services (youtube.com...) 1594// Understands various services (youtube.com...)
1500// Input: $url = url for which the thumbnail must be found. 1595// Input: $url = url for which the thumbnail must be found.
1501// $href = if provided, this URL will be followed instead of $url 1596// $href = if provided, this URL will be followed instead of $url
1502// Returns '' if no thumbnail available. 1597// Returns an associative array with thumbnail attributes (src,href,width,height,style,alt)
1503function thumbnail($url,$href=false) 1598// Some of them may be missing.
1599// Return an empty array if no thumbnail available.
1600function computeThumbnail($url,$href=false)
1504{ 1601{
1505 if (!$GLOBALS['config']['ENABLE_THUMBNAILS']) return ''; 1602 if (!$GLOBALS['config']['ENABLE_THUMBNAILS']) return array();
1506
1507 if ($href==false) $href=$url; 1603 if ($href==false) $href=$url;
1508 1604
1509 // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. 1605 // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link.
@@ -1513,38 +1609,47 @@ function thumbnail($url,$href=false)
1513 if ($domain=='youtube.com' || $domain=='www.youtube.com') 1609 if ($domain=='youtube.com' || $domain=='www.youtube.com')
1514 { 1610 {
1515 parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail 1611 parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail
1516 if (!empty($params['v'])) return '<a href="'.htmlspecialchars($href).'"><img src="http://img.youtube.com/vi/'.htmlspecialchars($params['v']).'/default.jpg" width="120" height="90" alt="YouTube thumbnail"></a>'; 1612 if (!empty($params['v'])) return array('src'=>'http://img.youtube.com/vi/'.$params['v'].'/default.jpg',
1613 'href'=>$href,'width'=>'120','height'=>'90','alt'=>'YouTube thumbnail');
1517 } 1614 }
1518 if ($domain=='youtu.be') // Youtube short links 1615 if ($domain=='youtu.be') // Youtube short links
1519 { 1616 {
1520 $path = parse_url($url,PHP_URL_PATH); 1617 $path = parse_url($url,PHP_URL_PATH);
1521 return '<a href="'.htmlspecialchars($href).'"><img src="http://img.youtube.com/vi'.htmlspecialchars($path).'/default.jpg" width="120" height="90" alt="YouTube thumbnail"></a>'; 1618 return array('src'=>'http://img.youtube.com/vi'.$path.'/default.jpg',
1619 'href'=>$href,'width'=>'120','height'=>'90','alt'=>'YouTube thumbnail');
1522 } 1620 }
1523 if ($domain=='pix.toile-libre.org') // pix.toile-libre.org image hosting 1621 if ($domain=='pix.toile-libre.org') // pix.toile-libre.org image hosting
1524 { 1622 {
1525 parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract image filename. 1623 parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract image filename.
1526 if (!empty($params) && !empty($params['img'])) return '<a href="'.htmlspecialchars($href).'"><img src="http://pix.toile-libre.org/upload/thumb/'.urlencode($params['img']).'" style:"max-width:120px; max-height:150px" alt="pix.toile-libre.org thumbnail"></a>'; 1624 if (!empty($params) && !empty($params['img'])) return array('src'=>'http://pix.toile-libre.org/upload/thumb/'.urlencode($params['img']),
1625 'href'=>$href,'style'=>'max-width:120px; max-height:150px','alt'=>'pix.toile-libre.org thumbnail');
1527 } 1626 }
1528 1627
1529 if ($domain=='imgur.com') 1628 if ($domain=='imgur.com')
1530 { 1629 {
1531 $path = parse_url($url,PHP_URL_PATH); 1630 $path = parse_url($url,PHP_URL_PATH);
1532 if (startsWith($path,'/a/')) return ''; // Thumbnails for albums are not available. 1631 if (startsWith($path,'/a/')) return array(); // Thumbnails for albums are not available.
1533 if (startsWith($path,'/r/')) return '<a href="'.htmlspecialchars($href).'"><img src="http://i.imgur.com/'.htmlspecialchars(basename($path)).'s.jpg" width="90" height="90" alt="imgur.com thumbnail"></a>'; 1632 if (startsWith($path,'/r/')) return array('src'=>'http://i.imgur.com/'.basename($path).'s.jpg',
1534 if (startsWith($path,'/gallery/')) return '<a href="'.htmlspecialchars($href).'"><img src="http://i.imgur.com'.htmlspecialchars(substr($path,8)).'s.jpg" width="90" height="90" alt="imgur.com thumbnail"></a>'; 1633 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail');
1535 if (substr_count($path,'/')==1) return '<a href="'.htmlspecialchars($href).'"><img src="http://i.imgur.com/'.htmlspecialchars(substr($path,1)).'s.jpg" width="90" height="90" alt="imgur.com thumbnail"></a>'; 1634 if (startsWith($path,'/gallery/')) return array('src'=>'http://i.imgur.com'.substr($path,8).'s.jpg',
1635 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail');
1636
1637 if (substr_count($path,'/')==1) return array('src'=>'http://i.imgur.com/'.substr($path,1).'s.jpg',
1638 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail');
1536 } 1639 }
1537 if ($domain=='i.imgur.com') 1640 if ($domain=='i.imgur.com')
1538 { 1641 {
1539 $pi = pathinfo(parse_url($url,PHP_URL_PATH)); 1642 $pi = pathinfo(parse_url($url,PHP_URL_PATH));
1540 if (!empty($pi['filename'])) return '<a href="'.htmlspecialchars($href).'"><img src="http://i.imgur.com/'.htmlspecialchars($pi['filename']).'s.jpg" width="90" height="90" alt="imgur.com thumbnail"></a>'; 1643 if (!empty($pi['filename'])) return array('src'=>'http://i.imgur.com/'.$pi['filename'].'s.jpg',
1644 'href'=>$href,'width'=>'90','height'=>'90','alt'=>'imgur.com thumbnail');
1541 } 1645 }
1542 if ($domain=='dailymotion.com' || $domain=='www.dailymotion.com') 1646 if ($domain=='dailymotion.com' || $domain=='www.dailymotion.com')
1543 { 1647 {
1544 if (strpos($url,'dailymotion.com/video/')!==false) 1648 if (strpos($url,'dailymotion.com/video/')!==false)
1545 { 1649 {
1546 $thumburl=str_replace('dailymotion.com/video/','dailymotion.com/thumbnail/video/',$url); 1650 $thumburl=str_replace('dailymotion.com/video/','dailymotion.com/thumbnail/video/',$url);
1547 return '<a href="'.htmlspecialchars($href).'"><img src="'.htmlspecialchars($thumburl).'" width="120" style="height:auto;" alt="DailyMotion thumbnail"></a>'; 1651 return array('src'=>$thumburl,
1652 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'DailyMotion thumbnail');
1548 } 1653 }
1549 } 1654 }
1550 if (endsWith($domain,'.imageshack.us')) 1655 if (endsWith($domain,'.imageshack.us'))
@@ -1553,7 +1658,8 @@ function thumbnail($url,$href=false)
1553 if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') 1658 if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif')
1554 { 1659 {
1555 $thumburl = substr($url,0,strlen($url)-strlen($ext)).'th.'.$ext; 1660 $thumburl = substr($url,0,strlen($url)-strlen($ext)).'th.'.$ext;
1556 return '<a href="'.htmlspecialchars($href).'"><img src="'.htmlspecialchars($thumburl).'" width="120" style="height:auto;" alt="imageshack.us thumbnail"></a>'; 1661 return array('src'=>$thumburl,
1662 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'imageshack.us thumbnail');
1557 } 1663 }
1558 } 1664 }
1559 1665
@@ -1561,7 +1667,7 @@ function thumbnail($url,$href=false)
1561 // So we deport the thumbnail generation in order not to slow down page generation 1667 // So we deport the thumbnail generation in order not to slow down page generation
1562 // (and we also cache the thumbnail) 1668 // (and we also cache the thumbnail)
1563 1669
1564 if (!$GLOBALS['config']['ENABLE_LOCALCACHE']) return ''; // If local cache is disabled, no thumbnails for services which require the use a local cache. 1670 if (!$GLOBALS['config']['ENABLE_LOCALCACHE']) return array(); // If local cache is disabled, no thumbnails for services which require the use a local cache.
1565 1671
1566 if ($domain=='flickr.com' || endsWith($domain,'.flickr.com') 1672 if ($domain=='flickr.com' || endsWith($domain,'.flickr.com')
1567 || $domain=='vimeo.com' 1673 || $domain=='vimeo.com'
@@ -1572,20 +1678,21 @@ function thumbnail($url,$href=false)
1572 if ($domain=='vimeo.com') 1678 if ($domain=='vimeo.com')
1573 { // Make sure this vimeo url points to a video (/xxx... where xxx is numeric) 1679 { // Make sure this vimeo url points to a video (/xxx... where xxx is numeric)
1574 $path = parse_url($url,PHP_URL_PATH); 1680 $path = parse_url($url,PHP_URL_PATH);
1575 if (!preg_match('!/\d+.+?!',$path)) return ''; // This is not a single video URL. 1681 if (!preg_match('!/\d+.+?!',$path)) return array(); // This is not a single video URL.
1576 } 1682 }
1577 if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) 1683 if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com'))
1578 { // Make sure this url points to a single comic (/xxx... where xxx is numeric) 1684 { // Make sure this url points to a single comic (/xxx... where xxx is numeric)
1579 $path = parse_url($url,PHP_URL_PATH); 1685 $path = parse_url($url,PHP_URL_PATH);
1580 if (!preg_match('!/\d+.+?!',$path)) return ''; 1686 if (!preg_match('!/\d+.+?!',$path)) return array();
1581 } 1687 }
1582 if ($domain=='ted.com' || endsWith($domain,'.ted.com')) 1688 if ($domain=='ted.com' || endsWith($domain,'.ted.com'))
1583 { // Make sure this TED url points to a video (/talks/...) 1689 { // Make sure this TED url points to a video (/talks/...)
1584 $path = parse_url($url,PHP_URL_PATH); 1690 $path = parse_url($url,PHP_URL_PATH);
1585 if ("/talks/" !== substr($path,0,7)) return ''; // This is not a single video URL. 1691 if ("/talks/" !== substr($path,0,7)) return array(); // This is not a single video URL.
1586 } 1692 }
1587 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) 1693 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation)
1588 return '<a href="'.htmlspecialchars($href).'"><img src="?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url).'" width="120" style="height:auto;" alt="thumbnail"></a>'; 1694 return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url),
1695 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail');
1589 } 1696 }
1590 1697
1591 // For all other, we try to make a thumbnail of links ending with .jpg/jpeg/png/gif 1698 // For all other, we try to make a thumbnail of links ending with .jpg/jpeg/png/gif
@@ -1595,12 +1702,68 @@ function thumbnail($url,$href=false)
1595 if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') 1702 if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif')
1596 { 1703 {
1597 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) 1704 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation)
1598 return '<a href="'.htmlspecialchars($href).'"><img src="?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url).'" width="120" style="height:auto;"></a>'; 1705 return array('src'=>indexUrl().'?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url),
1706 'href'=>$href,'width'=>'120','style'=>'height:auto;','alt'=>'thumbnail');
1599 } 1707 }
1600 return ''; // No thumbnail. 1708 return array(); // No thumbnail.
1709
1710}
1711
1712
1713// Returns the HTML code to display a thumbnail for a link
1714// with a link to the original URL.
1715// Understands various services (youtube.com...)
1716// Input: $url = url for which the thumbnail must be found.
1717// $href = if provided, this URL will be followed instead of $url
1718// Returns '' if no thumbnail available.
1719function thumbnail($url,$href=false)
1720{
1721 $t = computeThumbnail($url,$href);
1722 if (count($t)==0) return ''; // Empty array = no thumbnail for this URL.
1723
1724 $html='<a href="'.htmlspecialchars($t['href']).'"><img src="'.htmlspecialchars($t['src']).'"';
1725 if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"';
1726 if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
1727 if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"';
1728 if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"';
1729 $html.='></a>';
1730 return $html;
1731}
1732
1601 1733
1734// Returns the HTML code to display a thumbnail for a link
1735// for the picture wall (using lazy image loading)
1736// Understands various services (youtube.com...)
1737// Input: $url = url for which the thumbnail must be found.
1738// $href = if provided, this URL will be followed instead of $url
1739// Returns '' if no thumbnail available.
1740function lazyThumbnail($url,$href=false)
1741{
1742 $t = computeThumbnail($url,$href);
1743 if (count($t)==0) return ''; // Empty array = no thumbnail for this URL.
1744
1745 $html='<a href="'.htmlspecialchars($t['href']).'">';
1746
1747 // Lazy image (only loaded by javascript when in the viewport).
1748 $html.='<img class="lazyimage" src="#" data-original="'.htmlspecialchars($t['src']).'"';
1749 if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"';
1750 if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
1751 if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"';
1752 if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"';
1753 $html.='>';
1754
1755 // No-javascript fallback:
1756 $html.='<noscript><img src="'.htmlspecialchars($t['src']).'"';
1757 if (!empty($t['width'])) $html.=' width="'.htmlspecialchars($t['width']).'"';
1758 if (!empty($t['height'])) $html.=' height="'.htmlspecialchars($t['height']).'"';
1759 if (!empty($t['style'])) $html.=' style="'.htmlspecialchars($t['style']).'"';
1760 if (!empty($t['alt'])) $html.=' alt="'.htmlspecialchars($t['alt']).'"';
1761 $html.='></noscript></a>';
1762
1763 return $html;
1602} 1764}
1603 1765
1766
1604// ----------------------------------------------------------------------------------------------- 1767// -----------------------------------------------------------------------------------------------
1605// Installation 1768// Installation
1606// This function should NEVER be called if the file data/config.php exists. 1769// This function should NEVER be called if the file data/config.php exists.
@@ -1861,11 +2024,11 @@ function genThumbnail()
1861 // The thumbnail for TED talks is located in the <link rel="image_src" [...]> tag on that page 2024 // The thumbnail for TED talks is located in the <link rel="image_src" [...]> tag on that page
1862 // http://www.ted.com/talks/mikko_hypponen_fighting_viruses_defending_the_net.html 2025 // http://www.ted.com/talks/mikko_hypponen_fighting_viruses_defending_the_net.html
1863 // <link rel="image_src" href="http://images.ted.com/images/ted/28bced335898ba54d4441809c5b1112ffaf36781_389x292.jpg" /> 2026 // <link rel="image_src" href="http://images.ted.com/images/ted/28bced335898ba54d4441809c5b1112ffaf36781_389x292.jpg" />
1864 list($httpstatus,$headers,$data) = getHTTP($url,5); 2027 list($httpstatus,$headers,$data) = getHTTP($url,5);
1865 if (strpos($httpstatus,'200 OK')!==false) 2028 if (strpos($httpstatus,'200 OK')!==false)
1866 { 2029 {
1867 // Extract the link to the thumbnail 2030 // Extract the link to the thumbnail
1868 preg_match('!link rel="image_src" href="(http://images.ted.com/images/ted/.+_\d+x\d+\.jpg)[^s]!',$data,$matches); 2031 preg_match('!link rel="image_src" href="(http://images.ted.com/images/ted/.+_\d+x\d+\.jpg)"!',$data,$matches);
1869 if (!empty($matches[1])) 2032 if (!empty($matches[1]))
1870 { // Let's download the image. 2033 { // Let's download the image.
1871 $imageurl=$matches[1]; 2034 $imageurl=$matches[1];
@@ -1982,6 +2145,7 @@ if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=g
1982$LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in). 2145$LINKSDB=new linkdb(isLoggedIn() || $GLOBALS['config']['OPEN_SHAARLI']); // Read links from database (and filter private links if used it not logged in).
1983if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'ws=')) { processWS(); exit; } // Webservices (for jQuery/jQueryUI) 2146if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'ws=')) { processWS(); exit; } // Webservices (for jQuery/jQueryUI)
1984if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=$GLOBALS['config']['LINKS_PER_PAGE']; 2147if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=$GLOBALS['config']['LINKS_PER_PAGE'];
2148if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=dailyrss')) { showDailyRSS(); exit; }
1985if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; } 2149if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; }
1986if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; } 2150if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; }
1987renderPage(); 2151renderPage();