diff options
Diffstat (limited to 'index.php')
-rw-r--r-- | index.php | 165 |
1 files changed, 46 insertions, 119 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 { |
@@ -792,8 +806,6 @@ function renderPage($conf, $pluginManager) | |||
792 | if ($targetPage == Router::$PAGE_LOGIN) | 806 | if ($targetPage == Router::$PAGE_LOGIN) |
793 | { | 807 | { |
794 | 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 |
795 | $token=''; if (ban_canLogin($conf)) $token=getToken($conf); // Do not waste token generation if not useful. | ||
796 | $PAGE->assign('token',$token); | ||
797 | if (isset($_GET['username'])) { | 809 | if (isset($_GET['username'])) { |
798 | $PAGE->assign('username', escape($_GET['username'])); | 810 | $PAGE->assign('username', escape($_GET['username'])); |
799 | } | 811 | } |
@@ -1114,7 +1126,6 @@ function renderPage($conf, $pluginManager) | |||
1114 | } | 1126 | } |
1115 | else // show the change password form. | 1127 | else // show the change password form. |
1116 | { | 1128 | { |
1117 | $PAGE->assign('token',getToken($conf)); | ||
1118 | $PAGE->renderPage('changepassword'); | 1129 | $PAGE->renderPage('changepassword'); |
1119 | exit; | 1130 | exit; |
1120 | } | 1131 | } |
@@ -1161,7 +1172,6 @@ function renderPage($conf, $pluginManager) | |||
1161 | } | 1172 | } |
1162 | else // Show the configuration form. | 1173 | else // Show the configuration form. |
1163 | { | 1174 | { |
1164 | $PAGE->assign('token',getToken($conf)); | ||
1165 | $PAGE->assign('title', $conf->get('general.title')); | 1175 | $PAGE->assign('title', $conf->get('general.title')); |
1166 | $PAGE->assign('redirector', $conf->get('redirector.url')); | 1176 | $PAGE->assign('redirector', $conf->get('redirector.url')); |
1167 | list($timezone_form, $timezone_js) = generateTimeZoneForm($conf->get('general.timezone')); | 1177 | list($timezone_form, $timezone_js) = generateTimeZoneForm($conf->get('general.timezone')); |
@@ -1181,7 +1191,6 @@ function renderPage($conf, $pluginManager) | |||
1181 | if ($targetPage == Router::$PAGE_CHANGETAG) | 1191 | if ($targetPage == Router::$PAGE_CHANGETAG) |
1182 | { | 1192 | { |
1183 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { | 1193 | if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { |
1184 | $PAGE->assign('token', getToken($conf)); | ||
1185 | $PAGE->assign('tags', $LINKSDB->allTags()); | 1194 | $PAGE->assign('tags', $LINKSDB->allTags()); |
1186 | $PAGE->renderPage('changetag'); | 1195 | $PAGE->renderPage('changetag'); |
1187 | exit; | 1196 | exit; |
@@ -1356,7 +1365,6 @@ function renderPage($conf, $pluginManager) | |||
1356 | $data = array( | 1365 | $data = array( |
1357 | 'link' => $link, | 1366 | 'link' => $link, |
1358 | 'link_is_new' => false, | 1367 | 'link_is_new' => false, |
1359 | 'token' => getToken($conf), | ||
1360 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), | 1368 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), |
1361 | 'tags' => $LINKSDB->allTags(), | 1369 | 'tags' => $LINKSDB->allTags(), |
1362 | ); | 1370 | ); |
@@ -1423,11 +1431,10 @@ function renderPage($conf, $pluginManager) | |||
1423 | $data = array( | 1431 | $data = array( |
1424 | 'link' => $link, | 1432 | 'link' => $link, |
1425 | 'link_is_new' => $link_is_new, | 1433 | 'link_is_new' => $link_is_new, |
1426 | 'token' => getToken($conf), // XSRF protection. | ||
1427 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), | 1434 | 'http_referer' => (isset($_SERVER['HTTP_REFERER']) ? escape($_SERVER['HTTP_REFERER']) : ''), |
1428 | 'source' => (isset($_GET['source']) ? $_GET['source'] : ''), | 1435 | 'source' => (isset($_GET['source']) ? $_GET['source'] : ''), |
1429 | 'tags' => $LINKSDB->allTags(), | 1436 | 'tags' => $LINKSDB->allTags(), |
1430 | 'default_private_links' => $conf->get('default_private_links', false), | 1437 | 'default_private_links' => $conf->get('privacy.default_private_links', false), |
1431 | ); | 1438 | ); |
1432 | $pluginManager->executeHooks('render_editlink', $data); | 1439 | $pluginManager->executeHooks('render_editlink', $data); |
1433 | 1440 | ||
@@ -1483,27 +1490,37 @@ function renderPage($conf, $pluginManager) | |||
1483 | exit; | 1490 | exit; |
1484 | } | 1491 | } |
1485 | 1492 | ||
1486 | // -------- User is uploading a file for import | 1493 | if ($targetPage == Router::$PAGE_IMPORT) { |
1487 | if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=upload')) | 1494 | // Upload a Netscape bookmark dump to import its contents |
1488 | { | 1495 | |
1489 | // If file is too big, some form field may be missing. | 1496 | if (! isset($_POST['token']) || ! isset($_FILES['filetoupload'])) { |
1490 | if (!isset($_POST['token']) || (!isset($_FILES)) || (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size']==0)) | 1497 | // Show import dialog |
1491 | { | 1498 | $PAGE->assign('maxfilesize', getMaxFileSize()); |
1492 | $returnurl = ( empty($_SERVER['HTTP_REFERER']) ? '?' : $_SERVER['HTTP_REFERER'] ); | 1499 | $PAGE->renderPage('import'); |
1493 | 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>'; | ||
1494 | exit; | 1500 | exit; |
1495 | } | 1501 | } |
1496 | if (!tokenOk($_POST['token'])) die('Wrong token.'); | ||
1497 | importFile($LINKSDB); | ||
1498 | exit; | ||
1499 | } | ||
1500 | 1502 | ||
1501 | // -------- Show upload/import dialog: | 1503 | // Import bookmarks from an uploaded file |
1502 | if ($targetPage == Router::$PAGE_IMPORT) | 1504 | if (isset($_FILES['filetoupload']['size']) && $_FILES['filetoupload']['size'] == 0) { |
1503 | { | 1505 | // The file is too big or some form field may be missing. |
1504 | $PAGE->assign('token',getToken($conf)); | 1506 | echo '<script>alert("The file you are trying to upload is probably' |
1505 | $PAGE->assign('maxfilesize',getMaxFileSize()); | 1507 | .' bigger than what this webserver can accept (' |
1506 | $PAGE->renderPage('import'); | 1508 | .getMaxFileSize().' bytes).' |
1509 | .' Please upload in smaller chunks.");document.location=\'?do=' | ||
1510 | .Router::$PAGE_IMPORT .'\';</script>'; | ||
1511 | exit; | ||
1512 | } | ||
1513 | if (! tokenOk($_POST['token'])) { | ||
1514 | die('Wrong token.'); | ||
1515 | } | ||
1516 | $status = NetscapeBookmarkUtils::import( | ||
1517 | $_POST, | ||
1518 | $_FILES, | ||
1519 | $LINKSDB, | ||
1520 | $conf->get('resource.page_cache') | ||
1521 | ); | ||
1522 | echo '<script>alert("'.$status.'");document.location=\'?do=' | ||
1523 | .Router::$PAGE_IMPORT .'\';</script>'; | ||
1507 | exit; | 1524 | exit; |
1508 | } | 1525 | } |
1509 | 1526 | ||
@@ -1561,95 +1578,6 @@ function renderPage($conf, $pluginManager) | |||
1561 | } | 1578 | } |
1562 | 1579 | ||
1563 | /** | 1580 | /** |
1564 | * Process the import file form. | ||
1565 | * | ||
1566 | * @param LinkDB $LINKSDB Loaded LinkDB instance. | ||
1567 | * @param ConfigManager $conf Configuration Manager instance. | ||
1568 | */ | ||
1569 | function importFile($LINKSDB, $conf) | ||
1570 | { | ||
1571 | if (!isLoggedIn()) { die('Not allowed.'); } | ||
1572 | |||
1573 | $filename=$_FILES['filetoupload']['name']; | ||
1574 | $filesize=$_FILES['filetoupload']['size']; | ||
1575 | $data=file_get_contents($_FILES['filetoupload']['tmp_name']); | ||
1576 | $private = (empty($_POST['private']) ? 0 : 1); // Should the links be imported as private? | ||
1577 | $overwrite = !empty($_POST['overwrite']) ; // Should the imported links overwrite existing ones? | ||
1578 | $import_count=0; | ||
1579 | |||
1580 | // Sniff file type: | ||
1581 | $type='unknown'; | ||
1582 | if (startsWith($data,'<!DOCTYPE NETSCAPE-Bookmark-file-1>')) $type='netscape'; // Netscape bookmark file (aka Firefox). | ||
1583 | |||
1584 | // Then import the bookmarks. | ||
1585 | if ($type=='netscape') | ||
1586 | { | ||
1587 | // This is a standard Netscape-style bookmark file. | ||
1588 | // This format is supported by all browsers (except IE, of course), also Delicious, Diigo and others. | ||
1589 | foreach(explode('<DT>',$data) as $html) // explode is very fast | ||
1590 | { | ||
1591 | $link = array('linkdate'=>'','title'=>'','url'=>'','description'=>'','tags'=>'','private'=>0); | ||
1592 | $d = explode('<DD>',$html); | ||
1593 | if (startsWith($d[0], '<A ')) | ||
1594 | { | ||
1595 | $link['description'] = (isset($d[1]) ? html_entity_decode(trim($d[1]),ENT_QUOTES,'UTF-8') : ''); // Get description (optional) | ||
1596 | preg_match('!<A .*?>(.*?)</A>!i',$d[0],$matches); $link['title'] = (isset($matches[1]) ? trim($matches[1]) : ''); // Get title | ||
1597 | $link['title'] = html_entity_decode($link['title'],ENT_QUOTES,'UTF-8'); | ||
1598 | preg_match_all('! ([A-Z_]+)=\"(.*?)"!i',$html,$matches,PREG_SET_ORDER); // Get all other attributes | ||
1599 | $raw_add_date=0; | ||
1600 | foreach($matches as $m) | ||
1601 | { | ||
1602 | $attr=$m[1]; $value=$m[2]; | ||
1603 | if ($attr=='HREF') $link['url']=html_entity_decode($value,ENT_QUOTES,'UTF-8'); | ||
1604 | elseif ($attr=='ADD_DATE') | ||
1605 | { | ||
1606 | $raw_add_date=intval($value); | ||
1607 | if ($raw_add_date>30000000000) $raw_add_date/=1000; //If larger than year 2920, then was likely stored in milliseconds instead of seconds | ||
1608 | } | ||
1609 | elseif ($attr=='PRIVATE') $link['private']=($value=='0'?0:1); | ||
1610 | elseif ($attr=='TAGS') $link['tags']=html_entity_decode(str_replace(',',' ',$value),ENT_QUOTES,'UTF-8'); | ||
1611 | } | ||
1612 | if ($link['url']!='') | ||
1613 | { | ||
1614 | if ($private==1) $link['private']=1; | ||
1615 | $dblink = $LINKSDB->getLinkFromUrl($link['url']); // See if the link is already in database. | ||
1616 | if ($dblink==false) | ||
1617 | { // Link not in database, let's import it... | ||
1618 | if (empty($raw_add_date)) $raw_add_date=time(); // In case of shitty bookmark file with no ADD_DATE | ||
1619 | |||
1620 | // Make sure date/time is not already used by another link. | ||
1621 | // (Some bookmark files have several different links with the same ADD_DATE) | ||
1622 | // We increment date by 1 second until we find a date which is not used in DB. | ||
1623 | // (so that links that have the same date/time are more or less kept grouped by date, but do not conflict.) | ||
1624 | while (!empty($LINKSDB[date('Ymd_His',$raw_add_date)])) { $raw_add_date++; }// Yes, I know it's ugly. | ||
1625 | $link['linkdate']=date('Ymd_His',$raw_add_date); | ||
1626 | $LINKSDB[$link['linkdate']] = $link; | ||
1627 | $import_count++; | ||
1628 | } | ||
1629 | else // Link already present in database. | ||
1630 | { | ||
1631 | if ($overwrite) | ||
1632 | { // If overwrite is required, we import link data, except date/time. | ||
1633 | $link['linkdate']=$dblink['linkdate']; | ||
1634 | $LINKSDB[$link['linkdate']] = $link; | ||
1635 | $import_count++; | ||
1636 | } | ||
1637 | } | ||
1638 | |||
1639 | } | ||
1640 | } | ||
1641 | } | ||
1642 | $LINKSDB->savedb($conf->get('resource.page_cache')); | ||
1643 | |||
1644 | echo '<script>alert("File '.json_encode($filename).' ('.$filesize.' bytes) was successfully processed: '.$import_count.' links imported.");document.location=\'?\';</script>'; | ||
1645 | } | ||
1646 | else | ||
1647 | { | ||
1648 | echo '<script>alert("File '.json_encode($filename).' ('.$filesize.' bytes) has an unknown file format. Nothing was imported.");document.location=\'?\';</script>'; | ||
1649 | } | ||
1650 | } | ||
1651 | |||
1652 | /** | ||
1653 | * Template for the list of links (<div id="linklist">) | 1581 | * Template for the list of links (<div id="linklist">) |
1654 | * This function fills all the necessary fields in the $PAGE for the template 'linklist.html' | 1582 | * This function fills all the necessary fields in the $PAGE for the template 'linklist.html' |
1655 | * | 1583 | * |
@@ -1743,7 +1671,6 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) | |||
1743 | 'search_term' => $searchterm, | 1671 | 'search_term' => $searchterm, |
1744 | 'search_tags' => $searchtags, | 1672 | 'search_tags' => $searchtags, |
1745 | 'redirector' => $conf->get('redirector.url'), // Optional redirector URL. | 1673 | 'redirector' => $conf->get('redirector.url'), // Optional redirector URL. |
1746 | 'token' => $token, | ||
1747 | 'links' => $linkDisp, | 1674 | 'links' => $linkDisp, |
1748 | 'tags' => $LINKSDB->allTags(), | 1675 | 'tags' => $LINKSDB->allTags(), |
1749 | ); | 1676 | ); |