diff options
Diffstat (limited to 'index.php')
-rw-r--r-- | index.php | 176 |
1 files changed, 56 insertions, 120 deletions
@@ -1,6 +1,6 @@ | |||
1 | <?php | 1 | <?php |
2 | /** | 2 | /** |
3 | * Shaarli v0.7.0 - Shaare your links... | 3 | * Shaarli v0.8.0 - Shaare your links... |
4 | * | 4 | * |
5 | * The personal, minimalist, super-fast, database free, bookmarking service. | 5 | * The personal, minimalist, super-fast, database free, bookmarking service. |
6 | * | 6 | * |
@@ -25,7 +25,7 @@ if (date_default_timezone_get() == '') { | |||
25 | /* | 25 | /* |
26 | * PHP configuration | 26 | * PHP configuration |
27 | */ | 27 | */ |
28 | define('shaarli_version', '0.7.0'); | 28 | define('shaarli_version', '0.8.0'); |
29 | 29 | ||
30 | // http://server.com/x/shaarli --> /shaarli/ | 30 | // http://server.com/x/shaarli --> /shaarli/ |
31 | define('WEB_PATH', substr($_SERVER['REQUEST_URI'], 0, 1+strrpos($_SERVER['REQUEST_URI'], '/', 0))); | 31 | define('WEB_PATH', substr($_SERVER['REQUEST_URI'], 0, 1+strrpos($_SERVER['REQUEST_URI'], '/', 0))); |
@@ -44,6 +44,20 @@ error_reporting(E_ALL^E_WARNING); | |||
44 | //error_reporting(-1); | 44 | //error_reporting(-1); |
45 | 45 | ||
46 | 46 | ||
47 | // 3rd-party libraries | ||
48 | if (! file_exists(__DIR__ . '/vendor/autoload.php')) { | ||
49 | header('Content-Type: text/plain; charset=utf-8'); | ||
50 | echo "Error: missing Composer configuration\n\n" | ||
51 | ."If you installed Shaarli through Git or using the development branch,\n" | ||
52 | ."please refer to the installation documentation to install PHP" | ||
53 | ." dependencies using Composer:\n" | ||
54 | ."- https://github.com/shaarli/Shaarli/wiki/Server-requirements\n" | ||
55 | ."- https://github.com/shaarli/Shaarli/wiki/Download-and-Installation"; | ||
56 | exit; | ||
57 | } | ||
58 | require_once 'inc/rain.tpl.class.php'; | ||
59 | require_once __DIR__ . '/vendor/autoload.php'; | ||
60 | |||
47 | // Shaarli library | 61 | // Shaarli library |
48 | require_once 'application/ApplicationUtils.php'; | 62 | require_once 'application/ApplicationUtils.php'; |
49 | require_once 'application/Cache.php'; | 63 | require_once 'application/Cache.php'; |
@@ -53,6 +67,7 @@ require_once 'application/config/ConfigPlugin.php'; | |||
53 | require_once 'application/FeedBuilder.php'; | 67 | require_once 'application/FeedBuilder.php'; |
54 | require_once 'application/FileUtils.php'; | 68 | require_once 'application/FileUtils.php'; |
55 | require_once 'application/HttpUtils.php'; | 69 | require_once 'application/HttpUtils.php'; |
70 | require_once 'application/Languages.php'; | ||
56 | require_once 'application/LinkDB.php'; | 71 | require_once 'application/LinkDB.php'; |
57 | require_once 'application/LinkFilter.php'; | 72 | require_once 'application/LinkFilter.php'; |
58 | require_once 'application/LinkUtils.php'; | 73 | require_once 'application/LinkUtils.php'; |
@@ -64,7 +79,6 @@ require_once 'application/Utils.php'; | |||
64 | require_once 'application/PluginManager.php'; | 79 | require_once 'application/PluginManager.php'; |
65 | require_once 'application/Router.php'; | 80 | require_once 'application/Router.php'; |
66 | require_once 'application/Updater.php'; | 81 | require_once 'application/Updater.php'; |
67 | require_once 'inc/rain.tpl.class.php'; | ||
68 | 82 | ||
69 | // Ensure the PHP version is supported | 83 | // Ensure the PHP version is supported |
70 | try { | 84 | try { |
@@ -318,8 +332,17 @@ include $conf->get('resource.ban_file', 'data/ipbans.php'); | |||
318 | function ban_loginFailed($conf) | 332 | function ban_loginFailed($conf) |
319 | { | 333 | { |
320 | $ip = $_SERVER['REMOTE_ADDR']; | 334 | $ip = $_SERVER['REMOTE_ADDR']; |
335 | $trusted = $conf->get('security.trusted_proxies', array()); | ||
336 | if (in_array($ip, $trusted)) { | ||
337 | $ip = getIpAddressFromProxy($_SERVER, $trusted); | ||
338 | if (!$ip) { | ||
339 | return; | ||
340 | } | ||
341 | } | ||
321 | $gb = $GLOBALS['IPBANS']; | 342 | $gb = $GLOBALS['IPBANS']; |
322 | if (!isset($gb['FAILURES'][$ip])) $gb['FAILURES'][$ip]=0; | 343 | if (! isset($gb['FAILURES'][$ip])) { |
344 | $gb['FAILURES'][$ip]=0; | ||
345 | } | ||
323 | $gb['FAILURES'][$ip]++; | 346 | $gb['FAILURES'][$ip]++; |
324 | if ($gb['FAILURES'][$ip] > ($conf->get('security.ban_after') - 1)) | 347 | if ($gb['FAILURES'][$ip] > ($conf->get('security.ban_after') - 1)) |
325 | { | 348 | { |
@@ -783,8 +806,6 @@ function renderPage($conf, $pluginManager) | |||
783 | if ($targetPage == Router::$PAGE_LOGIN) | 806 | if ($targetPage == Router::$PAGE_LOGIN) |
784 | { | 807 | { |
785 | if ($conf->get('security.open_shaarli')) { header('Location: ?'); exit; } // No need to login for open Shaarli | 808 | if ($conf->get('security.open_shaarli')) { header('Location: ?'); exit; } // No need to login for open Shaarli |
786 | $token=''; if (ban_canLogin($conf)) $token=getToken($conf); // Do not waste token generation if not useful. | ||
787 | $PAGE->assign('token',$token); | ||
788 | if (isset($_GET['username'])) { | 809 | if (isset($_GET['username'])) { |
789 | $PAGE->assign('username', escape($_GET['username'])); | 810 | $PAGE->assign('username', escape($_GET['username'])); |
790 | } | 811 | } |
@@ -1105,7 +1126,6 @@ function renderPage($conf, $pluginManager) | |||
1105 | } | 1126 | } |
1106 | else // show the change password form. | 1127 | else // show the change password form. |
1107 | { | 1128 | { |
1108 | $PAGE->assign('token',getToken($conf)); | ||
1109 | $PAGE->renderPage('changepassword'); | 1129 | $PAGE->renderPage('changepassword'); |
1110 | exit; | 1130 | exit; |
1111 | } | 1131 | } |
@@ -1152,7 +1172,6 @@ function renderPage($conf, $pluginManager) | |||
1152 | } | 1172 | } |
1153 | else // Show the configuration form. | 1173 | else // Show the configuration form. |
1154 | { | 1174 | { |
1155 | $PAGE->assign('token',getToken($conf)); | ||
1156 | $PAGE->assign('title', $conf->get('general.title')); | 1175 | $PAGE->assign('title', $conf->get('general.title')); |
1157 | $PAGE->assign('redirector', $conf->get('redirector.url')); | 1176 | $PAGE->assign('redirector', $conf->get('redirector.url')); |
1158 | list($timezone_form, $timezone_js) = generateTimeZoneForm($conf->get('general.timezone')); | 1177 | list($timezone_form, $timezone_js) = generateTimeZoneForm($conf->get('general.timezone')); |
@@ -1172,7 +1191,6 @@ function renderPage($conf, $pluginManager) | |||
1172 | if ($targetPage == Router::$PAGE_CHANGETAG) | 1191 | if ($targetPage == Router::$PAGE_CHANGETAG) |
1173 | { | 1192 | { |
1174 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { | 1193 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { |
1175 | $PAGE->assign('token', getToken($conf)); | ||
1176 | $PAGE->assign('tags', $LINKSDB->allTags()); | 1194 | $PAGE->assign('tags', $LINKSDB->allTags()); |
1177 | $PAGE->renderPage('changetag'); | 1195 | $PAGE->renderPage('changetag'); |
1178 | exit; | 1196 | exit; |
@@ -1351,7 +1369,6 @@ function renderPage($conf, $pluginManager) | |||
1351 | $data = array( | 1369 | $data = array( |
1352 | 'link' => $link, | 1370 | 'link' => $link, |
1353 | 'link_is_new' => false, | 1371 | 'link_is_new' => false, |
1354 | 'token' => getToken($conf), | ||
1355 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), | 1372 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), |
1356 | 'tags' => $LINKSDB->allTags(), | 1373 | 'tags' => $LINKSDB->allTags(), |
1357 | ); | 1374 | ); |
@@ -1418,11 +1435,10 @@ function renderPage($conf, $pluginManager) | |||
1418 | $data = array( | 1435 | $data = array( |
1419 | 'link' => $link, | 1436 | 'link' => $link, |
1420 | 'link_is_new' => $link_is_new, | 1437 | 'link_is_new' => $link_is_new, |
1421 | 'token' => getToken($conf), // XSRF protection. | ||
1422 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), | 1438 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), |
1423 | 'source' => (isset($_GET['source']) ? $_GET['source'] : ''), | 1439 | 'source' => (isset($_GET['source']) ? $_GET['source'] : ''), |
1424 | 'tags' => $LINKSDB->allTags(), | 1440 | 'tags' => $LINKSDB->allTags(), |
1425 | 'default_private_links' => $conf->get('default_private_links', false), | 1441 | 'default_private_links' => $conf->get('privacy.default_private_links', false), |
1426 | ); | 1442 | ); |
1427 | $pluginManager->executeHooks('render_editlink', $data); | 1443 | $pluginManager->executeHooks('render_editlink', $data); |
1428 | 1444 | ||
@@ -1478,27 +1494,37 @@ function renderPage($conf, $pluginManager) | |||
1478 | exit; | 1494 | exit; |
1479 | } | 1495 | } |
1480 | 1496 | ||
1481 | // -------- User is uploading a file for import | 1497 | if ($targetPage == Router::$PAGE_IMPORT) { |
1482 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=upload')) | 1498 | // Upload a Netscape bookmark dump to import its contents |
1483 | { | 1499 | |
1484 | // If file is too big, some form field may be missing. | 1500 | if (! isset($_POST['token']) || ! isset($_FILES['filetoupload'])) { |
1485 | if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0)) | 1501 | // Show import dialog |
1486 | { | 1502 | $PAGE->assign('maxfilesize', getMaxFileSize()); |
1487 | $returnurl = ( empty($_SERVER['HTTP_REFERER']) ? '?' : $_SERVER['HTTP_REFERER'] ); | 1503 | $PAGE->renderPage('import'); |
1488 | 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>'; | ||
1489 | exit; | 1504 | exit; |
1490 | } | 1505 | } |
1491 | if (!tokenOk($_POST['token'])) die('Wrong token.'); | ||
1492 | importFile($LINKSDB); | ||
1493 | exit; | ||
1494 | } | ||
1495 | 1506 | ||
1496 | // -------- Show upload/import dialog: | 1507 | // Import bookmarks from an uploaded file |
1497 | if ($targetPage == Router::$PAGE_IMPORT) | 1508 | if (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size'] == 0) { |
1498 | { | 1509 | // The file is too big or some form field may be missing. |
1499 | $PAGE->assign('token',getToken($conf)); | 1510 | echo '<script>alert("The file you are trying to upload is probably' |
1500 | $PAGE->assign('maxfilesize',getMaxFileSize()); | 1511 | .' bigger than what this webserver can accept (' |
1501 | $PAGE->renderPage('import'); | 1512 | .getMaxFileSize().' bytes).' |
1513 | .' Please upload in smaller chunks.");document.location=\'?do=' | ||
1514 | .Router::$PAGE_IMPORT .'\';</script>'; | ||
1515 | exit; | ||
1516 | } | ||
1517 | if (! tokenOk($_POST['token'])) { | ||
1518 | die('Wrong token.'); | ||
1519 | } | ||
1520 | $status = NetscapeBookmarkUtils::import( | ||
1521 | $_POST, | ||
1522 | $_FILES, | ||
1523 | $LINKSDB, | ||
1524 | $conf->get('resource.page_cache') | ||
1525 | ); | ||
1526 | echo '<script>alert("'.$status.'");document.location=\'?do=' | ||
1527 | .Router::$PAGE_IMPORT .'\';</script>'; | ||
1502 | exit; | 1528 | exit; |
1503 | } | 1529 | } |
1504 | 1530 | ||
@@ -1556,95 +1582,6 @@ function renderPage($conf, $pluginManager) | |||
1556 | } | 1582 | } |
1557 | 1583 | ||
1558 | /** | 1584 | /** |
1559 | * Process the import file form. | ||
1560 | * | ||
1561 | * @param LinkDB $LINKSDB Loaded LinkDB instance. | ||
1562 | * @param ConfigManager $conf Configuration Manager instance. | ||
1563 | */ | ||
1564 | function importFile($LINKSDB, $conf) | ||
1565 | { | ||
1566 | if (!isLoggedIn()) { die('Not allowed.'); } | ||
1567 | |||
1568 | $filename=$_FILES['filetoupload']['name']; | ||
1569 | $filesize=$_FILES['filetoupload']['size']; | ||
1570 | $data=file_get_contents($_FILES['filetoupload']['tmp_name']); | ||
1571 | $private = (empty($_POST['private']) ? 0 : 1); // Should the links be imported as private? | ||
1572 | $overwrite = !empty($_POST['overwrite']) ; // Should the imported links overwrite existing ones? | ||
1573 | $import_count=0; | ||
1574 | |||
1575 | // Sniff file type: | ||
1576 | $type='unknown'; | ||
1577 | if (startsWith($data,'<!DOCTYPE NETSCAPE-Bookmark-file-1>')) $type='netscape'; // Netscape bookmark file (aka Firefox). | ||
1578 | |||
1579 | // Then import the bookmarks. | ||
1580 | if ($type=='netscape') | ||
1581 | { | ||
1582 | // This is a standard Netscape-style bookmark file. | ||
1583 | // This format is supported by all browsers (except IE, of course), also Delicious, Diigo and others. | ||
1584 | foreach(explode('<DT>',$data) as $html) // explode is very fast | ||
1585 | { | ||
1586 | $link = array('linkdate'=>'','title'=>'','url'=>'','description'=>'','tags'=>'','private'=>0); | ||
1587 | $d = explode('<DD>',$html); | ||
1588 | if (startsWith($d[0], '<A ')) | ||
1589 | { | ||
1590 | $link['description'] = (isset($d[1]) ? html_entity_decode(trim($d[1]),ENT_QUOTES,'UTF-8') : ''); // Get description (optional) | ||
1591 | preg_match('!<A .*?>(.*?)</A>!i',$d[0],$matches); $link['title'] = (isset($matches[1]) ? trim($matches[1]) : ''); // Get title | ||
1592 | $link['title'] = html_entity_decode($link['title'],ENT_QUOTES,'UTF-8'); | ||
1593 | preg_match_all('! ([A-Z_]+)=\"(.*?)"!i',$html,$matches,PREG_SET_ORDER); // Get all other attributes | ||
1594 | $raw_add_date=0; | ||
1595 | foreach($matches as $m) | ||
1596 | { | ||
1597 | $attr=$m[1]; $value=$m[2]; | ||
1598 | if ($attr=='HREF') $link['url']=html_entity_decode($value,ENT_QUOTES,'UTF-8'); | ||
1599 | elseif ($attr=='ADD_DATE') | ||
1600 | { | ||
1601 | $raw_add_date=intval($value); | ||
1602 | if ($raw_add_date>30000000000) $raw_add_date/=1000; //If larger than year 2920, then was likely stored in milliseconds instead of seconds | ||
1603 | } | ||
1604 | elseif ($attr=='PRIVATE') $link['private']=($value=='0'?0:1); | ||
1605 | elseif ($attr=='TAGS') $link['tags']=html_entity_decode(str_replace(',',' ',$value),ENT_QUOTES,'UTF-8'); | ||
1606 | } | ||
1607 | if ($link['url']!='') | ||
1608 | { | ||
1609 | if ($private==1) $link['private']=1; | ||
1610 | $dblink = $LINKSDB->getLinkFromUrl($link['url']); // See if the link is already in database. | ||
1611 | if ($dblink==false) | ||
1612 | { // Link not in database, let's import it... | ||
1613 | if (empty($raw_add_date)) $raw_add_date=time(); // In case of shitty bookmark file with no ADD_DATE | ||
1614 | |||
1615 | // Make sure date/time is not already used by another link. | ||
1616 | // (Some bookmark files have several different links with the same ADD_DATE) | ||
1617 | // We increment date by 1 second until we find a date which is not used in DB. | ||
1618 | // (so that links that have the same date/time are more or less kept grouped by date, but do not conflict.) | ||
1619 | while (!empty($LINKSDB[date('Ymd_His',$raw_add_date)])) { $raw_add_date++; }// Yes, I know it's ugly. | ||
1620 | $link['linkdate']=date('Ymd_His',$raw_add_date); | ||
1621 | $LINKSDB[$link['linkdate']] = $link; | ||
1622 | $import_count++; | ||
1623 | } | ||
1624 | else // Link already present in database. | ||
1625 | { | ||
1626 | if ($overwrite) | ||
1627 | { // If overwrite is required, we import link data, except date/time. | ||
1628 | $link['linkdate']=$dblink['linkdate']; | ||
1629 | $LINKSDB[$link['linkdate']] = $link; | ||
1630 | $import_count++; | ||
1631 | } | ||
1632 | } | ||
1633 | |||
1634 | } | ||
1635 | } | ||
1636 | } | ||
1637 | $LINKSDB->savedb($conf->get('resource.page_cache')); | ||
1638 | |||
1639 | echo '<script>alert("File '.json_encode($filename).' ('.$filesize.' bytes) was successfully processed: '.$import_count.' links imported.");document.location=\'?\';</script>'; | ||
1640 | } | ||
1641 | else | ||
1642 | { | ||
1643 | echo '<script>alert("File '.json_encode($filename).' ('.$filesize.' bytes) has an unknown file format. Nothing was imported.");document.location=\'?\';</script>'; | ||
1644 | } | ||
1645 | } | ||
1646 | |||
1647 | /** | ||
1648 | * Template for the list of links (<div id="linklist">) | 1585 | * Template for the list of links (<div id="linklist">) |
1649 | * This function fills all the necessary fields in the $PAGE for the template 'linklist.html' | 1586 | * This function fills all the necessary fields in the $PAGE for the template 'linklist.html' |
1650 | * | 1587 | * |
@@ -1744,7 +1681,6 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1744 | 'search_term' => $searchterm, | 1681 | 'search_term' => $searchterm, |
1745 | 'search_tags' => $searchtags, | 1682 | 'search_tags' => $searchtags, |
1746 | 'redirector' => $conf->get('redirector.url'), // Optional redirector URL. | 1683 | 'redirector' => $conf->get('redirector.url'), // Optional redirector URL. |
1747 | 'token' => $token, | ||
1748 | 'links' => $linkDisp, | 1684 | 'links' => $linkDisp, |
1749 | 'tags' => $LINKSDB->allTags(), | 1685 | 'tags' => $LINKSDB->allTags(), |
1750 | ); | 1686 | ); |