X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=index.php;h=cd83600bf7c4ab5c87d4606deced9a4c481cea1b;hb=88c15abb2a2b24f05ca926c0ddbdec18a407e47d;hp=654f7f8f36fabb83b84f2e0016b67a8d82e8866b;hpb=2e28269baed195d58bbe169841eed176b171db76;p=github%2Fshaarli%2FShaarli.git diff --git a/index.php b/index.php index 654f7f8f..cd83600b 100644 --- a/index.php +++ b/index.php @@ -1,6 +1,6 @@ /shaarli/ define('WEB_PATH', substr($_SERVER["REQUEST_URI"], 0, 1+strrpos($_SERVER["REQUEST_URI"], '/', 0))); @@ -150,6 +151,7 @@ require_once 'application/CachedPage.php'; require_once 'application/FileUtils.php'; require_once 'application/HttpUtils.php'; require_once 'application/LinkDB.php'; +require_once 'application/LinkFilter.php'; require_once 'application/TimeZone.php'; require_once 'application/Url.php'; require_once 'application/Utils.php'; @@ -159,7 +161,7 @@ require_once 'application/Router.php'; // Ensure the PHP version is supported try { - checkPHPVersion('5.3', PHP_VERSION); + ApplicationUtils::checkPHPVersion('5.3', PHP_VERSION); } catch(Exception $exc) { header('Content-Type: text/plain; charset=utf-8'); echo $exc->getMessage(); @@ -305,56 +307,15 @@ function setup_login_state() { } $userIsLoggedIn = setup_login_state(); -// Checks if an update is available for Shaarli. -// (at most once a day, and only for registered user.) -// Output: '' = no new version. -// other= the available version. -function checkUpdate() -{ - if (!isLoggedIn()) return ''; // Do not check versions for visitors. - if (empty($GLOBALS['config']['ENABLE_UPDATECHECK'])) return ''; // Do not check if the user doesn't want to. - - // Get latest version number at most once a day. - if (!is_file($GLOBALS['config']['UPDATECHECK_FILENAME']) || (filemtime($GLOBALS['config']['UPDATECHECK_FILENAME'])', '', str_replace('$1',$url); + file_put_contents($GLOBALS['config']['LOG_FILE'], $t, FILE_APPEND); } -// This function inserts   where relevant so that multiple spaces are properly displayed in HTML -// even in the absence of
  (This is used in description to keep text formatting)
-function keepMultipleSpaces($text)
-{
-    return str_replace('  ','  ',$text);
-
-}
 // ------------------------------------------------------------------------------------------
 // Sniff browser language to display dates in the right format automatically.
 // (Note that is may not work on your server if the corresponding local is not installed.)
@@ -672,7 +633,25 @@ class pageBuilder
     private function initialize()
     {
         $this->tpl = new RainTPL;
-        $this->tpl->assign('newversion', escape(checkUpdate()));
+
+        try {
+            $version = ApplicationUtils::checkUpdate(
+                shaarli_version,
+                $GLOBALS['config']['UPDATECHECK_FILENAME'],
+                $GLOBALS['config']['UPDATECHECK_INTERVAL'],
+                $GLOBALS['config']['ENABLE_UPDATECHECK'],
+                isLoggedIn(),
+                $GLOBALS['config']['UPDATECHECK_BRANCH']
+            );
+            $this->tpl->assign('newVersion', escape($version));
+            $this->tpl->assign('versionError', '');
+
+        } catch (Exception $exc) {
+            logm($exc->getMessage());
+            $this->tpl->assign('newVersion', '');
+            $this->tpl->assign('versionError', escape($exc->getMessage()));
+        }
+
         $this->tpl->assign('feedurl', escape(index_url($_SERVER)));
         $searchcrits = ''; // Search criteria
         if (!empty($_GET['searchtags'])) {
@@ -746,23 +725,29 @@ function showRSS()
     $LINKSDB = new LinkDB(
         $GLOBALS['config']['DATASTORE'],
         isLoggedIn(),
-        $GLOBALS['config']['HIDE_PUBLIC_LINKS']
+        $GLOBALS['config']['HIDE_PUBLIC_LINKS'],
+        $GLOBALS['redirector']
     );
     // Read links from database (and filter private links if user it not logged in).
 
     // Optionally filter the results:
-    $linksToDisplay=array();
-    if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']);
-    else if (!empty($_GET['searchtags']))   $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags']));
-    else $linksToDisplay = $LINKSDB;
+    if (!empty($_GET['searchterm'])) {
+        $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_TEXT, $_GET['searchterm']);
+    }
+    elseif (!empty($_GET['searchtags'])) {
+        $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_TAG, trim($_GET['searchtags']));
+    }
+    else {
+        $linksToDisplay = $LINKSDB;
+    }
 
     $nblinksToDisplay = 50;  // Number of links to display.
