From: Seb Sauvage Date: Thu, 17 Nov 2011 20:46:34 +0000 (+0100) Subject: Version 0.0.28 beta: X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;ds=sidebyside;h=6d946e78bfca94ac89494e84db3746473867c5ff;p=github%2Fshaarli%2FShaarli.git Version 0.0.28 beta: - Changed: New Shaarli theme and logo by Idle (http://www.idleman.fr/blog/?p=469) - Changed: In picture wall, pictures point to Shaarli permalink instead of final URL. This way, users can read the description. - Corrected: In RSS/ATOM feeds, guid and link URL of permalinks are now proper absolute URLs. - Added: In RSS/ATOM feeds, URLs are now clickable. - Changed: http_parse_headers() function renamed to http_parse_headers_shaarli() to prevent name collision with some php extensions. - Corrected: Thumbnails removed for imgur.com/a/ URLs (Thumbnails are not available for albums on imgur). - Corrected: Shaarli now correctly only tries to get thumbnails for vimeo video URLs. - Corrected: A bug in imgur.com URLs handling would cause some thumbnails not to appear. This has been corrected. You should see more thumbnails now. - Added: Thumbnail support for youtu.be URLs (YouTube short url service). - Added: PubSubHub protocol support (from http://aldarone.fr/les-flux-rss-shaarli-et-pubsubhubbub/). Warning: This was not tested. You need to set your hub $ - Corrected: The search engine would not return a result if the word to search was the first in description. - Corrected: Extracted title is now correct if the page has two title html tags. - Added: RSS and ATOM feeds now also contain tags (in category tags, as per their respective specifications). --- diff --git a/images/calendar.png b/images/calendar.png new file mode 100644 index 00000000..65891385 Binary files /dev/null and b/images/calendar.png differ diff --git a/images/favicon.ico b/images/favicon.ico new file mode 100644 index 00000000..c8b043b4 Binary files /dev/null and b/images/favicon.ico differ diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 00000000..20989288 Binary files /dev/null and b/images/logo.png differ diff --git a/images/tag_blue.png b/images/tag_blue.png new file mode 100644 index 00000000..9757fc6e Binary files /dev/null and b/images/tag_blue.png differ diff --git a/index.php b/index.php index 801108b8..daafb1db 100644 --- a/index.php +++ b/index.php @@ -1,5 +1,5 @@ publish_update($topic_url); + } +} + // ------------------------------------------------------------------------------------------ // Session management define('INACTIVITY_TIMEOUT',3600); // (in seconds). If the user does not access any page within this time, his/her session is considered expired. @@ -378,13 +396,13 @@ function linkdate2locale($linkdate) } // Parse HTTP response headers and return an associative array. -function http_parse_headers( $headers ) +function http_parse_headers_shaarli( $headers ) { $res=array(); foreach($headers as $header) { $i = strpos($header,': '); - if ($i) + if ($i!==false) { $key=substr($header,0,$i); $value=substr($header,$i+2,strlen($header)-$i-2); @@ -401,7 +419,7 @@ function http_parse_headers( $headers ) [1] = associative array containing HTTP response headers (eg. echo getHTTP($url)[1]['Content-Type']) [2] = data Example: list($httpstatus,$headers,$data) = getHTTP('http://sebauvage.net/'); - if (strpos($httpstatus,'200 OK')) + if (strpos($httpstatus,'200 OK')!==false) echo 'Data type: '.htmlspecialchars($headers['Content-Type']); else echo 'There was an error: '.htmlspecialchars($httpstatus) @@ -415,7 +433,7 @@ function getHTTP($url,$timeout=30) $data=file_get_contents($url,false,$context,-1, 4000000); // We download at most 4 Mb from source. if (!$data) { $lasterror=error_get_last(); return array($lasterror['message'],array(),''); } $httpStatus=$http_response_header[0]; // eg. "HTTP/1.1 200 OK" - $responseHeaders=http_parse_headers($http_response_header); + $responseHeaders=http_parse_headers_shaarli($http_response_header); return array($httpStatus,$responseHeaders,$data); } catch (Exception $e) // getHTTP *can* fail silentely (we don't care if the title cannot be fetched) @@ -428,7 +446,7 @@ function getHTTP($url,$timeout=30) // (Returns an empty string if not found.) function html_extract_title($html) { - return preg_match('!(.*)!is', $html, $matches) ? trim(str_replace("\n",' ', $matches[1])) : '' ; + return preg_match('!(.*?)!is', $html, $matches) ? trim(str_replace("\n",' ', $matches[1])) : '' ; } // ------------------------------------------------------------------------------------------ @@ -574,7 +592,10 @@ class linkdb implements Iterator, Countable, ArrayAccess $s = strtolower($searchterms); foreach($this->links as $l) { - $found=strpos(strtolower($l['title']),$s) || strpos(strtolower($l['description']),$s) || strpos(strtolower($l['url']),$s) || strpos(strtolower($l['tags']),$s); + $found= (strpos(strtolower($l['title']),$s)!==false) + || (strpos(strtolower($l['description']),$s)!==false) + || (strpos(strtolower($l['url']),$s)!==false) + || (strpos(strtolower($l['tags']),$s)!==false); if ($found) $filtered[$l['linkdate']] = $l; } krsort($filtered); @@ -644,16 +665,29 @@ function showRSS() $pageaddr=htmlspecialchars(serverUrl().$_SERVER["SCRIPT_NAME"]); echo ''; echo ''.htmlspecialchars($GLOBALS['title']).''.$pageaddr.''; - echo 'Shared links'.$pageaddr.''."\n\n"; + echo 'Shared linksen-en'.$pageaddr.''."\n\n"; + if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) + { + echo ''; + echo ''; + echo ''; + echo ''; + } $i=0; $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // No, I can't use array_keys(). while ($i<50 && $i'.htmlspecialchars($link['title']).''.htmlspecialchars($link['url']).''.htmlspecialchars($link['url']).''; - if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo ''.htmlspecialchars($rfc822date).''; - echo ''."\n"; + $absurl = htmlspecialchars($link['url']); + if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute + echo ''.htmlspecialchars($link['title']).''.$absurl.''.$absurl.''; + if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) echo ''.htmlspecialchars($rfc822date)."\n"; + if ($link['tags']!='') // Adding tags to each RSS entry (as mentioned in RSS specification) + { + foreach(explode(' ',$link['tags']) as $tag) { echo ''.htmlspecialchars($tag).''."\n"; } + } + echo ''."\n\n"; $i++; } echo ''; @@ -683,15 +717,29 @@ function showATOM() $link = $linksToDisplay[$keys[$i]]; $iso8601date = linkdate2iso8601($link['linkdate']); $latestDate = max($latestDate,$iso8601date); - $entries.=''.htmlspecialchars($link['title']).''.htmlspecialchars($link['url']).''; + $absurl = htmlspecialchars($link['url']); + if (startsWith($absurl,'?')) $absurl=$pageaddr.$absurl; // make permalink URL absolute + $entries.=''.htmlspecialchars($link['title']).''.$absurl.''; if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $entries.=''.htmlspecialchars($iso8601date).''; - $entries.=''.nl2br(htmlspecialchars($link['description'])).''."\n"; + $entries.=''.nl2br(text2clickable(htmlspecialchars($link['description'])))."\n"; + if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification) + { + foreach(explode(' ',$link['tags']) as $tag) + { $entries.=''."\n"; } + } + $entries.="\n"; $i++; } $feed=''; $feed.=''.htmlspecialchars($GLOBALS['title']).''; if (!$GLOBALS['config']['HIDE_TIMESTAMPS'] || isLoggedIn()) $feed.=''.htmlspecialchars($latestDate).''; - $feed.=''; + $feed.=''; + if (!empty($GLOBALS['config']['PUBSUBHUB_URL'])) + { + $feed.=''; + $feed.=''; + $feed.=''; + } $feed.=''.htmlspecialchars($pageaddr).''; $feed.=''.htmlspecialchars($pageaddr).''."\n\n"; // Yes, I know I should use a real IRI (RFC3987), but the site URL will do. $feed.=$entries; @@ -747,13 +795,14 @@ function renderPage() elseif (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); else $linksToDisplay = $LINKSDB; $body=''; + foreach($linksToDisplay as $link) { - $thumb=thumbnail($link['url']); + $href='?'.htmlspecialchars(smallhash($link['linkdate']),ENT_QUOTES); + $thumb=thumbnail($link['url'],$href); if ($thumb!='') { - $url=htmlspecialchars($link['url'],ENT_QUOTES); - $body.=''; + $body.=''; } } @@ -831,15 +880,15 @@ function renderPage() // Show login screen, then redirect to ?post=... if (isset($_GET['post'])) { - header('Location: ?do=login&post='.urlencode($_GET['post']).(isset($_GET['title'])?'&title='.urlencode($_GET['title']):'').(isset($_GET['source'])?'&source='.urlencode($_GET['source']):'')); // Redirect to login page, then back to post link. + header('Location: ?do=login&post='.urlencode($_GET['post']).(iset($_GET['title'])?'&title='.urlencode($_GET['title']):'').(isset($_GET['source'])?'&source='.urlencode($_GET['source']):'')); // Redirect to login page, then back to post link. exit; } // Show search form and display list of links. $searchform=<< -
-
+
+
HTML; $data = array('pageheader'=>$searchform,'body'=>templateLinkList(),'onload'=>''); @@ -856,13 +905,13 @@ HTML; // The javascript code for the bookmarklet: $changepwd = ($GLOBALS['config']['OPEN_SHAARLI'] ? '' : 'Change password - Change your password.

' ); $toolbar= <<
+

{$changepwd} Configure your Shaarli - Change Title, timezone...

Rename/delete tags - Rename or delete a tag in all links.

Import - Import Netscape html bookmarks (as exported from Firefox, Chrome, Opera, delicious...)

Export - Export Netscape html bookmarks (which can be imported in Firefox, Chrome, Opera, delicious...)

- Shaare link - Drag this link to your bookmarks toolbar (or right-click it and choose Bookmark This Link....). Then click "Shaare link" button in any page you want to share.

+ Shaare link - Drag this link to your bookmarks toolbar (or right-click it and choose Bookmark This Link....). Then click "Shaare link" button in any page you want to share.

HTML; $data = array('pageheader'=>$toolbar,'body'=>'','onload'=>''); @@ -892,7 +941,7 @@ HTML; { $token = getToken(); $changepwdform= << +
Old password:     New password: @@ -951,7 +1000,7 @@ HTML; { $token = getToken(); $changetagform = << + Tag: @@ -976,6 +1025,7 @@ HTML; $LINKSDB[$key]=$value; } $LINKSDB->savedb(); // save to disk + pubsubhub(); invalidateCaches(); echo ''; exit; @@ -1004,7 +1054,7 @@ HTML; if (startswith($_SERVER["QUERY_STRING"],'do=addlink')) { $onload = 'onload="document.addform.post.focus();"'; - $addform= '
'; + $addform= '
'; $data = array('pageheader'=>$addform,'body'=>'','onload'=>$onload); templatePage($data); exit; @@ -1075,9 +1125,9 @@ HTML; $url=$_GET['post']; // We remove the annoying parameters added by FeedBurner and GoogleFeedProxy (?utm_source=...) - $i=strpos($url,'&utm_source='); if ($i) $url=substr($url,0,$i); - $i=strpos($url,'?utm_source='); if ($i) $url=substr($url,0,$i); - $i=strpos($url,'#xtor=RSS-'); if ($i) $url=substr($url,0,$i); + $i=strpos($url,'&utm_source='); if ($i!==false) $url=substr($url,0,$i); + $i=strpos($url,'?utm_source='); if ($i!==false) $url=substr($url,0,$i); + $i=strpos($url,'#xtor=RSS-'); if ($i!==false) $url=substr($url,0,$i); $link_is_new = false; $link = $LINKSDB->getLinkFromUrl($url); // Check if URL is not already in database (in this case, we will edit the existing link) @@ -1093,7 +1143,7 @@ HTML; { list($status,$headers,$data) = getHTTP($url,4); // Short timeout to keep the application responsive. // FIXME: Decode charset according to specified in either 1) HTTP response headers or 2) in html - if (strpos($status,'200 OK')) $title=html_entity_decode(html_extract_title($data),ENT_QUOTES,'UTF-8'); + if (strpos($status,'200 OK')!==false) $title=html_entity_decode(html_extract_title($data),ENT_QUOTES,'UTF-8'); } if ($url=='') $url='?'.smallHash($linkdate); // In case of empty URL, this is just a text (with a link that point to itself) $link = array('linkdate'=>$linkdate,'title'=>$title,'url'=>$url,'description'=>$description,'tags'=>$tags,'private'=>0); @@ -1110,7 +1160,7 @@ HTML; if (empty($_GET['what'])) { $toolbar= <<
+
Export all - Export all links

Export public - Export public links only

Export private - Export private links only

@@ -1172,9 +1222,9 @@ HTML; $maxfilesize=getMaxFileSize(); $onload = 'onload="document.uploadform.filetoupload.focus();"'; $uploadform=<< +
Import Netscape html bookmarks (as exported from Firefox/Chrome/Opera/delicious/diigo...) (Max: {$maxfilesize} bytes). - + @@ -1192,8 +1242,8 @@ HTML; // -------- Otherwise, simply display search form and links: $searchform=<< - -
+
+
HTML; $data = array('pageheader'=>$searchform,'body'=>templateLinkList(),'onload'=>''); @@ -1362,7 +1412,8 @@ function templateLinkList() $link = $linksToDisplay[$keys[$i]]; $description=text2clickable(htmlspecialchars($link['description'])); $title=$link['title']; - $classprivate = ($link['private']==0 ? '' : 'class="private"'); + $classLi = $i%2!=0 ? '' : 'class="publicLinkHightLight"'; + $classprivate = ($link['private']==0 ? $classLi : 'class="private"'); if (isLoggedIn()) $actions='
'; $tags=''; if ($link['tags']!='') @@ -1389,19 +1440,24 @@ function templateLinkList() $linksperpage = << Links per page: 20 50 100 -
+
HTML; $paging = '
'.$linksperpage.$paging.'
'; $linklist=''; return $linklist; } -// Returns the HTML code to display a thumbnail for a link. +// Returns the HTML code to display a thumbnail for a link +// with a link to the original URL. // Understands various services (youtube.com...) -function thumbnail($url) +// Input: $url = url for which the thumbnail must be found. +// $href = if provided, this URL will be followed instead of $url +function thumbnail($url,$href=false) { if (!$GLOBALS['config']['ENABLE_THUMBNAILS']) return ''; + if ($href==false) $href=$url; + // For most hosts, the URL of the thumbnail can be easily deduced from the URL of the link. // (eg. http://www.youtube.com/watch?v=spVypYk4kto ---> http://img.youtube.com/vi/spVypYk4kto/default.jpg ) // ^^^^^^^^^^^ ^^^^^^^^^^^ @@ -1409,26 +1465,32 @@ function thumbnail($url) if ($domain=='youtube.com' || $domain=='www.youtube.com') { parse_str(parse_url($url,PHP_URL_QUERY), $params); // Extract video ID and get thumbnail - if (!empty($params['v'])) return ''; + if (!empty($params['v'])) return ''; } + if ($domain=='youtu.be') // Youtube short links + { + $path = parse_url($url,PHP_URL_PATH); + return ''; + } if ($domain=='imgur.com') { $path = parse_url($url,PHP_URL_PATH); - if (strpos($path,'/r/')==0) return ''; - if (strpos($path,'/gallery/')==0) return ''; - if (substr_count($path,'/')==1) return ''; + if (startsWith($path,'/a/')) return ''; // Thumbnails for albums are not available. + if (startsWith($path,'/r/')) return ''; + if (startsWith($path,'/gallery/')) return ''; + if (substr_count($path,'/')==1) return ''; } if ($domain=='i.imgur.com') { $pi = pathinfo(parse_url($url,PHP_URL_PATH)); - if (!empty($pi['filename'])) return ''; + if (!empty($pi['filename'])) return ''; } if ($domain=='dailymotion.com' || $domain=='www.dailymotion.com') { - if (strpos($url,'dailymotion.com/video/')) + if (strpos($url,'dailymotion.com/video/')!==false) { $thumburl=str_replace('dailymotion.com/video/','dailymotion.com/thumbnail/video/',$url); - return ''; + return ''; } } if (endsWith($domain,'.imageshack.us')) @@ -1437,11 +1499,10 @@ function thumbnail($url) if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') { $thumburl = substr($url,0,strlen($url)-strlen($ext)).'th.'.$ext; - return ''; + return ''; } } - - + // Some other hosts are SLOW AS HELL and usually require an extra HTTP request to get the thumbnail URL. // So we deport the thumbnail generation in order not to slow down page generation // (and we also cache the thumbnail) @@ -1450,8 +1511,13 @@ function thumbnail($url) if ($domain=='flickr.com' || endsWith($domain,'.flickr.com') || $domain=='vimeo.com') { + if ($domain=='vimeo.com') + { // Make sure this vimeo url points to a video (/xxx... where xxx is numeric) + $path = parse_url($url,PHP_URL_PATH); + if (!preg_match('!/\d+.+?!',$path)) return ''; // This is not a single video URL. + } $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) - return ''; + return ''; } // For all other, we try to make a thumbnail of links ending with .jpg/jpeg/png/gif @@ -1461,7 +1527,7 @@ function thumbnail($url) if ($ext=='jpg' || $ext=='jpeg' || $ext=='png' || $ext=='gif') { $sign = hash_hmac('sha256', $url, $GLOBALS['salt']); // We use the salt to sign data (it's random, secret, and specific to each installation) - return ''; + return ''; } return ''; // No thumbnail. @@ -1527,12 +1593,13 @@ JS; {$pagetitle} + {$jsincludes} {$newversion} -