4 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
\r
5 * Copyright (C) 2002-2009 The Nucleus Group
\r
7 * This program is free software; you can redistribute it and/or
\r
8 * modify it under the terms of the GNU General Public License
\r
9 * as published by the Free Software Foundation; either version 2
\r
10 * of the License, or (at your option) any later version.
\r
11 * (see nucleus/documentation/index.html#license for more info)
\r
14 * @license http://nucleuscms.org/license.txt GNU General Public License
\r
15 * @copyright Copyright (C) 2002-2009 The Nucleus Group
\r
17 * $NucleusJP: globalfunctions.php,v 1.23.2.7 2008/02/05 08:30:08 kimitake Exp $
\r
20 // needed if we include globalfunctions from install.php
\r
21 global $nucleus, $CONF, $DIR_LIBS, $DIR_LANG, $manager, $member;
\r
23 $nucleus['version'] = 'v3.40RC';
\r
24 $nucleus['codename'] = '';
\r
26 checkVars(array('nucleus', 'CONF', 'DIR_LIBS', 'MYSQL_HOST', 'MYSQL_USER', 'MYSQL_PASSWORD', 'MYSQL_DATABASE', 'DIR_LANG', 'DIR_PLUGINS', 'HTTP_GET_VARS', 'HTTP_POST_VARS', 'HTTP_COOKIE_VARS', 'HTTP_ENV_VARS', 'HTTP_SESSION_VARS', 'HTTP_POST_FILES', 'HTTP_SERVER_VARS', 'GLOBALS', 'argv', 'argc', '_GET', '_POST', '_COOKIE', '_ENV', '_SESSION', '_SERVER', '_FILES'));
\r
29 if ($CONF['debug']) {
\r
30 error_reporting(E_ALL); // report all errors!
\r
32 error_reporting(E_ERROR | E_WARNING | E_PARSE);
\r
36 Indicates when Nucleus should display startup errors. Set to 1 if you want
\r
37 the error enabled (default), false otherwise
\r
40 Displays an error when visiting a public Nucleus page and headers have
\r
41 been sent out to early. This usually indicates an error in either a
\r
42 configuration file or a language file, and could cause Nucleus to
\r
45 Displays an error only when visiting the admin area, and when one or
\r
46 more of the installation files (install.php, install.sql, upgrades/
\r
47 directory) are still on the server.
\r
49 $CONF['alertOnHeadersSent'] = 1;
\r
50 $CONF['alertOnSecurityRisk'] = 1;
\r
51 $CONF['ItemURL'] = $CONF['Self'];
\r
52 $CONF['ArchiveURL'] = $CONF['Self'];
\r
53 $CONF['ArchiveListURL'] = $CONF['Self'];
\r
54 $CONF['MemberURL'] = $CONF['Self'];
\r
55 $CONF['SearchURL'] = $CONF['Self'];
\r
56 $CONF['BlogURL'] = $CONF['Self'];
\r
57 $CONF['CategoryURL'] = $CONF['Self'];
\r
59 // switch URLMode back to normal when $CONF['Self'] ends in .php
\r
60 // this avoids urls like index.php/item/13/index.php/item/15
\r
61 if (!isset($CONF['URLMode']) || (($CONF['URLMode'] == 'pathinfo') && (substr($CONF['Self'], strlen($CONF['Self']) - 4) == '.php'))) {
\r
62 $CONF['URLMode'] = 'normal';
\r
65 if (getNucleusPatchLevel() > 0) {
\r
66 $nucleus['version'] .= '/' . getNucleusPatchLevel();
\r
70 if (!isset($CONF['installscript'])) {
\r
71 $CONF['installscript'] = 0;
\r
74 // we will use postVar, getVar, ... methods instead of HTTP_GET_VARS or _GET
\r
75 if ($CONF['installscript'] != 1) { // vars were already included in install.php
\r
76 if (phpversion() >= '4.1.0') {
\r
77 include_once($DIR_LIBS . 'vars4.1.0.php');
\r
79 include_once($DIR_LIBS . 'vars4.0.6.php');
\r
84 $bLoggingSanitizedResult=0;
\r
85 $bSanitizeAndContinue=0;
\r
87 $orgRequestURI = serverVar('REQUEST_URI');
\r
90 // get all variables that can come from the request and put them in the global scope
\r
91 $blogid = requestVar('blogid');
\r
92 $itemid = intRequestVar('itemid');
\r
93 $catid = intRequestVar('catid');
\r
94 $skinid = requestVar('skinid');
\r
95 $memberid = requestVar('memberid');
\r
96 $archivelist = requestVar('archivelist');
\r
97 $imagepopup = requestVar('imagepopup');
\r
98 $archive = requestVar('archive');
\r
99 $query = requestVar('query');
\r
100 $highlight = requestVar('highlight');
\r
101 $amount = requestVar('amount');
\r
102 $action = requestVar('action');
\r
103 $nextaction = requestVar('nextaction');
\r
104 $maxresults = requestVar('maxresults');
\r
105 $startpos = intRequestVar('startpos');
\r
106 $errormessage = '';
\r
108 $virtualpath = ((getVar('virtualpath') != null) ? getVar('virtualpath') : serverVar('PATH_INFO'));
\r
110 if (!headers_sent() ) {
\r
111 header('Generator: Nucleus CMS ' . $nucleus['version']);
\r
114 // include core classes that are needed for login & plugin handling
\r
115 include($DIR_LIBS . 'mysql.php');
\r
116 include($DIR_LIBS . 'MEMBER.php');
\r
117 include($DIR_LIBS . 'ACTIONLOG.php');
\r
118 include($DIR_LIBS . 'MANAGER.php');
\r
119 include($DIR_LIBS . 'PLUGIN.php');
\r
121 $manager =& MANAGER::instance();
\r
123 // make sure there's no unnecessary escaping:
\r
124 set_magic_quotes_runtime(0);
\r
127 if (!isset($CONF['UsingAdminArea'])) {
\r
128 $CONF['UsingAdminArea'] = 0;
\r
131 // only needed when updating logs
\r
132 if ($CONF['UsingAdminArea']) {
\r
133 include($DIR_LIBS . 'xmlrpc.inc.php'); // XML-RPC client classes
\r
134 include_once($DIR_LIBS . 'ADMIN.php');
\r
137 // connect to database
\r
141 // logs sanitized result if need
\r
142 if ($orgRequestURI!==serverVar('REQUEST_URI')) {
\r
143 $msg = "Sanitized [" . serverVar('REMOTE_ADDR') . "] ";
\r
144 $msg .= $orgRequestURI . " -> " . serverVar('REQUEST_URI');
\r
145 if ($bLoggingSanitizedResult) {
\r
146 addToLog(WARNING, $msg);
\r
148 if (!$bSanitizeAndContinue) {
\r
153 // makes sure database connection gets closed on script termination
\r
154 register_shutdown_function('sql_disconnect');
\r
159 // Properly set $CONF['Self'] and others if it's not set... usually when we are access from admin menu
\r
160 if (!isset($CONF['Self'])) {
\r
161 $CONF['Self'] = $CONF['IndexURL'];
\r
162 // strip trailing /
\r
163 if ($CONF['Self'][strlen($CONF['Self']) -1] == "/") {
\r
164 $CONF['Self'] = substr($CONF['Self'], 0, strlen($CONF['Self']) -1);
\r
167 $CONF['ItemURL'] = $CONF['Self'];
\r
168 $CONF['ArchiveURL'] = $CONF['Self'];
\r
169 $CONF['ArchiveListURL'] = $CONF['Self'];
\r
170 $CONF['MemberURL'] = $CONF['Self'];
\r
171 $CONF['SearchURL'] = $CONF['Self'];
\r
172 $CONF['BlogURL'] = $CONF['Self'];
\r
173 $CONF['CategoryURL'] = $CONF['Self'];
\r
176 // automatically use simpler toolbar for mozilla
\r
177 if (($CONF['DisableJsTools'] == 0) && strstr(serverVar('HTTP_USER_AGENT'), 'Mozilla/5.0') && strstr(serverVar('HTTP_USER_AGENT'), 'Gecko') ) {
\r
178 $CONF['DisableJsTools'] = 2;
\r
181 // login if cookies set
\r
182 $member = new MEMBER();
\r
184 // secure cookie key settings (either 'none', 0, 8, 16, 24, or 32)
\r
185 if (!isset($CONF['secureCookieKey'])) $CONF['secureCookieKey']=24;
\r
186 switch($CONF['secureCookieKey']){
\r
188 $CONF['secureCookieKeyIP']=preg_replace('/\.[0-9]+\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
\r
191 $CONF['secureCookieKeyIP']=preg_replace('/\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
\r
194 $CONF['secureCookieKeyIP']=preg_replace('/\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
\r
197 $CONF['secureCookieKeyIP']=serverVar('REMOTE_ADDR');
\r
200 $CONF['secureCookieKeyIP']='';
\r
203 // login/logout when required or renew cookies
\r
204 if ($action == 'login') {
\r
205 // Form Authentication
\r
206 $login = postVar('login');
\r
207 $pw = postVar('password');
\r
208 $shared = intPostVar('shared'); // shared computer or not
\r
210 $pw=substr($pw,0,40); // avoid md5 collision by using a long key
\r
212 if ($member->login($login, $pw) ) {
\r
214 $member->newCookieKey();
\r
215 $member->setCookies($shared);
\r
217 if ($CONF['secureCookieKey']!=='none') {
\r
218 // secure cookie key
\r
219 $member->setCookieKey(md5($member->getCookieKey().$CONF['secureCookieKeyIP']));
\r
223 // allows direct access to parts of the admin area after logging in
\r
225 $action = $nextaction;
\r
228 $manager->notify('LoginSuccess', array('member' => &$member) );
\r
229 $errormessage = '';
\r
230 ACTIONLOG::add(INFO, "Login successful for $login (sharedpc=$shared)");
\r
232 // errormessage for [%errordiv%]
\r
233 $errormessage = 'Login failed for ' . $login;
\r
235 $manager->notify('LoginFailed', array('username' => $login) );
\r
236 ACTIONLOG::add(INFO, $errormessage);
\r
240 Backed out for now: See http://forum.nucleuscms.org/viewtopic.php?t=3684 for details
\r
242 } elseif (serverVar('PHP_AUTH_USER') && serverVar('PHP_AUTH_PW')) {
\r
243 // HTTP Authentication
\r
244 $login = serverVar('PHP_AUTH_USER');
\r
245 $pw = serverVar('PHP_AUTH_PW');
\r
247 if ($member->login($login, $pw) ) {
\r
248 $manager->notify('LoginSuccess',array('member' => &$member));
\r
249 ACTIONLOG::add(INFO, "HTTP authentication successful for $login");
\r
251 $manager->notify('LoginFailed',array('username' => $login));
\r
252 ACTIONLOG::add(INFO, 'HTTP authentication failed for ' . $login);
\r
254 //Since bad credentials, generate an apropriate error page
\r
255 header("WWW-Authenticate: Basic realm=\"Nucleus CMS {$nucleus['version']}\"");
\r
256 header('HTTP/1.0 401 Unauthorized');
\r
257 echo 'Invalid username or password';
\r
262 } elseif (($action == 'logout') && (!headers_sent() ) && cookieVar($CONF['CookiePrefix'] . 'user') ) {
\r
263 // remove cookies on logout
\r
264 setcookie($CONF['CookiePrefix'] . 'user', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
\r
265 setcookie($CONF['CookiePrefix'] . 'loginkey', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
\r
266 $manager->notify('Logout', array('username' => cookieVar($CONF['CookiePrefix'] . 'user') ) );
\r
267 } elseif (cookieVar($CONF['CookiePrefix'] . 'user') ) {
\r
268 // Cookie Authentication
\r
269 $ck=cookieVar($CONF['CookiePrefix'] . 'loginkey');
\r
270 // secure cookie key
\r
271 $ck=substr($ck,0,32); // avoid md5 collision by using a long key
\r
272 if ($CONF['secureCookieKey']!=='none') $ck=md5($ck.$CONF['secureCookieKeyIP']);
\r
273 $res = $member->cookielogin(cookieVar($CONF['CookiePrefix'] . 'user'), $ck );
\r
276 // renew cookies when not on a shared computer
\r
277 if ($res && (cookieVar($CONF['CookiePrefix'] . 'sharedpc') != 1) && (!headers_sent() ) ) {
\r
278 $member->setCookieKey(cookieVar($CONF['CookiePrefix'] . 'loginkey'));
\r
279 $member->setCookies();
\r
284 $manager->notify('PostAuthentication', array('loggedIn' => $member->isLoggedIn() ) );
\r
287 // first, let's see if the site is disabled or not. always allow admin area access.
\r
288 if ($CONF['DisableSite'] && !$member->isAdmin() && !$CONF['UsingAdminArea']) {
\r
289 redirect($CONF['DisableSiteURL']);
\r
293 // load other classes
\r
294 include($DIR_LIBS . 'PARSER.php');
\r
295 include($DIR_LIBS . 'SKIN.php');
\r
296 include($DIR_LIBS . 'TEMPLATE.php');
\r
297 include($DIR_LIBS . 'BLOG.php');
\r
298 include($DIR_LIBS . 'BODYACTIONS.php');
\r
299 include($DIR_LIBS . 'COMMENTS.php');
\r
300 include($DIR_LIBS . 'COMMENT.php');
\r
301 //include($DIR_LIBS . 'ITEM.php');
\r
302 include($DIR_LIBS . 'NOTIFICATION.php');
\r
303 include($DIR_LIBS . 'BAN.php');
\r
304 include($DIR_LIBS . 'PAGEFACTORY.php');
\r
305 include($DIR_LIBS . 'SEARCH.php');
\r
306 include($DIR_LIBS . 'entity.php');
\r
309 // set lastVisit cookie (if allowed)
\r
310 if (!headers_sent() ) {
\r
311 if ($CONF['LastVisit']) {
\r
312 setcookie($CONF['CookiePrefix'] . 'lastVisit', time(), time() + 2592000, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
\r
314 setcookie($CONF['CookiePrefix'] . 'lastVisit', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
\r
318 // read language file, only after user has been initialized
\r
319 $language = getLanguageName();
\r
320 include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');
\r
322 // check if valid charset
\r
323 if (!encoding_check(false, false, _CHARSET)) {
\r
324 foreach(array($_REQUEST, $_SERVER) as $input) {
\r
325 array_walk($input, 'encoding_check');
\r
330 Backed out for now: See http://forum.nucleuscms.org/viewtopic.php?t=3684 for details
\r
332 // To remove after v2.5 is released and language files have been updated.
\r
333 // Including this makes sure that language files for v2.5beta can still be used for v2.5final
\r
334 // without having weird _SETTINGS_EXTAUTH string showing up in the admin area.
\r
335 if (!defined('_MEMBERS_BYPASS'))
\r
337 define('_SETTINGS_EXTAUTH', 'Enable External Authentication');
\r
338 define('_WARNING_EXTAUTH', 'Warning: Enable only if needed.');
\r
339 define('_MEMBERS_BYPASS', 'Use External Authentication');
\r
344 // make sure the archivetype skinvar keeps working when _ARCHIVETYPE_XXX not defined
\r
345 if (!defined('_ARCHIVETYPE_MONTH') ) {
\r
346 define('_ARCHIVETYPE_DAY', 'day');
\r
347 define('_ARCHIVETYPE_MONTH', 'month');
\r
350 // decode path_info
\r
351 if ($CONF['URLMode'] == 'pathinfo') {
\r
352 // initialize keywords if this hasn't been done before
\r
353 if (!isset($CONF['ItemKey']) || $CONF['ItemKey'] == '') {
\r
354 $CONF['ItemKey'] = 'item';
\r
357 if (!isset($CONF['ArchiveKey']) || $CONF['ArchiveKey'] == '') {
\r
358 $CONF['ArchiveKey'] = 'archive';
\r
361 if (!isset($CONF['ArchivesKey']) || $CONF['ArchivesKey'] == '') {
\r
362 $CONF['ArchivesKey'] = 'archives';
\r
365 if (!isset($CONF['MemberKey']) || $CONF['MemberKey'] == '') {
\r
366 $CONF['MemberKey'] = 'member';
\r
369 if (!isset($CONF['BlogKey']) || $CONF['BlogKey'] == '') {
\r
370 $CONF['BlogKey'] = 'blog';
\r
373 if (!isset($CONF['CategoryKey']) || $CONF['CategoryKey'] == '') {
\r
374 $CONF['CategoryKey'] = 'category';
\r
377 if ($CONF['SpecialskinKey'] == '') {
\r
378 $CONF['SpecialskinKey'] = 'special';
\r
385 'type' => basename(serverVar('SCRIPT_NAME') ), // e.g. item, blog, ...
\r
386 'info' => $virtualpath,
\r
387 'complete' => &$parsed
\r
392 // default implementation
\r
393 $data = explode("/", $virtualpath );
\r
394 for ($i = 0; $i < sizeof($data); $i++) {
\r
395 switch ($data[$i]) {
\r
396 case $CONF['ItemKey']: // item/1 (blogid)
\r
399 if ($i < sizeof($data) ) {
\r
400 $itemid = intval($data[$i]);
\r
404 case $CONF['ArchivesKey']: // archives/1 (blogid)
\r
407 if ($i < sizeof($data) ) {
\r
408 $archivelist = intval($data[$i]);
\r
412 case $CONF['ArchiveKey']: // two possibilities: archive/yyyy-mm or archive/1/yyyy-mm (with blogid)
\r
413 if ((($i + 1) < sizeof($data) ) && (!strstr($data[$i + 1], '-') ) ) {
\r
414 $blogid = intval($data[++$i]);
\r
419 if ($i < sizeof($data) ) {
\r
420 $archive = $data[$i];
\r
424 case 'blogid': // blogid/1
\r
425 case $CONF['BlogKey']: // blog/1
\r
428 if ($i < sizeof($data) ) {
\r
429 $blogid = intval($data[$i]);
\r
433 case $CONF['CategoryKey']: // category/1 (catid)
\r
437 if ($i < sizeof($data) ) {
\r
438 $catid = intval($data[$i]);
\r
442 case $CONF['MemberKey']:
\r
445 if ($i < sizeof($data) ) {
\r
446 $memberid = intval($data[$i]);
\r
450 case $CONF['SpecialskinKey']:
\r
453 if ($i < sizeof($data) ) {
\r
454 $_REQUEST['special'] = $data[$i];
\r
465 function intPostVar($name) {
\r
466 return intval(postVar($name) );
\r
469 function intGetVar($name) {
\r
470 return intval(getVar($name) );
\r
473 function intRequestVar($name) {
\r
474 return intval(requestVar($name) );
\r
477 function intCookieVar($name) {
\r
478 return intval(cookieVar($name) );
\r
482 * returns the currently used version (100 = 1.00, 101 = 1.01, etc...)
\r
484 function getNucleusVersion() {
\r
489 * power users can install patches in between nucleus releases. These patches
\r
490 * usually add new functionality in the plugin API and allow those to
\r
491 * be tested without having to install CVS.
\r
493 function getNucleusPatchLevel() {
\r
498 * Connects to mysql server
\r
500 function sql_connect() {
\r
501 global $MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWORD, $MYSQL_DATABASE, $MYSQL_CONN;
\r
503 $MYSQL_CONN = @mysql_connect($MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWORD) or startUpError('<p>Could not connect to MySQL database.</p>', 'Connect Error');
\r
504 mysql_select_db($MYSQL_DATABASE) or startUpError('<p>Could not select database: ' . mysql_error() . '</p>', 'Connect Error');
\r
506 return $MYSQL_CONN;
\r
510 * returns a prefixed nucleus table name
\r
512 function sql_table($name) {
\r
513 global $MYSQL_PREFIX;
\r
515 if ($MYSQL_PREFIX) {
\r
516 return $MYSQL_PREFIX . 'nucleus_' . $name;
\r
518 return 'nucleus_' . $name;
\r
522 function sendContentType($contenttype, $pagetype = '', $charset = _CHARSET) {
\r
523 global $manager, $CONF;
\r
525 if (!headers_sent() ) {
\r
526 // if content type is application/xhtml+xml, only send it to browsers
\r
527 // that can handle it (IE6 cannot). Otherwise, send text/html
\r
529 // v2.5: For admin area pages, keep sending text/html (unless it's a debug version)
\r
530 // application/xhtml+xml still causes too much problems with the javascript implementations
\r
532 // v3.3: ($CONF['UsingAdminArea'] && !$CONF['debug']) gets removed,
\r
533 // application/xhtml+xml seems to be working, so we're going to use it if we can.
\r
535 // Note: reverted the following function in JP version
\r
540 ($contenttype == 'application/xhtml+xml')
\r
541 && (!stristr(serverVar('HTTP_ACCEPT'), 'application/xhtml+xml') )
\r
543 $contenttype = 'text/html';
\r
548 ($contenttype == 'application/xhtml+xml')
\r
549 && (($CONF['UsingAdminArea'] && !$CONF['debug']) || !stristr(serverVar('HTTP_ACCEPT'),'application/xhtml+xml'))
\r
552 $contenttype = 'text/html';
\r
556 'PreSendContentType',
\r
558 'contentType' => &$contenttype,
\r
559 'charset' => &$charset,
\r
560 'pageType' => $pagetype
\r
564 // strip strange characters
\r
565 $contenttype = preg_replace('|[^a-z0-9-+./]|i', '', $contenttype);
\r
566 $charset = preg_replace('|[^a-z0-9-_]|i', '', $charset);
\r
568 if ($charset != '') {
\r
569 header('Content-Type: ' . $contenttype . '; charset=' . $charset);
\r
571 header('Content-Type: ' . $contenttype);
\r
574 // check if valid charset
\r
575 if (!encoding_check(false,false,$charset)) {
\r
576 foreach(array($_REQUEST, $_SERVER) as $input) {
\r
577 array_walk($input, 'encoding_check');
\r
584 * Errors before the database connection has been made
\r
586 function startUpError($msg, $title) {
\r
587 if (!defined('_CHARSET')) define('_CHARSET', 'iso-8859-1');
\r
588 header('Content-Type: text/html; charset=' . _CHARSET);
\r
590 <html <?php echo _HTML_XML_NAME_SPACE_AND_LANG_CODE; ?>>
\r
591 <head><meta http-equiv="Content-Type" content="text/html; charset=<?php echo _CHARSET?>" />
\r
592 <title><?php echo htmlspecialchars($title)?></title></head>
\r
594 <h1><?php echo htmlspecialchars($title)?></h1>
\r
602 * disconnects from SQL server
\r
604 function sql_disconnect() {
\r
609 * executes an SQL query
\r
611 function sql_query($query) {
\r
614 $res = mysql_query($query) or print("mySQL error with query $query: " . mysql_error() . '<p />');
\r
620 * Highlights a specific query in a given HTML text (not within HTML tags) and returns it
\r
623 * text to be highlighted
\r
624 * @param $expression
\r
625 * regular expression to be matched (can be an array of expressions as well)
\r
626 * @param $highlight
\r
627 * highlight to be used (use \\0 to indicate the matched expression)
\r
630 function highlight($text, $expression, $highlight) {
\r
631 if (!$highlight || !$expression) {
\r
635 if (is_array($expression) && (count($expression) == 0) ) {
\r
639 // add a tag in front (is needed for preg_match_all to work correct)
\r
640 $text = '<!--h-->' . $text;
\r
642 // split the HTML up so we have HTML tags
\r
643 // $matches[0][i] = HTML + text
\r
644 // $matches[1][i] = HTML
\r
645 // $matches[2][i] = text
\r
646 preg_match_all('/(<[^>]+>)([^<>]*)/', $text, $matches);
\r
648 // throw it all together again while applying the highlight to the text pieces
\r
650 for ($i = 0; $i < sizeof($matches[2]); $i++) {
\r
652 $result .= $matches[1][$i];
\r
655 if (is_array($expression) ) {
\r
656 foreach ($expression as $regex) {
\r
658 $matches[2][$i] = @eregi_replace($regex, $highlight, $matches[2][$i]);
\r
662 $result .= $matches[2][$i];
\r
664 $result .= @eregi_replace($expression, $highlight, $matches[2][$i]);
\r
672 * Parses a query into an array of expressions that can be passed on to the highlight method
\r
674 function parseHighlight($query) {
\r
675 // TODO: add more intelligent splitting logic
\r
677 // get rid of quotes
\r
678 $query = preg_replace('/\'|"/', '', $query);
\r
684 $aHighlight = explode(' ', $query);
\r
686 for ($i = 0; $i < count($aHighlight); $i++) {
\r
687 $aHighlight[$i] = trim($aHighlight[$i]);
\r
689 if (strlen($aHighlight[$i]) < 3) {
\r
690 unset($aHighlight[$i]);
\r
694 if (count($aHighlight) == 1) {
\r
695 return $aHighlight[0];
\r
697 return $aHighlight;
\r
702 * Checks if email address is valid
\r
704 function isValidMailAddress($address) {
\r
705 if (preg_match('/^[a-zA-Z+0-9\._-]+@[a-zA-Z0-9\._-]+\.[A-Za-z]{2,5}$/', $address)) {
\r
713 // some helper functions
\r
714 function getBlogIDFromName($name) {
\r
715 return quickQuery('SELECT bnumber as result FROM ' . sql_table('blog') . ' WHERE bshortname="' . addslashes($name) . '"');
\r
718 function getBlogNameFromID($id) {
\r
719 return quickQuery('SELECT bname as result FROM ' . sql_table('blog') . ' WHERE bnumber=' . intval($id) );
\r
722 function getBlogIDFromItemID($itemid) {
\r
723 return quickQuery('SELECT iblog as result FROM ' . sql_table('item') . ' WHERE inumber=' . intval($itemid) );
\r
726 function getBlogIDFromCommentID($commentid) {
\r
727 return quickQuery('SELECT cblog as result FROM ' . sql_table('comment') . ' WHERE cnumber=' . intval($commentid) );
\r
730 function getBlogIDFromCatID($catid) {
\r
731 return quickQuery('SELECT cblog as result FROM ' . sql_table('category') . ' WHERE catid=' . intval($catid) );
\r
734 function getCatIDFromName($name) {
\r
735 return quickQuery('SELECT catid as result FROM ' . sql_table('category') . ' WHERE cname="' . addslashes($name) . '"');
\r
738 function quickQuery($q) {
\r
739 $res = sql_query($q);
\r
740 $obj = mysql_fetch_object($res);
\r
741 return $obj->result;
\r
744 function getPluginNameFromPid($pid) {
\r
745 $res = sql_query('SELECT pfile FROM ' . sql_table('plugin') . ' WHERE pid=' . intval($pid) );
\r
746 $obj = mysql_fetch_object($res);
\r
747 return $obj->pfile;
\r
750 function selector() {
\r
751 global $itemid, $blogid, $memberid, $query, $amount, $archivelist, $maxresults;
\r
752 global $archive, $skinid, $blog, $memberinfo, $CONF, $member;
\r
753 global $imagepopup, $catid;
\r
756 $actionNames = array('addcomment', 'sendmessage', 'createaccount', 'forgotpassword', 'votepositive', 'votenegative', 'plugin');
\r
757 $action = requestVar('action');
\r
759 if (in_array($action, $actionNames) ) {
\r
760 global $DIR_LIBS, $errormessage;
\r
761 include_once($DIR_LIBS . 'ACTION.php');
\r
763 $errorInfo = $a->doAction($action);
\r
766 $errormessage = $errorInfo['message'];
\r
770 // show error when headers already sent out
\r
771 if (headers_sent() && $CONF['alertOnHeadersSent']) {
\r
773 // try to get line number/filename (extra headers_sent params only exists in PHP 4.3+)
\r
774 if (function_exists('version_compare') && version_compare('4.3.0', phpversion(), '<=') ) {
\r
775 headers_sent($hsFile, $hsLine);
\r
776 $extraInfo = ' in <code>' . $hsFile . '</code> line <code>' . $hsLine . '</code>';
\r
782 '<p>The page headers have already been sent out' . $extraInfo . '. This could cause Nucleus not to work in the expected way.</p><p>Usually, this is caused by spaces or newlines at the end of the <code>config.php</code> file, at the end of the language file or at the end of a plugin file. Please check this and try again.</p><p>If you don\'t want to see this error message again, without solving the problem, set <code>$CONF[\'alertOnHeadersSent\']</code> in <code>globalfunctions.php</code> to <code>0</code></p>',
\r
783 'Page headers already sent'
\r
788 // make is so ?archivelist without blogname or blogid shows the archivelist
\r
789 // for the default weblog
\r
790 if (serverVar('QUERY_STRING') == 'archivelist') {
\r
791 $archivelist = $CONF['DefaultBlog'];
\r
794 // now decide which type of skin we need
\r
796 // itemid given -> only show that item
\r
799 if (!$manager->existsItem($itemid,0,0) ) {
\r
800 doError(_ERROR_NOSUCHITEM);
\r
803 global $itemidprev, $itemidnext, $catid, $itemtitlenext, $itemtitleprev;
\r
805 // 1. get timestamp, blogid and catid for item
\r
806 $query = 'SELECT itime, iblog, icat FROM ' . sql_table('item') . ' WHERE inumber=' . intval($itemid);
\r
807 $res = sql_query($query);
\r
808 $obj = mysql_fetch_object($res);
\r
810 // if a different blog id has been set through the request or selectBlog(),
\r
812 // if ($blogid && (intval($blogid) != $obj->iblog) ) {
\r
813 // doError(_ERROR_NOSUCHITEM);
\r
815 if ($blogid && (intval($blogid) != $obj->iblog) ) {
\r
816 if (!headers_sent()) {
\r
817 $b =& $manager->getBlog($obj->iblog);
\r
818 $CONF['ItemURL'] = $b->getURL();
\r
819 if ($CONF['URLMode'] == 'pathinfo' and substr($CONF['ItemURL'],-1) == '/')
\r
820 $CONF['ItemURL'] = substr($CONF['ItemURL'], 0, -1);
\r
821 $correctURL = createItemLink($itemid, '');
\r
822 redirect($correctURL);
\r
825 doError(_ERROR_NOSUCHITEM);
\r
829 // if a category has been selected which doesn't match the item, ignore the
\r
831 if (($catid != 0) && ($catid != $obj->icat) ) {
\r
835 $blogid = $obj->iblog;
\r
836 $timestamp = strtotime($obj->itime);
\r
838 $b =& $manager->getBlog($blogid);
\r
840 if ($b->isValidCategory($catid) ) {
\r
841 $catextra = ' and icat=' . $catid;
\r
846 // get previous itemid and title
\r
847 $query = 'SELECT inumber, ititle FROM ' . sql_table('item') . ' WHERE itime<' . mysqldate($timestamp) . ' and idraft=0 and iblog=' . $blogid . $catextra . ' ORDER BY itime DESC LIMIT 1';
\r
848 $res = sql_query($query);
\r
850 $obj = mysql_fetch_object($res);
\r
853 $itemidprev = $obj->inumber;
\r
854 $itemtitleprev = $obj->ititle;
\r
857 // get next itemid and title
\r
858 $query = 'SELECT inumber, ititle FROM ' . sql_table('item') . ' WHERE itime>' . mysqldate($timestamp) . ' and itime <= ' . mysqldate($b->getCorrectTime()) . ' and idraft=0 and iblog=' . $blogid . $catextra . ' ORDER BY itime ASC LIMIT 1';
\r
859 $res = sql_query($query);
\r
861 $obj = mysql_fetch_object($res);
\r
864 $itemidnext = $obj->inumber;
\r
865 $itemtitlenext = $obj->ititle;
\r
868 } elseif ($archive) {
\r
872 // get next and prev month links ...
\r
873 global $archivenext, $archiveprev, $archivetype, $archivenextexists, $archiveprevexists;
\r
875 // sql queries for the timestamp of the first and the last published item
\r
876 $query = "SELECT UNIX_TIMESTAMP(itime) as result FROM ".sql_table('item')." WHERE idraft=0 AND iblog=".(int)($blogid ? $blogid : $CONF['DefaultBlog'])." ORDER BY itime ASC";
\r
877 $first_timestamp=quickQuery ($query);
\r
878 $query = "SELECT UNIX_TIMESTAMP(itime) as result FROM ".sql_table('item')." WHERE idraft=0 AND iblog=".(int)($blogid ? $blogid : $CONF['DefaultBlog'])." ORDER BY itime DESC";
\r
879 $last_timestamp=quickQuery ($query);
\r
881 sscanf($archive, '%d-%d-%d', $y, $m, $d);
\r
884 $archivetype = _ARCHIVETYPE_DAY;
\r
885 $t = mktime(0, 0, 0, $m, $d, $y);
\r
886 // one day has 24 * 60 * 60 = 86400 seconds
\r
887 $archiveprev = strftime('%Y-%m-%d', $t - 86400 );
\r
888 // check for published items
\r
889 if ($t > $first_timestamp) {
\r
890 $archiveprevexists = true;
\r
893 $archiveprevexists = false;
\r
898 $archivenext = strftime('%Y-%m-%d', $t);
\r
899 if ($t < $last_timestamp) {
\r
900 $archivenextexists = true;
\r
903 $archivenextexists = false;
\r
907 $archivetype = _ARCHIVETYPE_MONTH;
\r
908 $t = mktime(0, 0, 0, $m, 1, $y);
\r
909 // one day before is in the previous month
\r
910 $archiveprev = strftime('%Y-%m', $t - 86400);
\r
911 if ($t > $first_timestamp) {
\r
912 $archiveprevexists = true;
\r
915 $archiveprevexists = false;
\r
918 // timestamp for the next month
\r
919 $t = mktime(0, 0, 0, $m+1, 1, $y);
\r
920 $archivenext = strftime('%Y-%m', $t);
\r
921 if ($t < $last_timestamp) {
\r
922 $archivenextexists = true;
\r
925 $archivenextexists = false;
\r
929 } elseif ($archivelist) {
\r
930 $type = 'archivelist';
\r
932 if (is_numeric($archivelist)) {
\r
933 $blogid = intVal($archivelist);
\r
935 $blogid = getBlogIDFromName($archivelist);
\r
939 doError(_ERROR_NOSUCHBLOG);
\r
942 } elseif ($query) {
\r
945 $query = stripslashes($query);
\r
946 if(preg_match("/^(\xA1{2}|\xe3\x80{2}|\x20)+$/", $query)){
\r
949 $order = (_CHARSET == 'EUC-JP') ? 'EUC-JP, UTF-8,' : 'UTF-8, EUC-JP,';
\r
950 $query = mb_convert_encoding($query, _CHARSET, $order . ' JIS, SJIS, ASCII');
\r
951 if (is_numeric($blogid)) {
\r
952 $blogid = intVal($blogid);
\r
954 $blogid = getBlogIDFromName($blogid);
\r
958 doError(_ERROR_NOSUCHBLOG);
\r
961 } elseif ($memberid) {
\r
964 if (!MEMBER::existsID($memberid) ) {
\r
965 doError(_ERROR_NOSUCHMEMBER);
\r
968 $memberinfo = $manager->getMember($memberid);
\r
970 } elseif ($imagepopup) {
\r
971 // media object (images etc.)
\r
972 $type = 'imagepopup';
\r
974 // TODO: check if media-object exists
\r
975 // TODO: set some vars?
\r
977 // show regular index page
\r
982 // decide which blog should be displayed
\r
984 $blogid = $CONF['DefaultBlog'];
\r
987 $b =& $manager->getBlog($blogid);
\r
988 $blog = $b; // references can't be placed in global variables?
\r
990 if (!$blog->isValid) {
\r
991 doError(_ERROR_NOSUCHBLOG);
\r
994 // set catid if necessary
\r
996 $blog->setSelectedCategory($catid);
\r
999 // decide which skin should be used
\r
1000 if ($skinid != '' && ($skinid == 0) ) {
\r
1001 selectSkin($skinid);
\r
1005 $skinid = $blog->getDefaultSkin();
\r
1008 $special = requestVar('special');
\r
1009 if (!empty($special) && isValidShortName($special)) {
\r
1010 $type = strtolower($special);
\r
1013 $skin = new SKIN($skinid);
\r
1015 if (!$skin->isValid) {
\r
1016 doError(_ERROR_NOSUCHSKIN);
\r
1020 $skin->parse($type);
\r
1022 // check to see we should throw JustPosted event
\r
1023 $blog->checkJustPosted();
\r
1027 * Show error skin with given message. An optional skin-object to use can be given
\r
1029 function doError($msg, $skin = '') {
\r
1030 global $errormessage, $CONF, $skinid, $blogid, $manager;
\r
1032 if ($skin == '') {
\r
1034 if (SKIN::existsID($skinid) ) {
\r
1035 $skin = new SKIN($skinid);
\r
1036 } elseif ($manager->existsBlogID($blogid) ) {
\r
1037 $blog =& $manager->getBlog($blogid);
\r
1038 $skin = new SKIN($blog->getDefaultSkin() );
\r
1039 } elseif ($CONF['DefaultBlog']) {
\r
1040 $blog =& $manager->getBlog($CONF['DefaultBlog']);
\r
1041 $skin = new SKIN($blog->getDefaultSkin() );
\r
1043 // this statement should actually never be executed
\r
1044 $skin = new SKIN($CONF['BaseSkin']);
\r
1049 $errormessage = $msg;
\r
1050 $skin->parse('error');
\r
1054 function getConfig() {
\r
1057 $query = 'SELECT * FROM ' . sql_table('config');
\r
1058 $res = sql_query($query);
\r
1060 while ($obj = mysql_fetch_object($res) ) {
\r
1061 $CONF[$obj->name] = $obj->value;
\r
1065 // some checks for names of blogs, categories, templates, members, ...
\r
1066 function isValidShortName($name) {
\r
1067 return eregi('^[a-z0-9]+$', $name);
\r
1070 function isValidDisplayName($name) {
\r
1071 return eregi('^[a-z0-9]+[a-z0-9 ]*[a-z0-9]+$', $name);
\r
1074 function isValidCategoryName($name) {
\r
1078 function isValidTemplateName($name) {
\r
1079 return eregi('^[a-z0-9/]+$', $name);
\r
1082 function isValidSkinName($name) {
\r
1083 return eregi('^[a-z0-9/]+$', $name);
\r
1086 // add and remove linebreaks
\r
1087 function addBreaks($var) {
\r
1088 return nl2br($var);
\r
1091 function removeBreaks($var) {
\r
1092 return preg_replace("/<br \/>([\r\n])/", "$1", $var);
\r
1095 // shortens a text string to maxlength ($toadd) is what needs to be added
\r
1096 // at the end (end length is <= $maxlength)
\r
1097 function shorten($text, $maxlength, $toadd) {
\r
1098 // 1. remove entities...
\r
1099 // $trans = get_html_translation_table(HTML_ENTITIES);
\r
1100 $trans = get_html_translation_table(HTML_SPECIALCHARS); // for Japanese
\r
1101 $trans = array_flip($trans);
\r
1102 $text = strtr($text, $trans);
\r
1104 // 2. the actual shortening
\r
1105 if (strlen($text) > $maxlength)
\r
1106 $text = mb_strimwidth($text, 0, $maxlength, $toadd, _CHARSET);
\r
1111 * Converts a unix timestamp to a mysql DATETIME format, and places
\r
1112 * quotes around it.
\r
1114 function mysqldate($timestamp) {
\r
1115 return '"' . date('Y-m-d H:i:s', $timestamp) . '"';
\r
1119 * functions for use in index.php
\r
1121 function selectBlog($shortname) {
\r
1122 global $blogid, $archivelist;
\r
1123 $blogid = getBlogIDFromName($shortname);
\r
1125 // also force archivelist variable, if it is set
\r
1126 if ($archivelist) {
\r
1127 $archivelist = $blogid;
\r
1131 function selectSkin($skinname) {
\r
1133 $skinid = SKIN::getIdFromName($skinname);
\r
1137 * Can take either a category ID or a category name (be aware that
\r
1138 * multiple categories can have the same name)
\r
1140 function selectCategory($cat) {
\r
1142 if (is_numeric($cat) ) {
\r
1143 $catid = intval($cat);
\r
1145 $catid = getCatIDFromName($cat);
\r
1149 function selectItem($id) {
\r
1151 $itemid = intval($id);
\r
1154 // force the use of a language file (warning: can cause warnings)
\r
1155 function selectLanguage($language) {
\r
1157 include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');
\r
1160 function parseFile($filename, $includeMode = 'normal', $includePrefix = '') {
\r
1161 $handler = new ACTIONS('fileparser');
\r
1162 $parser = new PARSER(SKIN::getAllowedActionsForType('fileparser'), $handler);
\r
1163 $handler->parser =& $parser;
\r
1165 // set IncludeMode properties of parser
\r
1166 PARSER::setProperty('IncludeMode', $includeMode);
\r
1167 PARSER::setProperty('IncludePrefix', $includePrefix);
\r
1169 if (!file_exists($filename) ) {
\r
1170 doError('A file is missing');
\r
1173 $fsize = filesize($filename);
\r
1175 if ($fsize <= 0) {
\r
1180 $fd = fopen ($filename, 'r');
\r
1181 $contents = fread ($fd, $fsize);
\r
1184 // parse file contents
\r
1185 $parser->parse($contents);
\r
1189 * Outputs a debug message
\r
1191 function debug($msg) {
\r
1192 echo '<p><b>' . $msg . "</b></p>\n";
\r
1196 function addToLog($level, $msg) {
\r
1197 ACTIONLOG::add($level, $msg);
\r
1200 // shows a link to help file
\r
1201 function help($id) {
\r
1202 echo helpHtml($id);
\r
1205 function helpHtml($id) {
\r
1207 return helplink($id) . '<img src="' . $CONF['AdminURL'] . 'documentation/icon-help.gif" width="15" height="15" alt="' . _HELP_TT . '" /></a>';
\r
1210 function helplink($id) {
\r
1212 return '<a href="' . $CONF['AdminURL'] . 'documentation/help.html#'. $id . '" onclick="if (event && event.preventDefault) event.preventDefault(); return help(this.href);">';
\r
1215 function getMailFooter() {
\r
1216 $message = "\n\n-----------------------------";
\r
1217 $message .= "\n Powered by Nucleus CMS";
\r
1218 $message .= "\n(http://www.nucleuscms.org/)";
\r
1223 * Returns the name of the language to use
\r
1224 * preference priority: member - site
\r
1225 * defaults to english when no good language found
\r
1227 * checks if file exists, etc...
\r
1229 function getLanguageName() {
\r
1230 global $CONF, $member;
\r
1232 if ($member && $member->isLoggedIn() ) {
\r
1233 // try to use members language
\r
1234 $memlang = $member->getLanguage();
\r
1236 if (($memlang != '') && (checkLanguage($memlang) ) ) {
\r
1241 // use default language
\r
1242 if (checkLanguage($CONF['Language']) ) {
\r
1243 return $CONF['Language'];
\r
1250 * Includes a PHP file. This method can be called while parsing templates and skins
\r
1252 function includephp($filename) {
\r
1253 // make predefined variables global, so most simple scripts can be used here
\r
1255 // apache (names taken from PHP doc)
\r
1256 global $GATEWAY_INTERFACE, $SERVER_NAME, $SERVER_SOFTWARE, $SERVER_PROTOCOL;
\r
1257 global $REQUEST_METHOD, $QUERY_STRING, $DOCUMENT_ROOT, $HTTP_ACCEPT;
\r
1258 global $HTTP_ACCEPT_CHARSET, $HTTP_ACCEPT_ENCODING, $HTTP_ACCEPT_LANGUAGE;
\r
1259 global $HTTP_CONNECTION, $HTTP_HOST, $HTTP_REFERER, $HTTP_USER_AGENT;
\r
1260 global $REMOTE_ADDR, $REMOTE_PORT, $SCRIPT_FILENAME, $SERVER_ADMIN;
\r
1261 global $SERVER_PORT, $SERVER_SIGNATURE, $PATH_TRANSLATED, $SCRIPT_NAME;
\r
1262 global $REQUEST_URI;
\r
1264 // php (taken from PHP doc)
\r
1265 global $argv, $argc, $PHP_SELF, $HTTP_COOKIE_VARS, $HTTP_GET_VARS, $HTTP_POST_VARS;
\r
1266 global $HTTP_POST_FILES, $HTTP_ENV_VARS, $HTTP_SERVER_VARS, $HTTP_SESSION_VARS;
\r
1269 global $PATH_INFO, $HTTPS, $HTTP_RAW_POST_DATA, $HTTP_X_FORWARDED_FOR;
\r
1271 if (@file_exists($filename) ) {
\r
1272 include($filename);
\r
1277 * Checks if a certain language/plugin exists
\r
1279 function checkLanguage($lang) {
\r
1280 global $DIR_LANG ;
\r
1281 return file_exists($DIR_LANG . ereg_replace( '[\\|/]', '', $lang) . '.php');
\r
1284 function checkPlugin($plug) {
\r
1285 global $DIR_PLUGINS;
\r
1286 return file_exists($DIR_PLUGINS . ereg_replace( '[\\|/]', '', $plug) . '.php');
\r
1290 * Centralisation of the functions that generate links
\r
1292 function createItemLink($itemid, $extra = '') {
\r
1293 return createLink('item', array('itemid' => $itemid, 'extra' => $extra) );
\r
1296 function createMemberLink($memberid, $extra = '') {
\r
1297 return createLink('member', array('memberid' => $memberid, 'extra' => $extra) );
\r
1300 function createCategoryLink($catid, $extra = '') {
\r
1301 return createLink('category', array('catid' => $catid, 'extra' => $extra) );
\r
1304 function createArchiveListLink($blogid = '', $extra = '') {
\r
1305 return createLink('archivelist', array('blogid' => $blogid, 'extra' => $extra) );
\r
1308 function createArchiveLink($blogid, $archive, $extra = '') {
\r
1309 return createLink('archive', array('blogid' => $blogid, 'archive' => $archive, 'extra' => $extra) );
\r
1312 function createBlogidLink($blogid, $params = '') {
\r
1313 return createLink('blog', array('blogid' => $blogid, 'extra' => $params) );
\r
1316 function createLink($type, $params) {
\r
1317 global $manager, $CONF;
\r
1319 $generatedURL = '';
\r
1320 $usePathInfo = ($CONF['URLMode'] == 'pathinfo');
\r
1322 // ask plugins first
\r
1325 if ($usePathInfo) {
\r
1330 'params' => $params,
\r
1331 'completed' => &$created,
\r
1337 // if a plugin created the URL, return it
\r
1342 // default implementation
\r
1345 if ($usePathInfo) {
\r
1346 $url = $CONF['ItemURL'] . '/' . $CONF['ItemKey'] . '/' . $params['itemid'];
\r
1348 $url = $CONF['ItemURL'] . '?itemid=' . $params['itemid'];
\r
1353 if ($usePathInfo) {
\r
1354 $url = $CONF['MemberURL'] . '/' . $CONF['MemberKey'] . '/' . $params['memberid'];
\r
1356 $url = $CONF['MemberURL'] . '?memberid=' . $params['memberid'];
\r
1361 if ($usePathInfo) {
\r
1362 $url = $CONF['CategoryURL'] . '/' . $CONF['CategoryKey'] . '/' . $params['catid'];
\r
1364 $url = $CONF['CategoryURL'] . '?catid=' . $params['catid'];
\r
1368 case 'archivelist':
\r
1369 if (!$params['blogid']) {
\r
1370 $params['blogid'] = $CONF['DefaultBlog'];
\r
1373 if ($usePathInfo) {
\r
1374 $url = $CONF['ArchiveListURL'] . '/' . $CONF['ArchivesKey'] . '/' . $params['blogid'];
\r
1376 $url = $CONF['ArchiveListURL'] . '?archivelist=' . $params['blogid'];
\r
1381 if ($usePathInfo) {
\r
1382 $url = $CONF['ArchiveURL'] . '/' . $CONF['ArchiveKey'] . '/'.$params['blogid'].'/' . $params['archive'];
\r
1384 $url = $CONF['ArchiveURL'] . '?blogid='.$params['blogid'].'&archive=' . $params['archive'];
\r
1389 if ($usePathInfo) {
\r
1390 $url = $CONF['BlogURL'] . '/' . $CONF['BlogKey'] . '/' . $params['blogid'];
\r
1392 $url = $CONF['BlogURL'] . '?blogid=' . $params['blogid'];
\r
1397 return addLinkParams($url, (isset($params['extra'])? $params['extra'] : null));
\r
1400 function createBlogLink($url, $params) {
\r
1402 if ($CONF['URLMode'] == 'normal') {
\r
1403 if (strpos($url, '?') === FALSE && is_array($params)) {
\r
1404 $fParam = reset($params);
\r
1405 $fKey = key($params);
\r
1406 array_shift($params);
\r
1407 $url .= '?' . $fKey . '=' . $fParam;
\r
1409 } elseif ($CONF['URLMode'] == 'pathinfo' && substr($url, -1) == '/') {
\r
1410 $url = substr($url, 0, -1);
\r
1412 return addLinkParams($url, $params);
\r
1415 function addLinkParams($link, $params) {
\r
1418 if (is_array($params) ) {
\r
1420 if ($CONF['URLMode'] == 'pathinfo') {
\r
1422 foreach ($params as $param => $value) {
\r
1423 $link .= '/' . $param . '/' . urlencode($value);
\r
1428 foreach ($params as $param => $value) {
\r
1429 $link .= '&' . $param . '=' . urlencode($value);
\r
1439 * @param $querystr
\r
1440 * querystring to alter (e.g. foo=1&bar=2&x=y)
\r
1442 * name of parameter to change (e.g. 'foo')
\r
1444 * New value for that parameter (e.g. 3)
\r
1446 * altered query string (for the examples above: foo=3&bar=2&x=y)
\r
1448 function alterQueryStr($querystr, $param, $value) {
\r
1449 $vars = explode('&', $querystr);
\r
1452 for ($i = 0; $i < count($vars); $i++) {
\r
1453 $v = explode('=', $vars[$i]);
\r
1455 if ($v[0] == $param) {
\r
1457 $vars[$i] = implode('=', $v);
\r
1464 $vars[] = $param . '=' . $value;
\r
1467 return ltrim(implode('&', $vars), '&');
\r
1470 // passes one variable as hidden input field (multiple fields for arrays)
\r
1471 // @see passRequestVars in varsx.x.x.php
\r
1472 function passVar($key, $value) {
\r
1474 if (is_array($value) ) {
\r
1475 for ($i = 0; $i < sizeof($value); $i++) {
\r
1476 passVar($key . '[' . $i . ']', $value[$i]);
\r
1482 // other values: do stripslashes if needed
\r
1483 ?><input type="hidden" name="<?php echo htmlspecialchars($key)?>" value="<?php echo htmlspecialchars(undoMagic($value) )?>" /><?php
\r
1487 Date format functions (to be used from [%date(..)%] skinvars
\r
1489 function formatDate($format, $timestamp, $defaultFormat, &$blog) {
\r
1490 // apply blog offset (#42)
\r
1491 $boffset = $blog ? $blog->getTimeOffset() * 3600 : 0;
\r
1492 $offset = date('Z', $timestamp) + $boffset;
\r
1494 switch ($format) {
\r
1496 if ($offset >= 0) {
\r
1500 $offset = -$offset;
\r
1503 $tz .= sprintf("%02d%02d", floor($offset / 3600), round(($offset % 3600) / 60) );
\r
1504 return date('D, j M Y H:i:s ', $timestamp) . $tz;
\r
1507 $timestamp -= $offset;
\r
1508 return date('D, j M Y H:i:s ', $timestamp) . 'GMT';
\r
1511 $timestamp -= $offset;
\r
1512 return date('Y-m-d\TH:i:s\Z', $timestamp);
\r
1515 if ($offset >= 0) {
\r
1519 $offset = -$offset;
\r
1522 $tz .= sprintf("%02d:%02d", floor($offset / 3600), round(($offset % 3600) / 60) );
\r
1523 return date('Y-m-d\TH:i:s', $timestamp) . $tz;
\r
1526 return strftime($format ? $format : $defaultFormat, $timestamp);
\r
1530 function encoding_check($val, $key, $encoding=false, $exclude=false) {
\r
1532 When 3rd argument is set, return if checked already.
\r
1533 When 4th argument is set, set the excluded key(s).
\r
1535 static $search=false, $checked=array(), $excludes=array();
\r
1536 if ($exclude!==false) {
\r
1537 if (is_array($exclude)) {
\r
1538 foreach($exclude as $v) $excludes[$v]=true;
\r
1539 } else $excludes[$exclude]=true;
\r
1542 if ($encoding!==false) {
\r
1543 switch($encoding=strtolower($encoding)){
\r
1545 $search='/([\x00-\x7F]+'.
\r
1546 '|[\xC2-\xDF][\x80-\xBF]'.
\r
1547 '|[\xE0-\xEF][\x80-\xBF][\x80-\xBF]'.
\r
1548 '|[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF]'.
\r
1549 '|[\xF8-\xFB][\x80-\xBF][\x80-\xBF][\x80-\xBF][\x80-\xBF]'.
\r
1550 '|[\xFC-\xFD][\x80-\xBF][\x80-\xBF][\x80-\xBF][\x80-\xBF][\x80-\xBF])/';
\r
1553 $search='/([\x00-\x7F]+'.
\r
1554 '|[\x8E][\xA0-\xDF]'.
\r
1555 '|[\x8F]?[\xA1-\xFE][\xA1-\xFE])/';
\r
1558 $search='/([\x00-\x7F]+'.
\r
1559 '|[\xA1-\xF7][\xA1-\xFE])/';
\r
1562 // Note that shift_jis is only supported for output.
\r
1563 // Using shift_jis in DB is prohibited.
\r
1564 $search='/([\x00-\x7F\xA1-\xDF]+'.
\r
1565 '|[\x81-\x9F\xE0-\xFC][\x40-\xFC])/';
\r
1569 if (preg_match('/^iso\-8859\-[0-9]{1,2}$/',$encoding)) break;
\r
1570 if (preg_match('/^windows\-125[0-8]$/',$encoding)) break;
\r
1571 startUpError('<p>Unknown or non-supported encoding.</p>', 'Encoding Error');
\r
1574 if (isset($checked[$encoding])) return true; // Already checked.
\r
1575 $checked[$encoding]=true;
\r
1577 if ($key===false) return false; // Not yet checked.
\r
1578 if ($search===false) return true; // non-multibyte encoding
\r
1579 if (isset($excludes[$key])) return true; // This key isn't checked.
\r
1580 if (is_array($val)) {
\r
1581 array_walk($val, 'encoding_check');
\r
1583 $result=preg_replace($search,'',$val);
\r
1584 if (strlen($result)!=0) {
\r
1585 startUpError('<p>Invalid input.</p>', 'Input Error');
\r
1589 $result=preg_replace($search,'',$key);
\r
1590 if (strlen($result)!=0) {
\r
1591 startUpError('<p>Invalid input.</p>', 'Input Error');
\r
1597 function checkVars($aVars) {
\r
1598 global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_ENV_VARS, $HTTP_POST_FILES, $HTTP_SESSION_VARS;
\r
1600 foreach ($aVars as $varName) {
\r
1602 if (phpversion() >= '4.1.0') {
\r
1604 if ( isset($_GET[$varName])
\r
1605 || isset($_POST[$varName])
\r
1606 || isset($_COOKIE[$varName])
\r
1607 || isset($_ENV[$varName])
\r
1608 || isset($_SESSION[$varName])
\r
1609 || isset($_FILES[$varName])
\r
1611 die('Sorry. An error occurred.');
\r
1616 if ( isset($HTTP_GET_VARS[$varName])
\r
1617 || isset($HTTP_POST_VARS[$varName])
\r
1618 || isset($HTTP_COOKIE_VARS[$varName])
\r
1619 || isset($HTTP_ENV_VARS[$varName])
\r
1620 || isset($HTTP_SESSION_VARS[$varName])
\r
1621 || isset($HTTP_POST_FILES[$varName])
\r
1623 die('Sorry. An error occurred.');
\r
1632 * Sanitize parameters such as $_GET and $_SERVER['REQUEST_URI'] etc.
\r
1635 function sanitizeParams()
\r
1637 global $HTTP_SERVER_VARS;
\r
1643 // REQUEST_URI of $HTTP_SERVER_VARS
\r
1644 $str =& $HTTP_SERVER_VARS["REQUEST_URI"];
\r
1645 serverStringToArray($str, $array, $frontParam);
\r
1646 sanitizeArray($array);
\r
1647 arrayToServerString($array, $frontParam, $str);
\r
1649 // QUERY_STRING of $HTTP_SERVER_VARS
\r
1650 $str =& $HTTP_SERVER_VARS["QUERY_STRING"];
\r
1651 serverStringToArray($str, $array, $frontParam);
\r
1652 sanitizeArray($array);
\r
1653 arrayToServerString($array, $frontParam, $str);
\r
1655 if (phpversion() >= '4.1.0') {
\r
1656 // REQUEST_URI of $_SERVER
\r
1657 $str =& $_SERVER["REQUEST_URI"];
\r
1658 serverStringToArray($str, $array, $frontParam);
\r
1659 sanitizeArray($array);
\r
1660 arrayToServerString($array, $frontParam, $str);
\r
1662 // QUERY_STRING of $_SERVER
\r
1663 $str =& $_SERVER["QUERY_STRING"];
\r
1664 serverStringToArray($str, $array, $frontParam);
\r
1665 sanitizeArray($array);
\r
1666 arrayToServerString($array, $frontParam, $str);
\r
1670 convArrayForSanitizing($_GET, $array);
\r
1671 sanitizeArray($array);
\r
1672 revertArrayForSanitizing($array, $_GET);
\r
1674 // $_REQUEST (only GET param)
\r
1675 convArrayForSanitizing($_REQUEST, $array);
\r
1676 sanitizeArray($array);
\r
1677 revertArrayForSanitizing($array, $_REQUEST);
\r
1681 * Check ticket when not checked in plugin's admin page
\r
1683 * Also avoid the access to plugin/index.php by guest user.
\r
1685 function ticketForPlugin(){
\r
1686 global $CONF,$DIR_PLUGINS,$member,$ticketforplugin;
\r
1689 $ticketforplugin=array();
\r
1690 $ticketforplugin['ticket']=false;
\r
1692 /* Check if using plugin's php file. */
\r
1693 if ($p_translated=serverVar('PATH_TRANSLATED')) {
\r
1694 if (!file_exists($p_translated)) $p_translated='';
\r
1696 if (!$p_translated) {
\r
1697 $p_translated=serverVar('SCRIPT_FILENAME');
\r
1698 if (!file_exists($p_translated)) {
\r
1699 header("HTTP/1.0 404 Not Found");
\r
1703 $p_translated=str_replace('\\','/',$p_translated);
\r
1704 $d_plugins=str_replace('\\','/',$DIR_PLUGINS);
\r
1705 if (strpos($p_translated,$d_plugins)!==0) return;// This isn't plugin php file.
\r
1707 /* Solve the plugin php file or admin directory */
\r
1708 $phppath=substr($p_translated,strlen($d_plugins));
\r
1709 $phppath=preg_replace('!^/!','',$phppath);// Remove the first "/" if exists.
\r
1710 $path=preg_replace('/^NP_(.*)\.php$/','$1',$phppath); // Remove the first "NP_" and the last ".php" if exists.
\r
1711 $path=preg_replace('!^([^/]*)/(.*)$!','$1',$path); // Remove the "/" and beyond.
\r
1713 /* Solve the plugin name. */
\r
1715 $query='SELECT pfile FROM '.sql_table('plugin');
\r
1716 $res=sql_query($query);
\r
1717 while($row=mysql_fetch_row($res)) {
\r
1718 $name=substr($row[0],3);
\r
1719 $plugins[strtolower($name)]=$name;
\r
1721 mysql_free_result($res);
\r
1722 if ($plugins[$path]) $plugin_name=$plugins[$path];
\r
1723 else if (in_array($path,$plugins)) $plugin_name=$path;
\r
1725 header("HTTP/1.0 404 Not Found");
\r
1729 /* Return if not index.php */
\r
1730 if ( $phppath!=strtolower($plugin_name).'/'
\r
1731 && $phppath!=strtolower($plugin_name).'/index.php' ) return;
\r
1733 /* Exit if not logged in. */
\r
1734 if ( !$member->isLoggedIn() ) exit("You aren't logged in.");
\r
1736 global $manager,$DIR_LIBS,$DIR_LANG,$HTTP_GET_VARS,$HTTP_POST_VARS;
\r
1738 /* Check if this feature is needed (ie, if "$manager->checkTicket()" is not included in the script). */
\r
1739 if (!($p_translated=serverVar('PATH_TRANSLATED'))) $p_translated=serverVar('SCRIPT_FILENAME');
\r
1740 if ($file=@file($p_translated)) {
\r
1742 foreach($file as $line) {
\r
1743 if (preg_match('/[\$]manager([\s]*)[\-]>([\s]*)checkTicket([\s]*)[\(]/i',$prevline.$line)) return;
\r
1748 /* Show a form if not valid ticket */
\r
1749 if ( ( strstr(serverVar('REQUEST_URI'),'?') || serverVar('QUERY_STRING')
\r
1750 || strtoupper(serverVar('REQUEST_METHOD'))=='POST' )
\r
1751 && (!$manager->checkTicket()) ){
\r
1753 if (!class_exists('PluginAdmin')) {
\r
1754 $language = getLanguageName();
\r
1755 include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');
\r
1756 include($DIR_LIBS . 'PLUGINADMIN.php');
\r
1758 if (!(function_exists('mb_strimwidth') || extension_loaded('mbstring'))) {
\r
1759 if (file_exists($DIR_LIBS.'mb_emulator/mb-emulator.php')) {
\r
1760 global $mbemu_internals;
\r
1761 include_once($DIR_LIBS.'mb_emulator/mb-emulator.php');
\r
1764 $oPluginAdmin = new PluginAdmin($plugin_name);
\r
1765 $oPluginAdmin->start();
\r
1766 echo '<p>' . _ERROR_BADTICKET . "</p>\n";
\r
1768 /* Show the form to confirm action */
\r
1769 // PHP 4.0.x support
\r
1770 $get= (isset($_GET)) ? $_GET : $HTTP_GET_VARS;
\r
1771 $post= (isset($_POST)) ? $_POST : $HTTP_POST_VARS;
\r
1772 // Resolve URI and QUERY_STRING
\r
1773 if ($uri=serverVar('REQUEST_URI')) {
\r
1774 list($uri,$qstring)=explode('?',$uri);
\r
1776 if ( !($uri=serverVar('PHP_SELF')) ) $uri=serverVar('SCRIPT_NAME');
\r
1777 $qstring=serverVar('QUERY_STRING');
\r
1779 if ($qstring) $qstring='?'.$qstring;
\r
1780 echo '<p>'._SETTINGS_UPDATE.' : '._QMENU_PLUGINS.' <span style="color:red;">'.
\r
1781 htmlspecialchars($plugin_name)."</span> ?</p>\n";
\r
1782 switch(strtoupper(serverVar('REQUEST_METHOD'))){
\r
1784 echo '<form method="POST" action="'.htmlspecialchars($uri.$qstring).'">';
\r
1785 $manager->addTicketHidden();
\r
1786 _addInputTags($post);
\r
1789 echo '<form method="GET" action="'.htmlspecialchars($uri).'">';
\r
1790 $manager->addTicketHidden();
\r
1791 _addInputTags($get);
\r
1795 echo '<input type="submit" value="'._YES.'" /> ';
\r
1796 echo '<input type="button" value="'._NO.'" onclick="history.back(); return false;" />';
\r
1799 $oPluginAdmin->end();
\r
1803 /* Create new ticket */
\r
1804 $ticket=$manager->addTicketToUrl('');
\r
1805 $ticketforplugin['ticket']=substr($ticket,strpos($ticket,'ticket=')+7);
\r
1807 function _addInputTags(&$keys,$prefix=''){
\r
1808 foreach($keys as $key=>$value){
\r
1809 if ($prefix) $key=$prefix.'['.$key.']';
\r
1810 if (is_array($value)) _addInputTags($value,$key);
\r
1812 if (get_magic_quotes_gpc()) $value=stripslashes($value);
\r
1813 if ($key=='ticket') continue;
\r
1814 echo '<input type="hidden" name="'.htmlspecialchars($key).
\r
1815 '" value="'.htmlspecialchars($value).'" />'."\n";
\r
1821 * Convert the server string such as $_SERVER['REQUEST_URI']
\r
1822 * to arry like arry['blogid']=1 and array['page']=2 etc.
\r
1824 function serverStringToArray($str, &$array, &$frontParam)
\r
1830 // split front param, e.g. /index.php, and others, e.g. blogid=1&page=2
\r
1831 if (strstr($str, "?")){
\r
1832 list($frontParam, $args) = preg_split("/\?/", $str, 2);
\r
1839 // If there is no args like blogid=1&page=2, return
\r
1840 if (!strstr($str, "=") && !strlen($frontParam)) {
\r
1841 $frontParam = $str;
\r
1845 $array = explode("&", $args);
\r
1849 * Convert array like array['blogid'] to server string
\r
1850 * such as $_SERVER['REQUEST_URI']
\r
1852 function arrayToServerString($array, $frontParam, &$str)
\r
1854 if (strstr($str, "?")) {
\r
1855 $str = $frontParam . "?";
\r
1857 $str = $frontParam;
\r
1859 if (count($array)) {
\r
1860 $str .= implode("&", $array);
\r
1865 * Sanitize array parameters.
\r
1866 * This function checks both key and value.
\r
1867 * - check key if it inclues " (double quote), remove from array
\r
1868 * - check value if it includes \ (escape sequece), remove remaining string
\r
1870 function sanitizeArray(&$array)
\r
1872 $excludeListForSanitization = array('query');
\r
1873 // $excludeListForSanitization = array();
\r
1875 foreach ($array as $k => $v) {
\r
1877 // split to key and value
\r
1878 list($key, $val) = preg_split("/=/", $v, 2);
\r
1879 if (!isset($val)) {
\r
1883 // when magic quotes is on, need to use stripslashes,
\r
1884 // and then addslashes
\r
1885 if (get_magic_quotes_gpc()) {
\r
1886 $val = stripslashes($val);
\r
1888 $val = addslashes($val);
\r
1890 // if $key is included in exclude list, skip this param
\r
1891 if (!in_array($key, $excludeListForSanitization)) {
\r
1894 @list($val, $tmp) = explode('\\', $val);
\r
1896 // remove control code etc.
\r
1897 $val = strtr($val, "\0\r\n<>'\"", " ");
\r
1900 if (preg_match('/\"/i', $key)) {
\r
1901 unset($array[$k]);
\r
1905 // set sanitized info
\r
1906 $array[$k] = sprintf("%s=%s", $key, $val);
\r
1912 * Convert array for sanitizeArray function
\r
1914 function convArrayForSanitizing($src, &$array)
\r
1917 foreach ($src as $key => $val) {
\r
1918 if (key_exists($key, $_GET)) {
\r
1919 array_push($array, sprintf("%s=%s", $key, $val));
\r
1925 * Revert array after sanitizeArray function
\r
1927 function revertArrayForSanitizing($array, &$dst)
\r
1929 foreach ($array as $v) {
\r
1930 list($key, $val) = preg_split("/=/", $v, 2);
\r
1931 $dst[$key] = $val;
\r
1936 * Stops processing the request and redirects to the given URL.
\r
1937 * - no actual contents should have been sent to the output yet
\r
1938 * - the URL will be stripped of illegal or dangerous characters
\r
1940 function redirect($url) {
\r
1941 $url = preg_replace('|[^a-z0-9-~+_.?#=&;,/:@%*]|i', '', $url);
\r
1942 header('Location: ' . $url);
\r
1947 * Strip HTML tags from a string
\r
1948 * This function is a bit more intelligent than a regular call to strip_tags(),
\r
1949 * because it also deletes the contents of certain tags and cleans up any
\r
1950 * unneeded whitespace.
\r
1952 function stringStripTags ($string) {
\r
1953 $string = preg_replace("/<del[^>]*>.+<\/del[^>]*>/isU", '', $string);
\r
1954 $string = preg_replace("/<script[^>]*>.+<\/script[^>]*>/isU", '', $string);
\r
1955 $string = preg_replace("/<style[^>]*>.+<\/style[^>]*>/isU", '', $string);
\r
1956 $string = str_replace('>', '> ', $string);
\r
1957 $string = str_replace('<', ' <', $string);
\r
1958 $string = strip_tags($string);
\r
1959 $string = preg_replace("/\s+/", " ", $string);
\r
1960 $string = trim($string);
\r
1965 * Make a string containing HTML safe for use in a HTML attribute
\r
1966 * Tags are stripped and entities are normalized
\r
1968 function stringToAttribute ($string) {
\r
1969 $string = stringStripTags($string);
\r
1970 $string = entity::named_to_numeric($string);
\r
1971 $string = entity::normalize_numeric($string);
\r
1973 if (_CHARSET == 'UTF-8') {
\r
1974 $string = entity::numeric_to_utf8($string);
\r
1977 $string = entity::specialchars($string, 'html');
\r
1978 $string = entity::numeric_to_named($string);
\r
1983 * Make a string containing HTML safe for use in a XML document
\r
1984 * Tags are stripped, entities are normalized and named entities are
\r
1985 * converted to numeric entities.
\r
1987 function stringToXML ($string) {
\r
1988 $string = stringStripTags($string);
\r
1989 $string = entity::named_to_numeric($string);
\r
1990 $string = entity::normalize_numeric($string);
\r
1992 if (_CHARSET == 'UTF-8') {
\r
1993 $string = entity::numeric_to_utf8($string);
\r
1996 $string = entity::specialchars($string, 'xml');
\r
2000 // START: functions from the end of file BLOG.php
\r
2001 // used for mail notification (html -> text)
\r
2002 function toAscii($html) {
\r
2003 // strip off most tags
\r
2004 $html = strip_tags($html,'<a>');
\r
2005 $to_replace = "/<a[^>]*href=[\"\']([^\"^']*)[\"\'][^>]*>([^<]*)<\/a>/i";
\r
2007 $ascii = preg_replace_callback ($to_replace, '_links_add', $html);
\r
2008 $ascii .= "\n\n" . _links_list();
\r
2009 return strip_tags($ascii);
\r
2012 function _links_init() {
\r
2013 global $tmp_links;
\r
2014 $tmp_links = array();
\r
2017 function _links_add($match) {
\r
2018 global $tmp_links;
\r
2019 array_push($tmp_links, $match[1]);
\r
2020 return $match[2] . ' [' . sizeof($tmp_links) .']';
\r
2023 function _links_list() {
\r
2024 global $tmp_links;
\r
2027 foreach ($tmp_links as $current) {
\r
2028 $output .= "[$i] $current\n";
\r
2033 // END: functions from the end of file BLOG.php
\r
2035 // START: functions from the end of file ADMIN.php
\r
2037 * @todo document this
\r
2039 function encode_desc(&$data)
\r
2040 { //_$to_entities = get_html_translation_table(HTML_ENTITIES);
\r
2041 $to_entities = get_html_translation_table(HTML_SPECIALCHARS);
\r
2042 $from_entities = array_flip($to_entities);
\r
2043 $data = str_replace('<br />', '\n', $data); //hack
\r
2044 $data = strtr($data,$from_entities);
\r
2045 $data = strtr($data,$to_entities);
\r
2046 $data = str_replace('\n', '<br />', $data); //hack
\r
2051 * Returns the Javascript code for a bookmarklet that works on most modern browsers
\r
2055 function getBookmarklet($blogid) {
\r
2059 $document = 'document';
\r
2060 $bookmarkletline = "javascript:Q='';x=".$document.";y=window;if(x.selection){Q=x.selection.createRange().text;}else if(y.getSelection){Q=y.getSelection();}else if(x.getSelection){Q=x.getSelection();}wingm=window.open('";
\r
2061 $bookmarkletline .= $CONF['AdminURL'] . "bookmarklet.php?blogid=$blogid";
\r
2062 $bookmarkletline .="&logtext='+escape(Q)+'&loglink='+escape(x.location.href)+'&loglinktitle='+escape(x.title),'nucleusbm','toolbar=no,scrollbars=no,width=600,height=550,left=10,top=10,status=no,resizable=yes');wingm.focus();";
\r
2064 return $bookmarkletline;
\r
2066 // END: functions from the end of file ADMIN.php
\r
2069 * Returns a variable or null if not set
\r
2071 * @param mixed Variable
\r
2072 * @return mixed Variable
\r
2074 function ifset(&$var) {
\r
2075 if (isset($var)) {
\r
2083 * Returns number of subscriber to an event
\r
2086 * @return number of subscriber(s)
\r
2088 function numberOfEventSubscriber($event) {
\r
2089 $query = 'SELECT COUNT(*) as count FROM ' . sql_table('plugin_event') . ' WHERE event=\'' . $event . '\'';
\r
2090 $res = sql_query($query);
\r
2091 $obj = mysql_fetch_object($res);
\r
2092 return $obj->count;
\r