diff options
Diffstat (limited to 'index.php')
-rw-r--r-- | index.php | 96 |
1 files changed, 85 insertions, 11 deletions
@@ -1,5 +1,5 @@ | |||
1 | <?php | 1 | <?php |
2 | // Shaarli 0.0.11 beta - Shaare your links... | 2 | // Shaarli 0.0.12 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 |
@@ -15,6 +15,7 @@ define('LINKS_PER_PAGE',20); // Default links per page. | |||
15 | define('IPBANS_FILENAME',DATADIR.'/ipbans.php'); // File storage for failures and bans. | 15 | define('IPBANS_FILENAME',DATADIR.'/ipbans.php'); // File storage for failures and bans. |
16 | define('BAN_AFTER',4); // Ban IP after this many failures. | 16 | define('BAN_AFTER',4); // Ban IP after this many failures. |
17 | define('BAN_DURATION',1800); // Ban duration for IP address after login failures (in seconds) (1800 sec. = 30 minutes) | 17 | define('BAN_DURATION',1800); // Ban duration for IP address after login failures (in seconds) (1800 sec. = 30 minutes) |
18 | define('OPEN_SHAARLI',false); // If true, anyone can add/edit/delete links without having to login | ||
18 | if (get_magic_quotes_gpc()) | 19 | if (get_magic_quotes_gpc()) |
19 | { | 20 | { |
20 | header('Content-Type: text/plain; charset=utf-8'); | 21 | header('Content-Type: text/plain; charset=utf-8'); |
@@ -34,7 +35,7 @@ header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); | |||
34 | header("Cache-Control: no-store, no-cache, must-revalidate"); | 35 | header("Cache-Control: no-store, no-cache, must-revalidate"); |
35 | header("Cache-Control: post-check=0, pre-check=0", false); | 36 | header("Cache-Control: post-check=0, pre-check=0", false); |
36 | header("Pragma: no-cache"); | 37 | header("Pragma: no-cache"); |
37 | define('shaarli_version','0.0.11 beta'); | 38 | define('shaarli_version','0.0.12 beta'); |
38 | if (!is_dir(DATADIR)) { mkdir(DATADIR,0705); chmod(DATADIR,0705); } | 39 | if (!is_dir(DATADIR)) { mkdir(DATADIR,0705); chmod(DATADIR,0705); } |
39 | if (!is_file(DATADIR.'/.htaccess')) { file_put_contents(DATADIR.'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. | 40 | if (!is_file(DATADIR.'/.htaccess')) { file_put_contents(DATADIR.'/.htaccess',"Allow from none\nDeny from all\n"); } // Protect data files. |
40 | if (!is_file(CONFIG_FILE)) install(); | 41 | if (!is_file(CONFIG_FILE)) install(); |
@@ -124,6 +125,8 @@ function check_auth($login,$password) | |||
124 | // Returns true if the user is logged in. | 125 | // Returns true if the user is logged in. |
125 | function isLoggedIn() | 126 | function isLoggedIn() |
126 | { | 127 | { |
128 | if (OPEN_SHAARLI) return true; | ||
129 | |||
127 | // If session does not exist on server side, or IP address has changed, or session has expired, logout. | 130 | // If session does not exist on server side, or IP address has changed, or session has expired, logout. |
128 | if (empty($_SESSION['uid']) || $_SESSION['ip']!=allIPs() || time()>=$_SESSION['expires_on']) | 131 | if (empty($_SESSION['uid']) || $_SESSION['ip']!=allIPs() || time()>=$_SESSION['expires_on']) |
129 | { | 132 | { |
@@ -504,8 +507,20 @@ class linkdb implements Iterator, Countable, ArrayAccess | |||
504 | } | 507 | } |
505 | krsort($filtered); | 508 | krsort($filtered); |
506 | return $filtered; | 509 | return $filtered; |
510 | } | ||
507 | 511 | ||
508 | } | 512 | // Returns the list of all tags |
513 | // Output: associative array key=tags, value=0 | ||
514 | public function allTags() | ||
515 | { | ||
516 | $tags=array(); | ||
517 | foreach($this->links as $link) | ||
518 | foreach(explode(' ',$link['tags']) as $tag) | ||
519 | if (!empty($tag)) $tags[$tag]=0; | ||
520 | ksort($tags); // FIXME: sort by usage ? That would be better. | ||
521 | return $tags; | ||
522 | } | ||
523 | |||
509 | } | 524 | } |
510 | 525 | ||
511 | // ------------------------------------------------------------------------------------------ | 526 | // ------------------------------------------------------------------------------------------ |
@@ -545,6 +560,7 @@ function renderPage() | |||
545 | // -------- Display login form. | 560 | // -------- Display login form. |
546 | if (startswith($_SERVER["QUERY_STRING"],'do=login')) | 561 | if (startswith($_SERVER["QUERY_STRING"],'do=login')) |
547 | { | 562 | { |
563 | if (OPEN_SHAARLI) { header('Location: ?'); exit; } // No need to login for open Shaarli | ||
548 | if (!ban_canLogin()) | 564 | if (!ban_canLogin()) |
549 | { | 565 | { |
550 | $loginform='<div id="headerform">You have been banned from login after too many failed attempts. Try later.</div>'; | 566 | $loginform='<div id="headerform">You have been banned from login after too many failed attempts. Try later.</div>'; |
@@ -907,7 +923,7 @@ function templateEditForm($link,$link_is_new=false) | |||
907 | <i>URL</i><br><input type="text" name="lf_url" value="{$url}" style="width:100%"><br> | 923 | <i>URL</i><br><input type="text" name="lf_url" value="{$url}" style="width:100%"><br> |
908 | <i>Title</i><br><input type="text" name="lf_title" value="{$title}" style="width:100%"><br> | 924 | <i>Title</i><br><input type="text" name="lf_title" value="{$title}" style="width:100%"><br> |
909 | <i>Description</i><br><textarea name="lf_description" rows="4" cols="25" style="width:100%">{$description}</textarea><br> | 925 | <i>Description</i><br><textarea name="lf_description" rows="4" cols="25" style="width:100%">{$description}</textarea><br> |
910 | <i>Tags</i><br><input type="text" name="lf_tags" value="{$tags}" style="width:100%"><br> | 926 | <i>Tags</i><br><input type="text" id="lf_tags" name="lf_tags" value="{$tags}" style="width:100%"><br> |
911 | <input type="checkbox" {$private} style="margin:7 0 10 0;" name="lf_private"> <i>Private</i><br> | 927 | <input type="checkbox" {$private} style="margin:7 0 10 0;" name="lf_private"> <i>Private</i><br> |
912 | <input type="submit" value="Save" name="save_edit" class="bigbutton" style="margin-left:40px;"> | 928 | <input type="submit" value="Save" name="save_edit" class="bigbutton" style="margin-left:40px;"> |
913 | <input type="submit" value="Cancel" name="cancel_edit" class="bigbutton" style="margin-left:40px;"> | 929 | <input type="submit" value="Cancel" name="cancel_edit" class="bigbutton" style="margin-left:40px;"> |
@@ -1005,18 +1021,40 @@ function templatePage($data) | |||
1005 | global $STARTTIME; | 1021 | global $STARTTIME; |
1006 | global $LINKSDB; | 1022 | global $LINKSDB; |
1007 | $shaarli_version = shaarli_version; | 1023 | $shaarli_version = shaarli_version; |
1008 | $linkcount = count($LINKSDB); | 1024 | $linkcount = count($LINKSDB); |
1009 | $menu=(isLoggedIn() ? ' <a href="?do=logout">Logout</a> <a href="?do=tools">Tools</a> <a href="?do=addlink"><b>Add link</b></a>' : ' <a href="?do=login">Login</a>'); | 1025 | $open=''; |
1026 | if (OPEN_SHAARLI) | ||
1027 | { | ||
1028 | $menu=' <a href="?do=tools">Tools</a> <a href="?do=addlink"><b>Add link</b></a>'; | ||
1029 | $open='Open '; | ||
1030 | } | ||
1031 | else | ||
1032 | $menu=(isLoggedIn() ? ' <a href="?do=logout">Logout</a> <a href="?do=tools">Tools</a> <a href="?do=addlink"><b>Add link</b></a>' : ' <a href="?do=login">Login</a>'); | ||
1010 | foreach(array('pageheader','body','onload') as $k) // make sure all required fields exist (put an empty string if not). | 1033 | foreach(array('pageheader','body','onload') as $k) // make sure all required fields exist (put an empty string if not). |
1011 | { | 1034 | { |
1012 | if (!array_key_exists($k,$data)) $data[$k]=''; | 1035 | if (!array_key_exists($k,$data)) $data[$k]=''; |
1013 | } | 1036 | } |
1037 | $jsincludes=''; $jsincludes_bottom = ''; | ||
1038 | if (OPEN_SHAARLI || isLoggedIn()) | ||
1039 | { | ||
1040 | $jsincludes='<script language="JavaScript" src="jquery.min.js"></script><script language="JavaScript" src="jquery-ui.custom.min.js"></script>'; | ||
1041 | $source = serverUrl().$_SERVER['SCRIPT_NAME'].'?ws=tags'; | ||
1042 | $jsincludes_bottom = <<<JS | ||
1043 | <script language="JavaScript"> | ||
1044 | $(document).ready(function() | ||
1045 | { | ||
1046 | $('#lf_tags').autocomplete({source:'{$source}',minLength:0}); | ||
1047 | }); | ||
1048 | </script> | ||
1049 | JS; | ||
1050 | } | ||
1014 | $feedurl=htmlspecialchars(serverUrl().$_SERVER['SCRIPT_NAME'].'?do=rss'); | 1051 | $feedurl=htmlspecialchars(serverUrl().$_SERVER['SCRIPT_NAME'].'?do=rss'); |
1015 | echo <<<HTML | 1052 | echo <<<HTML |
1016 | <html> | 1053 | <html> |
1017 | <head> | 1054 | <head> |
1018 | <title>Shaarli - Let's shaare your links...</title> | 1055 | <title>{$open}Shaarli - Let's shaare your links...</title> |
1019 | <link rel="alternate" type="application/rss+xml" href="{$feedurl}"> | 1056 | <link rel="alternate" type="application/rss+xml" href="{$feedurl}"> |
1057 | {$jsincludes} | ||
1020 | <style type="text/css"> | 1058 | <style type="text/css"> |
1021 | <!-- | 1059 | <!-- |
1022 | /* CSS Reset from Yahoo to cope with browsers CSS inconsistencies. */ | 1060 | /* CSS Reset from Yahoo to cope with browsers CSS inconsistencies. */ |
@@ -1072,12 +1110,17 @@ border-bottom:1px solid #aaa; border-right:1px solid #aaa; } | |||
1072 | .linktag a { color:#777; text-decoration:none; } | 1110 | .linktag a { color:#777; text-decoration:none; } |
1073 | .buttoneditform { display:inline; } | 1111 | .buttoneditform { display:inline; } |
1074 | #footer { font-size:8pt; text-align:center; border-top:1px solid #ddd; color: #888; } | 1112 | #footer { font-size:8pt; text-align:center; border-top:1px solid #ddd; color: #888; } |
1113 | |||
1114 | /* Minimal customisation for jQuery widgets */ | ||
1115 | .ui-autocomplete { background-color:#fff; padding-left:5px;} | ||
1116 | .ui-state-hover { background-color: #604dff; color:#fff; } | ||
1117 | |||
1075 | --> | 1118 | --> |
1076 | </style> | 1119 | </style> |
1077 | </head> | 1120 | </head> |
1078 | <body {$data['onload']}> | 1121 | <body {$data['onload']}> |
1079 | <div id="pageheader"><div style="float:right; font-style:italic; color:#bbb; text-align:right; padding:0 5 0 0;">Shaare your links...<br>{$linkcount} links</div> | 1122 | <div id="pageheader"><div style="float:right; font-style:italic; color:#bbb; text-align:right; padding:0 5 0 0;">Shaare your links...<br>{$linkcount} links</div> |
1080 | <b><i>Shaarli {$shaarli_version}</i></b> - <a href="?">Home</a> {$menu} <a href="{$feedurl}" style="padding-left:30px;">RSS Feed</a> | 1123 | <b><i>{$open}Shaarli {$shaarli_version}</i></b> - <a href="?">Home</a> {$menu} <a href="{$feedurl}" style="padding-left:30px;">RSS Feed</a> |
1081 | {$data['pageheader']} | 1124 | {$data['pageheader']} |
1082 | </div> | 1125 | </div> |
1083 | {$data['body']} | 1126 | {$data['body']} |
@@ -1086,7 +1129,7 @@ HTML; | |||
1086 | $exectime = round(microtime(true)-$STARTTIME,4); | 1129 | $exectime = round(microtime(true)-$STARTTIME,4); |
1087 | echo '<div id="footer"><b><a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli">Shaarli '.shaarli_version.'</a></b> - The personal, minimalist, super-fast, no-database delicious clone. By sebsauvage.net<br>Who gives a shit that this page was generated in '.$exectime.' seconds ?</div>'; | 1130 | echo '<div id="footer"><b><a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli">Shaarli '.shaarli_version.'</a></b> - The personal, minimalist, super-fast, no-database delicious clone. By sebsauvage.net<br>Who gives a shit that this page was generated in '.$exectime.' seconds ?</div>'; |
1088 | if (isLoggedIn()) echo '<script language="JavaScript">function confirmDeleteLink() { var agree=confirm("Are you sure you want to delete this link ?"); if (agree) return true ; else return false ; }</script>'; | 1131 | if (isLoggedIn()) echo '<script language="JavaScript">function confirmDeleteLink() { var agree=confirm("Are you sure you want to delete this link ?"); if (agree) return true ; else return false ; }</script>'; |
1089 | echo '</body></html>'; | 1132 | echo $jsincludes_bottom.'</body></html>'; |
1090 | } | 1133 | } |
1091 | 1134 | ||
1092 | // ----------------------------------------------------------------------------------------------- | 1135 | // ----------------------------------------------------------------------------------------------- |
@@ -1101,7 +1144,11 @@ function install() | |||
1101 | $salt=sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. | 1144 | $salt=sha1(uniqid('',true).'_'.mt_rand()); // Salt renders rainbow-tables attacks useless. |
1102 | $hash = sha1($_POST['setpassword'].$_POST['setlogin'].$salt); | 1145 | $hash = sha1($_POST['setpassword'].$_POST['setlogin'].$salt); |
1103 | $config='<?php $GLOBALS[\'login\']='.var_export($_POST['setlogin'],true).'; $GLOBALS[\'hash\']='.var_export($hash,true).'; $GLOBALS[\'salt\']='.var_export($salt,true).'; date_default_timezone_set('.var_export($tz,true).'); ?>'; | 1146 | $config='<?php $GLOBALS[\'login\']='.var_export($_POST['setlogin'],true).'; $GLOBALS[\'hash\']='.var_export($hash,true).'; $GLOBALS[\'salt\']='.var_export($salt,true).'; date_default_timezone_set('.var_export($tz,true).'); ?>'; |
1104 | file_put_contents(CONFIG_FILE,$config); | 1147 | if (!file_put_contents(CONFIG_FILE,$config) || strcmp(file_get_contents(CONFIG_FILE),$config)!=0) |
1148 | { | ||
1149 | echo '<script language="JavaScript">alert("Shaarli could not create the config file. Please make sure Shaarli has the right to write in the folder is it installed in.");document.location=\'?\';</script>'; | ||
1150 | exit; | ||
1151 | } | ||
1105 | echo '<script language="JavaScript">alert("Shaarli is now configured. Please enter your login/password and start shaaring your links !");document.location=\'?do=login\';</script>'; | 1152 | echo '<script language="JavaScript">alert("Shaarli is now configured. Please enter your login/password and start shaaring your links !");document.location=\'?do=login\';</script>'; |
1106 | exit; | 1153 | exit; |
1107 | } | 1154 | } |
@@ -1127,7 +1174,34 @@ HTML; | |||
1127 | exit; | 1174 | exit; |
1128 | } | 1175 | } |
1129 | 1176 | ||
1130 | $LINKSDB=new linkdb(isLoggedIn()); // Read links from database (and filter private links if used it not logged in). | 1177 | // Webservices (for use with jQuery/jQueryUI) |
1178 | // eg. index.php?ws=tags&term=minecr | ||
1179 | function processWS() | ||
1180 | { | ||
1181 | if (empty($_GET['ws']) || empty($_GET['term'])) return; | ||
1182 | $term = $_GET['term']; | ||
1183 | global $LINKSDB; | ||
1184 | header('Content-Type: application/json; charset=utf-8'); | ||
1185 | |||
1186 | // Search in tags | ||
1187 | if ($_GET['ws']=='tags') | ||
1188 | { | ||
1189 | $tags=explode(' ',$term); $last = array_pop($tags); // Get the last term ("a b c d" ==> "a b c", "d") | ||
1190 | $addtags=''; if ($tags) $addtags=implode(' ',$tags).' '; // We will pre-pend previous tags | ||
1191 | $suggested=array(); | ||
1192 | /* To speed up things, we store list of tags in session */ | ||
1193 | if (empty($_SESSION['tags'])) $_SESSION['tags'] = $LINKSDB->allTags(); | ||
1194 | foreach($_SESSION['tags'] as $key=>$value) | ||
1195 | { | ||
1196 | if (startsWith($key,$last,$case=false)) $suggested[$addtags.$key.' ']=0; | ||
1197 | } | ||
1198 | echo json_encode(array_keys($suggested)); | ||
1199 | exit; | ||
1200 | } | ||
1201 | } | ||
1202 | |||
1203 | $LINKSDB=new linkdb(isLoggedIn() || OPEN_SHAARLI); // Read links from database (and filter private links if used it not logged in). | ||
1204 | if (startswith($_SERVER["QUERY_STRING"],'ws=')) { processWS(); exit; } // Webservices (for jQuery/jQueryUI) | ||
1131 | if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=LINKS_PER_PAGE; | 1205 | if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=LINKS_PER_PAGE; |
1132 | if (startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; } | 1206 | if (startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; } |
1133 | renderPage(); | 1207 | renderPage(); |