aboutsummaryrefslogtreecommitdiffhomepage
path: root/index.php
diff options
context:
space:
mode:
authorSeb Sauvage <sebsauvage@sebsauvage.net>2012-01-25 10:24:44 +0100
committerEmilien Klein <emilien@klein.st>2012-01-25 10:24:44 +0100
commit51788ab8bacfe5fe951531ef545913ff6983f1b8 (patch)
tree225b21a815893ed28588e6e3199f5a0020eccbe2 /index.php
parentc2f6c2680330ad40f80a4cfe68388ece8dd313ec (diff)
downloadShaarli-51788ab8bacfe5fe951531ef545913ff6983f1b8.tar.gz
Shaarli-51788ab8bacfe5fe951531ef545913ff6983f1b8.tar.zst
Shaarli-51788ab8bacfe5fe951531ef545913ff6983f1b8.zip
Version 0.0.34 beta:
- Corrected: In link edition, you can now click the word “Private” to check the box. - Corrected: Clicking a tag would not work properly if the tag contained special characters (like +). - Corrected: Added proper jQuery licence (shame on me). - Changed: Upgraded bundled versions of jQuery (1.7.1) and jQuery UI (1.8.17). - Changed: Upgraded bundled version of RainTPL (2.7). - Changed: Changed HTTPS detection code. - Added: There is now a QR-Code of each permalink to easily open a link on your smartphone. - Added: Protocols file: and apt: are now also converted to clickable links (patch by Francis Chavanon) - Added: Thumbnail support for http://xkcd.com/ (patch by Emilien Klein). [r31] - Added: Thumbnail support for http://pix.toile-libre.org/ - Added: Well I had some mercy for users with antique browsers (IE) which do not have support for gradients: I added a few background-color. - Added: First version of the “Shaarli Daily”, a page showing all links of a specific day. By default, you see the links of the previous day. There is still work to do on this page (error checking, better navigation (calendar?), RSS feed, CSS for mobile and printing…)
Diffstat (limited to 'index.php')
-rw-r--r--index.php128
1 files changed, 106 insertions, 22 deletions
diff --git a/index.php b/index.php
index ba3d9c34..46a8c902 100644
--- a/index.php
+++ b/index.php
@@ -1,5 +1,5 @@
1<?php 1<?php
2// Shaarli 0.0.33 beta - Shaare your links... 2// Shaarli 0.0.34 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.33 beta'); 61define('shaarli_version','0.0.34 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'])
@@ -141,11 +141,12 @@ function smallHash($text)
141 return $t; 141 return $t;
142} 142}
143 143
144// In a string, converts urls to clickable links.
144// Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722 145// Function inspired from http://www.php.net/manual/en/function.preg-replace.php#85722
145function text2clickable($url) 146function text2clickable($url)
146{ 147{
147 $redir = empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector']; 148 $redir = empty($GLOBALS['redirector']) ? '' : $GLOBALS['redirector'];
148 return preg_replace('!((?:https?|ftp)://\S+[[:alnum:]]/?)!si','<a href="'.$redir.'$1" rel="nofollow">$1</a>',$url); 149 return preg_replace('!(((?:https?|ftp|file)://|apt:)\S+[[:alnum:]]/?)!si','<a href="'.$redir.'$1" rel="nofollow">$1</a>',$url);
149} 150}
150 151
151// This function inserts &nbsp; where relevant so that multiple spaces are properly displayed in HTML 152// This function inserts &nbsp; where relevant so that multiple spaces are properly displayed in HTML
@@ -336,13 +337,15 @@ if (isset($_POST['login']))
336// You can append $_SERVER['SCRIPT_NAME'] to get the current script URL. 337// You can append $_SERVER['SCRIPT_NAME'] to get the current script URL.
337function serverUrl() 338function serverUrl()
338{ 339{
339 $serverport = ($_SERVER["SERVER_PORT"]=='80' || (!empty($_SERVER['HTTPS']) && $_SERVER["SERVER_PORT"]=='443') ? '' : ':'.$_SERVER["SERVER_PORT"]); 340 $https = (!empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS'])=='on')) || $_SERVER["SERVER_PORT"]=='443'; // HTTPS detection.
340 return 'http'.(!empty($_SERVER['HTTPS'])?'s':'').'://'.$_SERVER["SERVER_NAME"].$serverport; 341 $serverport = ($_SERVER["SERVER_PORT"]=='80' || ($https && $_SERVER["SERVER_PORT"]=='443') ? '' : ':'.$_SERVER["SERVER_PORT"]);
342 return 'http'.($https?'s':'').'://'.$_SERVER["SERVER_NAME"].$serverport;
341} 343}
342 344
345// Returns the absolute URL of current script.
343function indexUrl() 346function indexUrl()
344{ 347{
345 return serverUrl() . ($_SERVER["SCRIPT_NAME"] == '/index.php' ? '' : $_SERVER["SCRIPT_NAME"]); 348 return serverUrl() . ($_SERVER["SCRIPT_NAME"] == '/index.php' ? '/' : $_SERVER["SCRIPT_NAME"]);
346} 349}
347 350
348// Convert post_max_size/upload_max_filesize (eg.'16M') parameters to bytes. 351// Convert post_max_size/upload_max_filesize (eg.'16M') parameters to bytes.
@@ -526,6 +529,7 @@ class pageBuilder
526 $this->tpl->assign('searchcrits',$searchcrits); 529 $this->tpl->assign('searchcrits',$searchcrits);
527 $this->tpl->assign('source',indexUrl()); 530 $this->tpl->assign('source',indexUrl());
528 $this->tpl->assign('version',shaarli_version); 531 $this->tpl->assign('version',shaarli_version);
532 $this->tpl->assign('scripturl',indexUrl());
529 $this->tpl->assign('pagetitle','Shaarli'); 533 $this->tpl->assign('pagetitle','Shaarli');
530 if (!empty($GLOBALS['title'])) $this->tpl->assign('pagetitle',$GLOBALS['title']); 534 if (!empty($GLOBALS['title'])) $this->tpl->assign('pagetitle',$GLOBALS['title']);
531 if (!empty($GLOBALS['pagetitle'])) $this->tpl->assign('pagetitle',$GLOBALS['pagetitle']); 535 if (!empty($GLOBALS['pagetitle'])) $this->tpl->assign('pagetitle',$GLOBALS['pagetitle']);
@@ -557,6 +561,14 @@ class pageBuilder
557 echo $mylinks['20110826_161819']['title']; 561 echo $mylinks['20110826_161819']['title'];
558 foreach($mylinks as $link) 562 foreach($mylinks as $link)
559 echo $link['title'].' at url '.$link['url'].' ; description:'.$link['description']; 563 echo $link['title'].' at url '.$link['url'].' ; description:'.$link['description'];
564
565 Available keys:
566 title : Title of the link
567 url : URL of the link. Can be absolute or relative. Relative URLs are permalinks (eg.'?m-ukcw')
568 description : description of the entry
569 private : Is this link private ? 0=no, other value=yes
570 linkdate : date of the creation of this entry, in the form YYYYMMDD_HHMMSS (eg.'20110914_192317')
571 tags : tags attached to this entry (separated by spaces)
560 572
561 We implement 3 interfaces: 573 We implement 3 interfaces:
562 - ArrayAccess so that this object behaves like an associative array. 574 - ArrayAccess so that this object behaves like an associative array.
@@ -694,6 +706,19 @@ class linkdb implements Iterator, Countable, ArrayAccess
694 return $filtered; 706 return $filtered;
695 } 707 }
696 708
709 // Filter by day. Day must be in the form 'YYYYMMDD' (eg. '20120125')
710 // Sort order is: older articles first.
711 // eg. print_r($mydb->filterDay('20120125'));
712 public function filterDay($day)
713 {
714 $filtered=array();
715 foreach($this->links as $l)
716 {
717 if (startsWith($l['linkdate'],$day)) $filtered[$l['linkdate']] = $l;
718 }
719 ksort($filtered);
720 return $filtered;
721 }
697 // Filter by smallHash. 722 // Filter by smallHash.
698 // Only 1 article is returned. 723 // Only 1 article is returned.
699 public function filterSmallHash($smallHash) 724 public function filterSmallHash($smallHash)
@@ -934,7 +959,55 @@ function renderPage()
934 header('Location: '.(empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER'])); 959 header('Location: '.(empty($_SERVER['HTTP_REFERER'])?'?':$_SERVER['HTTP_REFERER']));
935 exit; 960 exit;
936 } 961 }
937 962
963 // --------- Daily (all links form a specific day) ----------------------
964 if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=daily'))
965 {
966 $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD.
967 if (isset($_GET['day'])) $day=$_GET['day'];
968
969 $previousday = Date('Ymd',strtotime('-1 day',strtotime($day)));
970 $nextday = Date('Ymd',strtotime('+1 day',strtotime($day)));
971
972 $linksToDisplay=$LINKSDB->filterDay($day);
973 // We pre-format some fields for proper output.
974 foreach($linksToDisplay as $key=>$link)
975 {
976 $linksToDisplay[$key]['taglist']=explode(' ',$link['tags']);
977 $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable(htmlspecialchars($link['description']))));
978 $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']);
979 }
980
981 /* We need to spread the articles on 3 columns.
982 I did not want to use a javascript lib like http://masonry.desandro.com/
983 so I manually spread entries with a simple method: I roughly evaluate the
984 height of a div according to title and description length.
985 */
986 $columns=array(array(),array(),array()); // Entries to display, for each column.
987 $fill=array(0,0,0); // Rough estimate of columns fill.
988 foreach($linksToDisplay as $key=>$link)
989 {
990 // Roughly estimate length of entry (by counting characters)
991 $length=strlen($link['title'])+strlen($link['description']);
992 if ($link['thumbnail']) $length +=100; // 1 thumbnails roughly take as much space as 100 words;
993
994 // Then put in column which is the less filled:
995 $smallest=min($fill); // find smallest value in array.
996 $index=array_search($smallest,$fill); // find index of this smallest value.
997 array_push($columns[$index],$link); // Put entry in this column.
998 $fill[$index]+=$length;
999 }
1000 $PAGE = new pageBuilder;
1001 $PAGE->assign('linksToDisplay',$linksToDisplay);
1002 $PAGE->assign('col1',$columns[0]);
1003 $PAGE->assign('col2',$columns[1]);
1004 $PAGE->assign('col3',$columns[2]);
1005 $PAGE->assign('day',utf8_encode(strftime('%A %d, %B %Y',linkdate2timestamp($day.'_000000'))));
1006 $PAGE->assign('previousday',$previousday);
1007 $PAGE->assign('nextday',$nextday);
1008 $PAGE->renderPage('daily');
1009 exit;
1010 }
938 1011
939 // -------- Handle other actions allowed for non-logged in users: 1012 // -------- Handle other actions allowed for non-logged in users:
940 if (!isLoggedIn()) 1013 if (!isLoggedIn())
@@ -1424,6 +1497,7 @@ function buildLinkList($PAGE)
1424// Understands various services (youtube.com...) 1497// Understands various services (youtube.com...)
1425// Input: $url = url for which the thumbnail must be found. 1498// Input: $url = url for which the thumbnail must be found.
1426// $href = if provided, this URL will be followed instead of $url 1499// $href = if provided, this URL will be followed instead of $url
1500// Returns '' if no thumbnail available.
1427function thumbnail($url,$href=false) 1501function thumbnail($url,$href=false)
1428{ 1502{
1429 if (!$GLOBALS['config']['ENABLE_THUMBNAILS']) return ''; 1503 if (!$GLOBALS['config']['ENABLE_THUMBNAILS']) return '';
@@ -1437,32 +1511,38 @@ function thumbnail($url,$href=false)
1437 if ($domain=='youtube.com' || $domain=='www.youtube.com') 1511 if ($domain=='youtube.com' || $domain=='www.youtube.com')
1438 { 1512 {
1439 parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail 1513 parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail
1440 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"></a>'; 1514 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>';
1441 } 1515 }
1442 if ($domain=='youtu.be') // Youtube short links 1516 if ($domain=='youtu.be') // Youtube short links
1443 { 1517 {
1444 $path = parse_url($url,PHP_URL_PATH); 1518 $path = parse_url($url,PHP_URL_PATH);
1445 return '<a href="'.htmlspecialchars($href).'"><img src="http://img.youtube.com/vi'.htmlspecialchars($path).'/default.jpg" width="120" height="90"></a>'; 1519 return '<a href="'.htmlspecialchars($href).'"><img src="http://img.youtube.com/vi'.htmlspecialchars($path).'/default.jpg" width="120" height="90" alt="YouTube thumbnail"></a>';
1446 } 1520 }
1521 if ($domain=='pix.toile-libre.org') // pix.toile-libre.org image hosting
1522 {
1523 parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract image filename.
1524 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>';
1525 }
1526
1447 if ($domain=='imgur.com') 1527 if ($domain=='imgur.com')
1448 { 1528 {
1449 $path = parse_url($url,PHP_URL_PATH); 1529 $path = parse_url($url,PHP_URL_PATH);
1450 if (startsWith($path,'/a/')) return ''; // Thumbnails for albums are not available. 1530 if (startsWith($path,'/a/')) return ''; // Thumbnails for albums are not available.
1451 if (startsWith($path,'/r/')) return '<a href="'.htmlspecialchars($href).'"><img src="http://i.imgur.com/'.htmlspecialchars(basename($path)).'s.jpg" width="90" height="90"></a>'; 1531 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>';
1452 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"></a>'; 1532 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>';
1453 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"></a>'; 1533 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>';
1454 } 1534 }
1455 if ($domain=='i.imgur.com') 1535 if ($domain=='i.imgur.com')
1456 { 1536 {
1457 $pi = pathinfo(parse_url($url,PHP_URL_PATH)); 1537 $pi = pathinfo(parse_url($url,PHP_URL_PATH));
1458 if (!empty($pi['filename'])) return '<a href="'.htmlspecialchars($href).'"><img src="http://i.imgur.com/'.htmlspecialchars($pi['filename']).'s.jpg" width="90" height="90"></a>'; 1538 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>';
1459 } 1539 }
1460 if ($domain=='dailymotion.com' || $domain=='www.dailymotion.com') 1540 if ($domain=='dailymotion.com' || $domain=='www.dailymotion.com')
1461 { 1541 {
1462 if (strpos($url,'dailymotion.com/video/')!==false) 1542 if (strpos($url,'dailymotion.com/video/')!==false)
1463 { 1543 {
1464 $thumburl=str_replace('dailymotion.com/video/','dailymotion.com/thumbnail/video/',$url); 1544 $thumburl=str_replace('dailymotion.com/video/','dailymotion.com/thumbnail/video/',$url);
1465 return '<a href="'.htmlspecialchars($href).'"><img src="'.htmlspecialchars($thumburl).'" width="120" style="height:auto;"></a>'; 1545 return '<a href="'.htmlspecialchars($href).'"><img src="'.htmlspecialchars($thumburl).'" width="120" style="height:auto;" alt="DailyMotion thumbnail"></a>';
1466 } 1546 }
1467 } 1547 }
1468 if (endsWith($domain,'.imageshack.us')) 1548 if (endsWith($domain,'.imageshack.us'))
@@ -1471,7 +1551,7 @@ function thumbnail($url,$href=false)
1471 if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') 1551 if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif')
1472 { 1552 {
1473 $thumburl = substr($url,0,strlen($url)-strlen($ext)).'th.'.$ext; 1553 $thumburl = substr($url,0,strlen($url)-strlen($ext)).'th.'.$ext;
1474 return '<a href="'.htmlspecialchars($href).'"><img src="'.htmlspecialchars($thumburl).'" width="120" style="height:auto;"></a>'; 1554 return '<a href="'.htmlspecialchars($href).'"><img src="'.htmlspecialchars($thumburl).'" width="120" style="height:auto;" alt="imageshack.us thumbnail"></a>';
1475 } 1555 }
1476 } 1556 }
1477 1557
@@ -1487,11 +1567,15 @@ function thumbnail($url,$href=false)
1487 || $domain=='xkcd.com' || endsWith($domain,'.xkcd.com') 1567 || $domain=='xkcd.com' || endsWith($domain,'.xkcd.com')
1488 ) 1568 )
1489 { 1569 {
1490 if ($domain=='vimeo.com' || $domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) 1570 if ($domain=='vimeo.com')
1491 { // Make sure the url is of the form /xxx... where xxx is numeric 1571 { // Make sure this vimeo url points to a video (/xxx... where xxx is numeric)
1492 // For Vimeo's videos and xkcd's comics 1572 $path = parse_url($url,PHP_URL_PATH);
1573 if (!preg_match('!/\d+.+?!',$path)) return ''; // This is not a single video URL.
1574 }
1575 if ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com'))
1576 { // Make sure this url points to a single comic (/xxx... where xxx is numeric)
1493 $path = parse_url($url,PHP_URL_PATH); 1577 $path = parse_url($url,PHP_URL_PATH);
1494 if (!preg_match('!/\d+.+?!',$path)) return ''; // This is not a single video/comic URL. 1578 if (!preg_match('!/\d+.+?!',$path)) return '';
1495 } 1579 }
1496 if ($domain=='ted.com' || endsWith($domain,'.ted.com')) 1580 if ($domain=='ted.com' || endsWith($domain,'.ted.com'))
1497 { // Make sure this TED url points to a video (/talks/...) 1581 { // Make sure this TED url points to a video (/talks/...)
@@ -1499,7 +1583,7 @@ function thumbnail($url,$href=false)
1499 if ("/talks/" !== substr($path,0,7)) return ''; // This is not a single video URL. 1583 if ("/talks/" !== substr($path,0,7)) return ''; // This is not a single video URL.
1500 } 1584 }
1501 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) 1585 $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation)
1502 return '<a href="'.htmlspecialchars($href).'"><img src="?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url).'" width="120" style="height:auto;"></a>'; 1586 return '<a href="'.htmlspecialchars($href).'"><img src="?do=genthumbnail&hmac='.htmlspecialchars($sign).'&url='.urlencode($url).'" width="120" style="height:auto;" alt="thumbnail"></a>';
1503 } 1587 }
1504 1588
1505 // For all other, we try to make a thumbnail of links ending with .jpg/jpeg/png/gif 1589 // For all other, we try to make a thumbnail of links ending with .jpg/jpeg/png/gif
@@ -1798,7 +1882,7 @@ function genThumbnail()
1798 } 1882 }
1799 } 1883 }
1800 } 1884 }
1801 1885
1802 elseif ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com')) 1886 elseif ($domain=='xkcd.com' || endsWith($domain,'.xkcd.com'))
1803 { 1887 {
1804 // There is no thumbnail available for xkcd comics, so download the whole image and resize it. 1888 // There is no thumbnail available for xkcd comics, so download the whole image and resize it.
@@ -1826,7 +1910,7 @@ function genThumbnail()
1826 } 1910 }
1827 } 1911 }
1828 } 1912 }
1829 } 1913 }
1830 1914
1831 else 1915 else
1832 { 1916 {