-    if (!empty($_GET['nb']))  // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.
-    {
-        $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ;
+    // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links.
+    if (!empty($_GET['nb'])) {
+        $nblinksToDisplay = $_GET['nb'] == 'all' ? count($linksToDisplay) : max(intval($_GET['nb']), 1);
     }
 
-    $pageaddr=escape(index_url($_SERVER));
+    $pageaddr = escape(index_url($_SERVER));
     echo '';
     echo ''.$GLOBALS['title'].''.$pageaddr.'';
     echo 'Shared linksen-en'.$pageaddr.''."\n\n";
@@ -797,7 +782,9 @@ function showRSS()
         // If user wants permalinks first, put the final link in description
         if ($usepermalinks===true) $descriptionlink = '(Link)';
         if (strlen($link['description'])>0) $descriptionlink = '
'.$descriptionlink; - echo ''."\n\n"; + echo '' . "\n\n"; $i++; } echo '
'; @@ -835,19 +822,25 @@ function showATOM() $LINKSDB = new LinkDB( $GLOBALS['config']['DATASTORE'], isLoggedIn(), - $GLOBALS['config']['HIDE_PUBLIC_LINKS'] + $GLOBALS['config']['HIDE_PUBLIC_LINKS'], + $GLOBALS['redirector'] ); // Optionally filter the results: - $linksToDisplay=array(); - if (!empty($_GET['searchterm'])) $linksToDisplay = $LINKSDB->filterFulltext($_GET['searchterm']); - else if (!empty($_GET['searchtags'])) $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); - else $linksToDisplay = $LINKSDB; + if (!empty($_GET['searchterm'])) { + $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_TEXT, $_GET['searchterm']); + } + else if (!empty($_GET['searchtags'])) { + $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_TAG, trim($_GET['searchtags'])); + } + else { + $linksToDisplay = $LINKSDB; + } $nblinksToDisplay = 50; // Number of links to display. - if (!empty($_GET['nb'])) // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. - { - $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max($_GET['nb']+0,1) ; + // In URL, you can specificy the number of links. Example: nb=200 or nb=all for all links. + if (!empty($_GET['nb'])) { + $nblinksToDisplay = $_GET['nb']=='all' ? count($linksToDisplay) : max(intval($_GET['nb']), 1); } $pageaddr=escape(index_url($_SERVER)); @@ -876,7 +869,9 @@ function showATOM() if ($usepermalinks===true) $descriptionlink = '(Link)'; if (strlen($link['description'])>0) $descriptionlink = '
'.$descriptionlink; - $entries.='\n"; + $entries .= '\n"; if ($link['tags']!='') // Adding tags to each ATOM entry (as mentioned in ATOM specification) { foreach(explode(' ',$link['tags']) as $tag) @@ -929,7 +924,8 @@ function showDailyRSS() { $LINKSDB = new LinkDB( $GLOBALS['config']['DATASTORE'], isLoggedIn(), - $GLOBALS['config']['HIDE_PUBLIC_LINKS'] + $GLOBALS['config']['HIDE_PUBLIC_LINKS'], + $GLOBALS['redirector'] ); /* Some Shaarlies may have very few links, so we need to look @@ -983,7 +979,7 @@ function showDailyRSS() { // We pre-format some fields for proper output. foreach ($linkdates as $linkdate) { $l = $LINKSDB[$linkdate]; - $l['formatedDescription'] = nl2br(keepMultipleSpaces(text2clickable($l['description']))); + $l['formatedDescription'] = format_description($l['description'], $GLOBALS['redirector']); $l['thumbnail'] = thumbnail($l['url']); $l['timestamp'] = linkdate2timestamp($l['linkdate']); if (startsWith($l['url'], '?')) { @@ -1010,13 +1006,18 @@ function showDailyRSS() { exit; } -// "Daily" page. -function showDaily() +/** + * Show the 'Daily' page. + * + * @param PageBuilder $pageBuilder Template engine wrapper. + */ +function showDaily($pageBuilder) { $LINKSDB = new LinkDB( $GLOBALS['config']['DATASTORE'], isLoggedIn(), - $GLOBALS['config']['HIDE_PUBLIC_LINKS'] + $GLOBALS['config']['HIDE_PUBLIC_LINKS'], + $GLOBALS['redirector'] ); $day=Date('Ymd',strtotime('-1 day')); // Yesterday, in format YYYYMMDD. @@ -1034,7 +1035,7 @@ function showDaily() } try { - $linksToDisplay = $LINKSDB->filterDay($day); + $linksToDisplay = $LINKSDB->filter(LinkFilter::$FILTER_DAY, $day); } catch (Exception $exc) { error_log($exc); $linksToDisplay = array(); @@ -1047,7 +1048,7 @@ function showDaily() $taglist = explode(' ',$link['tags']); uasort($taglist, 'strcasecmp'); $linksToDisplay[$key]['taglist']=$taglist; - $linksToDisplay[$key]['formatedDescription']=nl2br(keepMultipleSpaces(text2clickable($link['description']))); + $linksToDisplay[$key]['formatedDescription'] = format_description($link['description'], $GLOBALS['redirector']); $linksToDisplay[$key]['thumbnail'] = thumbnail($link['url']); $linksToDisplay[$key]['timestamp'] = linkdate2timestamp($link['linkdate']); } @@ -1073,7 +1074,7 @@ function showDaily() array_push($columns[$index],$link); // Put entry in this column. $fill[$index]+=$length; } - $PAGE = new pageBuilder; + $data = array( 'linksToDisplay' => $linksToDisplay, 'linkcount' => count($LINKSDB), @@ -1086,10 +1087,10 @@ function showDaily() $pluginManager->executeHooks('render_daily', $data, array('loggedin' => isLoggedIn())); foreach ($data as $key => $value) { - $PAGE->assign($key, $value); + $pageBuilder->assign($key, $value); } - $PAGE->renderPage('daily'); + $pageBuilder->renderPage('daily'); exit; } @@ -1107,7 +1108,8 @@ function renderPage() $LINKSDB = new LinkDB( $GLOBALS['config']['DATASTORE'], isLoggedIn(), - $GLOBALS['config']['HIDE_PUBLIC_LINKS'] + $GLOBALS['config']['HIDE_PUBLIC_LINKS'], + $GLOBALS['redirector'] ); $PAGE = new pageBuilder; @@ -1158,13 +1160,17 @@ function renderPage() if ($targetPage == Router::$PAGE_PICWALL) { // Optionally filter the results: - $links=array(); - if (!empty($_GET['searchterm'])) $links = $LINKSDB->filterFulltext($_GET['searchterm']); - elseif (!empty($_GET['searchtags'])) $links = $LINKSDB->filterTags(trim($_GET['searchtags'])); - else $links = $LINKSDB; + if (!empty($_GET['searchterm'])) { + $links = $LINKSDB->filter(LinkFilter::$FILTER_TEXT, $_GET['searchterm']); + } + elseif (! empty($_GET['searchtags'])) { + $links = $LINKSDB->filter(LinkFilter::$FILTER_TAG, trim($_GET['searchtags'])); + } + else { + $links = $LINKSDB; + } - $body=''; - $linksToDisplay=array(); + $linksToDisplay = array(); // Get only links which have a thumbnail. foreach($links as $link) @@ -1222,6 +1228,11 @@ function renderPage() exit; } + // Daily page. + if ($targetPage == Router::$PAGE_DAILY) { + showDaily($PAGE); + } + // Display openseach plugin (XML) if ($targetPage == Router::$PAGE_OPENSEARCH) { header('Content-Type: application/xml; charset=utf-8'); @@ -1286,13 +1297,15 @@ function renderPage() } if (isset($params['searchtags'])) { - $tags = explode(' ',$params['searchtags']); - $tags=array_diff($tags, array($_GET['removetag'])); // Remove value from array $tags. - if (count($tags)==0) { + $tags = explode(' ', $params['searchtags']); + // Remove value from array $tags. + $tags = array_diff($tags, array($_GET['removetag'])); + $params['searchtags'] = implode(' ',$tags); + + if (empty($params['searchtags'])) { unset($params['searchtags']); - } else { - $params['searchtags'] = implode(' ',$tags); } + unset($params['page']); // We also remove page (keeping the same page has no sense, since the results are different) } header('Location: ?'.http_build_query($params)); @@ -1457,21 +1470,23 @@ function renderPage() // -------- User wants to rename a tag or delete it if ($targetPage == Router::$PAGE_CHANGETAG) { - if (empty($_POST['fromtag'])) - { - $PAGE->assign('linkcount',count($LINKSDB)); - $PAGE->assign('token',getToken()); + if (empty($_POST['fromtag']) || (empty($_POST['totag']) && isset($_POST['renametag']))) { + $PAGE->assign('linkcount', count($LINKSDB)); + $PAGE->assign('token', getToken()); $PAGE->assign('tags', $LINKSDB->allTags()); $PAGE->renderPage('changetag'); exit; } - if (!tokenOk($_POST['token'])) die('Wrong token.'); + + if (!tokenOk($_POST['token'])) { + die('Wrong token.'); + } // Delete a tag: - if (!empty($_POST['deletetag']) && !empty($_POST['fromtag'])) - { + if (isset($_POST['deletetag']) && !empty($_POST['fromtag'])) { $needle=trim($_POST['fromtag']); - $linksToAlter = $LINKSDB->filterTags($needle,true); // True for case-sensitive tag search. + // True for case-sensitive tag search. + $linksToAlter = $LINKSDB->filter(LinkFilter::$FILTER_TAG, $needle, true); foreach($linksToAlter as $key=>$value) { $tags = explode(' ',trim($value['tags'])); @@ -1485,10 +1500,10 @@ function renderPage() } // Rename a tag: - if (!empty($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) - { + if (isset($_POST['renametag']) && !empty($_POST['fromtag']) && !empty($_POST['totag'])) { $needle=trim($_POST['fromtag']); - $linksToAlter = $LINKSDB->filterTags($needle,true); // true for case-sensitive tag search. + // True for case-sensitive tag search. + $linksToAlter = $LINKSDB->filter(LinkFilter::$FILTER_TAG, $needle, true); foreach($linksToAlter as $key=>$value) { $tags = explode(' ',trim($value['tags'])); @@ -1781,7 +1796,8 @@ function importFile() $LINKSDB = new LinkDB( $GLOBALS['config']['DATASTORE'], isLoggedIn(), - $GLOBALS['config']['HIDE_PUBLIC_LINKS'] + $GLOBALS['config']['HIDE_PUBLIC_LINKS'], + $GLOBALS['redirector'] ); $filename=$_FILES['filetoupload']['name']; $filesize=$_FILES['filetoupload']['size']; @@ -1868,82 +1884,78 @@ function importFile() function buildLinkList($PAGE,$LINKSDB) { // ---- Filter link database according to parameters - $linksToDisplay=array(); - $search_type=''; - $search_crits=''; - if (isset($_GET['searchterm'])) // Fulltext search - { - $linksToDisplay = $LINKSDB->filterFulltext(trim($_GET['searchterm'])); - $search_crits=escape(trim($_GET['searchterm'])); - $search_type='fulltext'; - } - elseif (isset($_GET['searchtags'])) // Search by tag - { - $linksToDisplay = $LINKSDB->filterTags(trim($_GET['searchtags'])); - $search_crits=explode(' ',escape(trim($_GET['searchtags']))); - $search_type='tags'; - } - elseif (isset($_SERVER['QUERY_STRING']) && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/',$_SERVER['QUERY_STRING'])) // Detect smallHashes in URL - { - $linksToDisplay = $LINKSDB->filterSmallHash(substr(trim($_SERVER["QUERY_STRING"], '/'),0,6)); - if (count($linksToDisplay)==0) - { - header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); - echo '

404 Not found.

Oh crap. The link you are trying to reach does not exist or has been deleted.'; + $search_type = ''; + $search_crits = ''; + $privateonly = !empty($_SESSION['privateonly']) ? true : false; + + // Fulltext search + if (isset($_GET['searchterm'])) { + $search_crits = escape(trim($_GET['searchterm'])); + $search_type = LinkFilter::$FILTER_TEXT; + $linksToDisplay = $LINKSDB->filter($search_type, $search_crits, false, $privateonly); + } + // Search by tag + elseif (isset($_GET['searchtags'])) { + $search_crits = explode(' ', escape(trim($_GET['searchtags']))); + $search_type = LinkFilter::$FILTER_TAG; + $linksToDisplay = $LINKSDB->filter($search_type, $search_crits, false, $privateonly); + } + // Detect smallHashes in URL. + elseif (isset($_SERVER['QUERY_STRING']) + && preg_match('/[a-zA-Z0-9-_@]{6}(&.+?)?/', $_SERVER['QUERY_STRING'])) { + $search_type = LinkFilter::$FILTER_HASH; + $search_crits = substr(trim($_SERVER["QUERY_STRING"], '/'), 0, 6); + $linksToDisplay = $LINKSDB->filter($search_type, $search_crits); + + if (count($linksToDisplay) == 0) { + header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); + echo '

404 Not found.

Oh crap. + The link you are trying to reach does not exist or has been deleted.'; echo '
Would you mind clicking here?'; exit; } - $search_type='permalink'; } - else - $linksToDisplay = $LINKSDB; // Otherwise, display without filtering. - - - // Option: Show only private links - if (!empty($_SESSION['privateonly'])) - { - $tmp = array(); - foreach($linksToDisplay as $linkdate=>$link) - { - if ($link['private']!=0) $tmp[$linkdate]=$link; - } - $linksToDisplay=$tmp; + // Otherwise, display without filtering. + else { + $linksToDisplay = $LINKSDB->filter('', '', false, $privateonly); } // ---- Handle paging. - /* Can someone explain to me why you get the following error when using array_keys() on an object which implements the interface ArrayAccess??? - "Warning: array_keys() expects parameter 1 to be array, object given in ... " - If my class implements ArrayAccess, why won't array_keys() accept it ? ( $keys=array_keys($linksToDisplay); ) - */ - $keys=array(); foreach($linksToDisplay as $key=>$value) { $keys[]=$key; } // Stupid and ugly. Thanks PHP. + $keys = array(); + foreach ($linksToDisplay as $key => $value) { + $keys[] = $key; + } // If there is only a single link, we change on-the-fly the title of the page. - if (count($linksToDisplay)==1) $GLOBALS['pagetitle'] = $linksToDisplay[$keys[0]]['title'].' - '.$GLOBALS['title']; + if (count($linksToDisplay) == 1) { + $GLOBALS['pagetitle'] = $linksToDisplay[$keys[0]]['title'].' - '.$GLOBALS['title']; + } // Select articles according to paging. - $pagecount = ceil(count($keys)/$_SESSION['LINKS_PER_PAGE']); - $pagecount = ($pagecount==0 ? 1 : $pagecount); - $page=( empty($_GET['page']) ? 1 : intval($_GET['page'])); - $page = ( $page<1 ? 1 : $page ); - $page = ( $page>$pagecount ? $pagecount : $page ); - $i = ($page-1)*$_SESSION['LINKS_PER_PAGE']; // Start index. - $end = $i+$_SESSION['LINKS_PER_PAGE']; - $linkDisp=array(); // Links to display + $pagecount = ceil(count($keys) / $_SESSION['LINKS_PER_PAGE']); + $pagecount = $pagecount == 0 ? 1 : $pagecount; + $page= empty($_GET['page']) ? 1 : intval($_GET['page']); + $page = $page < 1 ? 1 : $page; + $page = $page > $pagecount ? $pagecount : $page; + // Start index. + $i = ($page-1) * $_SESSION['LINKS_PER_PAGE']; + $end = $i + $_SESSION['LINKS_PER_PAGE']; + $linkDisp = array(); while ($i<$end && $i1) $next_page_url='?page='.($page-1).$searchterm.$searchtags; + $searchterm = empty($_GET['searchterm']) ? '' : '&searchterm=' . $_GET['searchterm']; + $searchtags = empty($_GET['searchtags']) ? '' : '&searchtags=' . $_GET['searchtags']; + $previous_page_url = ''; + if ($i != count($keys)) { + $previous_page_url = '?page=' . ($page+1) . $searchterm . $searchtags; + } + $next_page_url=''; + if ($page>1) { + $next_page_url = '?page=' . ($page-1) . $searchterm . $searchtags; + } - $token = ''; if (isLoggedIn()) $token=getToken(); + $token = ''; + if (isLoggedIn()) { + $token = getToken(); + } // Fill all template fields. $data = array( @@ -1974,6 +1994,10 @@ function buildLinkList($PAGE,$LINKSDB) 'links' => $linkDisp, 'tags' => $LINKSDB->allTags(), ); + // FIXME! temporary fix - see #399. + if (!empty($GLOBALS['pagetitle']) && count($linkDisp) == 1) { + $data['pagetitle'] = $GLOBALS['pagetitle']; + } $pluginManager = PluginManager::getInstance(); $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => isLoggedIn())); @@ -2239,45 +2263,6 @@ function install() exit; } -if (!function_exists('json_encode')) { - function json_encode($data) { - switch ($type = gettype($data)) { - case 'NULL': - return 'null'; - case 'boolean': - return ($data ? 'true' : 'false'); - case 'integer': - case 'double': - case 'float': - return $data; - case 'string': - return '"' . addslashes($data) . '"'; - case 'object': - $data = get_object_vars($data); - case 'array': - $output_index_count = 0; - $output_indexed = array(); - $output_associative = array(); - foreach ($data as $key => $value) { - $output_indexed[] = json_encode($value); - $output_associative[] = json_encode($key) . ':' . json_encode($value); - if ($output_index_count !== NULL && $output_index_count++ !== $key) { - $output_index_count = NULL; - } - } - if ($output_index_count !== NULL) { - return '[' . implode(',', $output_indexed) . ']'; - } else { - return '{' . implode(',', $output_associative) . '}'; - } - default: - return ''; // Not supported - } - } -} - - - /* Because some f*cking services like flickr require an extra HTTP request to get the thumbnail URL, I have deported the thumbnail URL code generation here, otherwise this would slow down page generation. The following function takes the URL a link (e.g. a flickr page) and return the proper thumbnail. @@ -2507,7 +2492,6 @@ if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=g if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=rss')) { showRSS(); exit; } if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=atom')) { showATOM(); exit; } if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=dailyrss')) { showDailyRSS(); exit; } -if (isset($_SERVER["QUERY_STRING"]) && startswith($_SERVER["QUERY_STRING"],'do=daily')) { showDaily(); exit; } if (!isset($_SESSION['LINKS_PER_PAGE'])) $_SESSION['LINKS_PER_PAGE']=$GLOBALS['config']['LINKS_PER_PAGE']; renderPage(); ?>