4 * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
\r
5 * Copyright (C) 2002-2007 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-2007 The Nucleus Group
\r
16 * @version $Id: globalfunctions.php,v 1.24 2008-02-08 09:31:22 kimitake Exp $
\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.4';
\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 if (!isset($CONF['Self'])) {
\r
37 $CONF['Self'] = htmlspecialchars($_SERVER['PHP_SELF'],ENT_QUOTES);
\r
41 Indicates when Nucleus should display startup errors. Set to 1 if you want
\r
42 the error enabled (default), false otherwise
\r
45 Displays an error when visiting a public Nucleus page and headers have
\r
46 been sent out to early. This usually indicates an error in either a
\r
47 configuration file or a language file, and could cause Nucleus to
\r
50 Displays an error only when visiting the admin area, and when one or
\r
51 more of the installation files (install.php, install.sql, upgrades/
\r
52 directory) are still on the server.
\r
54 $CONF['alertOnHeadersSent'] = 1;
\r
55 $CONF['alertOnSecurityRisk'] = 1;
\r
56 $CONF['ItemURL'] = $CONF['Self'];
\r
57 $CONF['ArchiveURL'] = $CONF['Self'];
\r
58 $CONF['ArchiveListURL'] = $CONF['Self'];
\r
59 $CONF['MemberURL'] = $CONF['Self'];
\r
60 $CONF['SearchURL'] = $CONF['Self'];
\r
61 $CONF['BlogURL'] = $CONF['Self'];
\r
62 $CONF['CategoryURL'] = $CONF['Self'];
\r
64 // switch URLMode back to normal when $CONF['Self'] ends in .php
\r
65 // this avoids urls like index.php/item/13/index.php/item/15
\r
66 if (!isset($CONF['URLMode']) || (($CONF['URLMode'] == 'pathinfo') && (substr($CONF['Self'], strlen($CONF['Self']) - 4) == '.php'))) {
\r
67 $CONF['URLMode'] = 'normal';
\r
70 if (getNucleusPatchLevel() > 0) {
\r
71 $nucleus['version'] .= '/' . getNucleusPatchLevel();
\r
75 if (!isset($CONF['installscript'])) {
\r
76 $CONF['installscript'] = 0;
\r
79 // we will use postVar, getVar, ... methods instead of HTTP_GET_VARS or _GET
\r
80 if ($CONF['installscript'] != 1) { // vars were already included in install.php
\r
81 if (phpversion() >= '4.1.0') {
\r
82 include_once($DIR_LIBS . 'vars4.1.0.php');
\r
84 include_once($DIR_LIBS . 'vars4.0.6.php');
\r
89 $bLoggingSanitizedResult=0;
\r
90 $bSanitizeAndContinue=0;
\r
92 $orgRequestURI = serverVar('REQUEST_URI');
\r
95 // get all variables that can come from the request and put them in the global scope
\r
96 $blogid = requestVar('blogid');
\r
97 $itemid = intRequestVar('itemid');
\r
98 $catid = intRequestVar('catid');
\r
99 $skinid = requestVar('skinid');
\r
100 $memberid = requestVar('memberid');
\r
101 $archivelist = requestVar('archivelist');
\r
102 $imagepopup = requestVar('imagepopup');
\r
103 $archive = requestVar('archive');
\r
104 $query = requestVar('query');
\r
105 $highlight = requestVar('highlight');
\r
106 $amount = requestVar('amount');
\r
107 $action = requestVar('action');
\r
108 $nextaction = requestVar('nextaction');
\r
109 $maxresults = requestVar('maxresults');
\r
110 $startpos = intRequestVar('startpos');
\r
111 $errormessage = '';
\r
113 $virtualpath = ((getVar('virtualpath') != null) ? getVar('virtualpath') : serverVar('PATH_INFO'));
\r
115 if (!headers_sent() ) {
\r
116 header('Generator: Nucleus CMS ' . $nucleus['version']);
\r
119 // include core classes that are needed for login & plugin handling
\r
120 include($DIR_LIBS . 'mysql.php');
\r
121 include($DIR_LIBS . 'MEMBER.php');
\r
122 include($DIR_LIBS . 'ACTIONLOG.php');
\r
123 include($DIR_LIBS . 'MANAGER.php');
\r
124 include($DIR_LIBS . 'PLUGIN.php');
\r
126 $manager =& MANAGER::instance();
\r
128 // make sure there's no unnecessary escaping:
\r
129 set_magic_quotes_runtime(0);
\r
132 if (!isset($CONF['UsingAdminArea'])) {
\r
133 $CONF['UsingAdminArea'] = 0;
\r
136 // only needed when updating logs
\r
137 if ($CONF['UsingAdminArea']) {
\r
138 include($DIR_LIBS . 'xmlrpc.inc.php'); // XML-RPC client classes
\r
139 include_once($DIR_LIBS . 'ADMIN.php');
\r
142 // connect to database
\r
146 // logs sanitized result if need
\r
147 if ($orgRequestURI!==serverVar('REQUEST_URI')) {
\r
148 $msg = "Sanitized [" . serverVar('REMOTE_ADDR') . "] ";
\r
149 $msg .= $orgRequestURI . " -> " . serverVar('REQUEST_URI');
\r
150 if ($bLoggingSanitizedResult) {
\r
151 addToLog(WARNING, $msg);
\r
153 if (!$bSanitizeAndContinue) {
\r
158 // makes sure database connection gets closed on script termination
\r
159 register_shutdown_function('sql_disconnect');
\r
164 // automatically use simpler toolbar for mozilla
\r
165 if (($CONF['DisableJsTools'] == 0) && strstr(serverVar('HTTP_USER_AGENT'), 'Mozilla/5.0') && strstr(serverVar('HTTP_USER_AGENT'), 'Gecko') ) {
\r
166 $CONF['DisableJsTools'] = 2;
\r
169 // login if cookies set
\r
170 $member = new MEMBER();
\r
172 // secure cookie key settings (either 'none', 0, 8, 16, 24, or 32)
\r
173 if (!isset($CONF['secureCookieKey'])) $CONF['secureCookieKey']=24;
\r
174 switch($CONF['secureCookieKey']){
\r
176 $CONF['secureCookieKeyIP']=preg_replace('/\.[0-9]+\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
\r
179 $CONF['secureCookieKeyIP']=preg_replace('/\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
\r
182 $CONF['secureCookieKeyIP']=preg_replace('/\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
\r
185 $CONF['secureCookieKeyIP']=serverVar('REMOTE_ADDR');
\r
188 $CONF['secureCookieKeyIP']='';
\r
191 // login/logout when required or renew cookies
\r
192 if ($action == 'login') {
\r
193 // Form Authentication
\r
194 $login = postVar('login');
\r
195 $pw = postVar('password');
\r
196 $shared = intPostVar('shared'); // shared computer or not
\r
198 $pw=substr($pw,0,40); // avoid md5 collision by using a long key
\r
200 if ($member->login($login, $pw) ) {
\r
202 $member->newCookieKey();
\r
203 $member->setCookies($shared);
\r
205 if ($CONF['secureCookieKey']!=='none') {
\r
206 // secure cookie key
\r
207 $member->setCookieKey(md5($member->getCookieKey().$CONF['secureCookieKeyIP']));
\r
211 // allows direct access to parts of the admin area after logging in
\r
213 $action = $nextaction;
\r
216 $manager->notify('LoginSuccess', array('member' => &$member) );
\r
217 $errormessage = '';
\r
218 ACTIONLOG::add(INFO, "Login successful for $login (sharedpc=$shared)");
\r
220 // errormessage for [%errordiv%]
\r
221 $errormessage = 'Login failed for ' . $login;
\r
223 $manager->notify('LoginFailed', array('username' => $login) );
\r
224 ACTIONLOG::add(INFO, $errormessage);
\r
228 Backed out for now: See http://forum.nucleuscms.org/viewtopic.php?t=3684 for details
\r
230 } elseif (serverVar('PHP_AUTH_USER') && serverVar('PHP_AUTH_PW')) {
\r
231 // HTTP Authentication
\r
232 $login = serverVar('PHP_AUTH_USER');
\r
233 $pw = serverVar('PHP_AUTH_PW');
\r
235 if ($member->login($login, $pw) ) {
\r
236 $manager->notify('LoginSuccess',array('member' => &$member));
\r
237 ACTIONLOG::add(INFO, "HTTP authentication successful for $login");
\r
239 $manager->notify('LoginFailed',array('username' => $login));
\r
240 ACTIONLOG::add(INFO, 'HTTP authentication failed for ' . $login);
\r
242 //Since bad credentials, generate an apropriate error page
\r
243 header("WWW-Authenticate: Basic realm=\"Nucleus CMS {$nucleus['version']}\"");
\r
244 header('HTTP/1.0 401 Unauthorized');
\r
245 echo 'Invalid username or password';
\r
250 } elseif (($action == 'logout') && (!headers_sent() ) && cookieVar($CONF['CookiePrefix'] . 'user') ) {
\r
251 // remove cookies on logout
\r
252 setcookie($CONF['CookiePrefix'] . 'user', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
\r
253 setcookie($CONF['CookiePrefix'] . 'loginkey', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
\r
254 $manager->notify('Logout', array('username' => cookieVar($CONF['CookiePrefix'] . 'user') ) );
\r
255 } elseif (cookieVar($CONF['CookiePrefix'] . 'user') ) {
\r
256 // Cookie Authentication
\r
257 $ck=cookieVar($CONF['CookiePrefix'] . 'loginkey');
\r
258 // secure cookie key
\r
259 $ck=substr($ck,0,32); // avoid md5 collision by using a long key
\r
260 if ($CONF['secureCookieKey']!=='none') $ck=md5($ck.$CONF['secureCookieKeyIP']);
\r
261 $res = $member->cookielogin(cookieVar($CONF['CookiePrefix'] . 'user'), $ck );
\r
264 // renew cookies when not on a shared computer
\r
265 if ($res && (cookieVar($CONF['CookiePrefix'] . 'sharedpc') != 1) && (!headers_sent() ) ) {
\r
266 $member->setCookieKey(cookieVar($CONF['CookiePrefix'] . 'loginkey'));
\r
267 $member->setCookies();
\r
272 $manager->notify('PostAuthentication', array('loggedIn' => $member->isLoggedIn() ) );
\r
275 // first, let's see if the site is disabled or not. always allow admin area access.
\r
276 if ($CONF['DisableSite'] && !$member->isAdmin() && !$CONF['UsingAdminArea']) {
\r
277 redirect($CONF['DisableSiteURL']);
\r
281 // load other classes
\r
282 include($DIR_LIBS . 'PARSER.php');
\r
283 include($DIR_LIBS . 'SKIN.php');
\r
284 include($DIR_LIBS . 'TEMPLATE.php');
\r
285 include($DIR_LIBS . 'BLOG.php');
\r
286 include($DIR_LIBS . 'BODYACTIONS.php');
\r
287 include($DIR_LIBS . 'COMMENTS.php');
\r
288 include($DIR_LIBS . 'COMMENT.php');
\r
289 //include($DIR_LIBS . 'ITEM.php');
\r
290 include($DIR_LIBS . 'NOTIFICATION.php');
\r
291 include($DIR_LIBS . 'BAN.php');
\r
292 include($DIR_LIBS . 'PAGEFACTORY.php');
\r
293 include($DIR_LIBS . 'SEARCH.php');
\r
294 include($DIR_LIBS . 'entity.php');
\r
297 // set lastVisit cookie (if allowed)
\r
298 if (!headers_sent() ) {
\r
299 if ($CONF['LastVisit']) {
\r
300 setcookie($CONF['CookiePrefix'] . 'lastVisit', time(), time() + 2592000, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
\r
302 setcookie($CONF['CookiePrefix'] . 'lastVisit', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
\r
306 // read language file, only after user has been initialized
\r
307 $language = getLanguageName();
\r
308 include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');
\r
310 // check if valid charset
\r
311 if (!encoding_check(false,false,_CHARSET)) {
\r
312 foreach(array($_REQUEST, $_SERVER) as $input) {
\r
313 array_walk($input, 'encoding_check');
\r
318 Backed out for now: See http://forum.nucleuscms.org/viewtopic.php?t=3684 for details
\r
320 // To remove after v2.5 is released and language files have been updated.
\r
321 // Including this makes sure that language files for v2.5beta can still be used for v2.5final
\r
322 // without having weird _SETTINGS_EXTAUTH string showing up in the admin area.
\r
323 if (!defined('_MEMBERS_BYPASS'))
\r
325 define('_SETTINGS_EXTAUTH', 'Enable External Authentication');
\r
326 define('_WARNING_EXTAUTH', 'Warning: Enable only if needed.');
\r
327 define('_MEMBERS_BYPASS', 'Use External Authentication');
\r
332 // make sure the archivetype skinvar keeps working when _ARCHIVETYPE_XXX not defined
\r
333 if (!defined('_ARCHIVETYPE_MONTH') ) {
\r
334 define('_ARCHIVETYPE_DAY', 'day');
\r
335 define('_ARCHIVETYPE_MONTH', 'month');
\r
338 // decode path_info
\r
339 if ($CONF['URLMode'] == 'pathinfo') {
\r
340 // initialize keywords if this hasn't been done before
\r
341 if ($CONF['ItemKey'] == '') {
\r
342 $CONF['ItemKey'] = 'item';
\r
345 if ($CONF['ArchiveKey'] == '') {
\r
346 $CONF['ArchiveKey'] = 'archive';
\r
349 if ($CONF['ArchivesKey'] == '') {
\r
350 $CONF['ArchivesKey'] = 'archives';
\r
353 if ($CONF['MemberKey'] == '') {
\r
354 $CONF['MemberKey'] = 'member';
\r
357 if ($CONF['BlogKey'] == '') {
\r
358 $CONF['BlogKey'] = 'blog';
\r
361 if ($CONF['CategoryKey'] == '') {
\r
362 $CONF['CategoryKey'] = 'category';
\r
365 if ($CONF['SpecialskinKey'] == '') {
\r
366 $CONF['SpecialskinKey'] = 'special';
\r
373 'type' => basename(serverVar('SCRIPT_NAME') ), // e.g. item, blog, ...
\r
374 'info' => $virtualpath,
\r
375 'complete' => &$parsed
\r
380 // default implementation
\r
381 $data = explode("/", $virtualpath );
\r
382 for ($i = 0; $i < sizeof($data); $i++) {
\r
383 switch ($data[$i]) {
\r
384 case $CONF['ItemKey']: // item/1 (blogid)
\r
387 if ($i < sizeof($data) ) {
\r
388 $itemid = intval($data[$i]);
\r
392 case $CONF['ArchivesKey']: // archives/1 (blogid)
\r
395 if ($i < sizeof($data) ) {
\r
396 $archivelist = intval($data[$i]);
\r
400 case $CONF['ArchiveKey']: // two possibilities: archive/yyyy-mm or archive/1/yyyy-mm (with blogid)
\r
401 if ((($i + 1) < sizeof($data) ) && (!strstr($data[$i + 1], '-') ) ) {
\r
402 $blogid = intval($data[++$i]);
\r
407 if ($i < sizeof($data) ) {
\r
408 $archive = $data[$i];
\r
412 case 'blogid': // blogid/1
\r
413 case $CONF['BlogKey']: // blog/1
\r
416 if ($i < sizeof($data) ) {
\r
417 $blogid = intval($data[$i]);
\r
421 case $CONF['CategoryKey']: // category/1 (catid)
\r
425 if ($i < sizeof($data) ) {
\r
426 $catid = intval($data[$i]);
\r
430 case $CONF['MemberKey']:
\r
433 if ($i < sizeof($data) ) {
\r
434 $memberid = intval($data[$i]);
\r
438 case $CONF['SpecialskinKey']:
\r
441 if ($i < sizeof($data) ) {
\r
442 $_REQUEST['special'] = $data[$i];
\r
453 function intPostVar($name) {
\r
454 return intval(postVar($name) );
\r
457 function intGetVar($name) {
\r
458 return intval(getVar($name) );
\r
461 function intRequestVar($name) {
\r
462 return intval(requestVar($name) );
\r
465 function intCookieVar($name) {
\r
466 return intval(cookieVar($name) );
\r
470 * returns the currently used version (100 = 1.00, 101 = 1.01, etc...)
\r
472 function getNucleusVersion() {
\r
477 * power users can install patches in between nucleus releases. These patches
\r
478 * usually add new functionality in the plugin API and allow those to
\r
479 * be tested without having to install CVS.
\r
481 function getNucleusPatchLevel() {
\r
486 * Connects to mysql server
\r
488 function sql_connect() {
\r
489 global $MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWORD, $MYSQL_DATABASE, $MYSQL_CONN;
\r
491 $MYSQL_CONN = @mysql_connect($MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWORD) or startUpError('<p>Could not connect to MySQL database.</p>', 'Connect Error');
\r
492 mysql_select_db($MYSQL_DATABASE) or startUpError('<p>Could not select database: ' . mysql_error() . '</p>', 'Connect Error');
\r
494 return $MYSQL_CONN;
\r
498 * returns a prefixed nucleus table name
\r
500 function sql_table($name) {
\r
501 global $MYSQL_PREFIX;
\r
503 if ($MYSQL_PREFIX) {
\r
504 return $MYSQL_PREFIX . 'nucleus_' . $name;
\r
506 return 'nucleus_' . $name;
\r
510 function sendContentType($contenttype, $pagetype = '', $charset = _CHARSET) {
\r
511 global $manager, $CONF;
\r
513 if (!headers_sent() ) {
\r
514 // if content type is application/xhtml+xml, only send it to browsers
\r
515 // that can handle it (IE6 cannot). Otherwise, send text/html
\r
517 // v2.5: For admin area pages, keep sending text/html (unless it's a debug version)
\r
518 // application/xhtml+xml still causes too much problems with the javascript implementations
\r
520 // v3.3: ($CONF['UsingAdminArea'] && !$CONF['debug']) gets removed,
\r
521 // application/xhtml+xml seems to be working, so we're going to use it if we can.
\r
523 // Note: reverted the following function in JP version
\r
528 ($contenttype == 'application/xhtml+xml')
\r
529 && (!stristr(serverVar('HTTP_ACCEPT'), 'application/xhtml+xml') )
\r
531 $contenttype = 'text/html';
\r
536 ($contenttype == 'application/xhtml+xml')
\r
537 && (($CONF['UsingAdminArea'] && !$CONF['debug']) || !stristr(serverVar('HTTP_ACCEPT'),'application/xhtml+xml'))
\r
540 $contenttype = 'text/html';
\r
544 'PreSendContentType',
\r
546 'contentType' => &$contenttype,
\r
547 'charset' => &$charset,
\r
548 'pageType' => $pagetype
\r
552 // strip strange characters
\r
553 $contenttype = preg_replace('|[^a-z0-9-+./]|i', '', $contenttype);
\r
554 $charset = preg_replace('|[^a-z0-9-_]|i', '', $charset);
\r
556 if ($charset != '') {
\r
557 header('Content-Type: ' . $contenttype . '; charset=' . $charset);
\r
559 header('Content-Type: ' . $contenttype);
\r
562 // check if valid charset
\r
563 if (!encoding_check(false,false,$charset)) {
\r
564 foreach(array($_REQUEST, $_SERVER) as $input) {
\r
565 array_walk($input, 'encoding_check');
\r
572 * Errors before the database connection has been made
\r
574 function startUpError($msg, $title) {
\r
575 if (!defined('_CHARSET')) define('_CHARSET','iso-8859-1');
\r
576 header('Content-Type: text/html; charset=' . _CHARSET);
\r
578 <html xmlns="http://www.w3.org/1999/xhtml">
\r
579 <head><meta http-equiv="Content-Type" content="text/html; charset=<?php echo _CHARSET?>" />
\r
580 <title><?php echo htmlspecialchars($title)?></title></head>
\r
582 <h1><?php echo htmlspecialchars($title)?></h1>
\r
590 * disconnects from SQL server
\r
592 function sql_disconnect() {
\r
597 * executes an SQL query
\r
599 function sql_query($query) {
\r
602 $res = mysql_query($query) or print("mySQL error with query $query: " . mysql_error() . '<p />');
\r
608 * Highlights a specific query in a given HTML text (not within HTML tags) and returns it
\r
611 * text to be highlighted
\r
612 * @param $expression
\r
613 * regular expression to be matched (can be an array of expressions as well)
\r
614 * @param $highlight
\r
615 * highlight to be used (use \\0 to indicate the matched expression)
\r
618 function highlight($text, $expression, $highlight) {
\r
619 if (!$highlight || !$expression) {
\r
623 if (is_array($expression) && (count($expression) == 0) ) {
\r
627 // add a tag in front (is needed for preg_match_all to work correct)
\r
628 $text = '<!--h-->' . $text;
\r
630 // split the HTML up so we have HTML tags
\r
631 // $matches[0][i] = HTML + text
\r
632 // $matches[1][i] = HTML
\r
633 // $matches[2][i] = text
\r
634 preg_match_all('/(<[^>]+>)([^<>]*)/', $text, $matches);
\r
636 // throw it all together again while applying the highlight to the text pieces
\r
638 for ($i = 0; $i < sizeof($matches[2]); $i++) {
\r
640 $result .= $matches[1][$i];
\r
643 if (is_array($expression) ) {
\r
644 foreach ($expression as $regex) {
\r
646 $matches[2][$i] = @eregi_replace($regex, $highlight, $matches[2][$i]);
\r
650 $result .= $matches[2][$i];
\r
652 $result .= @eregi_replace($expression, $highlight, $matches[2][$i]);
\r
660 * Parses a query into an array of expressions that can be passed on to the highlight method
\r
662 function parseHighlight($query) {
\r
663 // TODO: add more intelligent splitting logic
\r
665 // get rid of quotes
\r
666 $query = preg_replace('/\'|"/', '', $query);
\r
672 $aHighlight = explode(' ', $query);
\r
674 for ($i = 0; $i < count($aHighlight); $i++) {
\r
675 $aHighlight[$i] = trim($aHighlight[$i]);
\r
677 if (strlen($aHighlight[$i]) < 3) {
\r
678 unset($aHighlight[$i]);
\r
682 if (count($aHighlight) == 1) {
\r
683 return $aHighlight[0];
\r
685 return $aHighlight;
\r
690 * Checks if email address is valid
\r
692 function isValidMailAddress($address) {
\r
693 if (preg_match('/^[a-zA-Z+0-9\._-]+@[a-zA-Z0-9\._-]+\.[A-Za-z]{2,5}$/', $address)) {
\r
701 // some helper functions
\r
702 function getBlogIDFromName($name) {
\r
703 return quickQuery('SELECT bnumber as result FROM ' . sql_table('blog') . ' WHERE bshortname="' . addslashes($name) . '"');
\r
706 function getBlogNameFromID($id) {
\r
707 return quickQuery('SELECT bname as result FROM ' . sql_table('blog') . ' WHERE bnumber=' . intval($id) );
\r
710 function getBlogIDFromItemID($itemid) {
\r
711 return quickQuery('SELECT iblog as result FROM ' . sql_table('item') . ' WHERE inumber=' . intval($itemid) );
\r
714 function getBlogIDFromCommentID($commentid) {
\r
715 return quickQuery('SELECT cblog as result FROM ' . sql_table('comment') . ' WHERE cnumber=' . intval($commentid) );
\r
718 function getBlogIDFromCatID($catid) {
\r
719 return quickQuery('SELECT cblog as result FROM ' . sql_table('category') . ' WHERE catid=' . intval($catid) );
\r
722 function getCatIDFromName($name) {
\r
723 return quickQuery('SELECT catid as result FROM ' . sql_table('category') . ' WHERE cname="' . addslashes($name) . '"');
\r
726 function quickQuery($q) {
\r
727 $res = sql_query($q);
\r
728 $obj = mysql_fetch_object($res);
\r
729 return $obj->result;
\r
732 function getPluginNameFromPid($pid) {
\r
733 $res = sql_query('SELECT pfile FROM ' . sql_table('plugin') . ' WHERE pid=' . intval($pid) );
\r
734 $obj = mysql_fetch_object($res);
\r
735 return $obj->pfile;
\r
738 function selector() {
\r
739 global $itemid, $blogid, $memberid, $query, $amount, $archivelist, $maxresults;
\r
740 global $archive, $skinid, $blog, $memberinfo, $CONF, $member;
\r
741 global $imagepopup, $catid;
\r
744 $actionNames = array('addcomment', 'sendmessage', 'createaccount', 'forgotpassword', 'votepositive', 'votenegative', 'plugin');
\r
745 $action = requestVar('action');
\r
747 if (in_array($action, $actionNames) ) {
\r
748 global $DIR_LIBS, $errormessage;
\r
749 include_once($DIR_LIBS . 'ACTION.php');
\r
751 $errorInfo = $a->doAction($action);
\r
754 $errormessage = $errorInfo['message'];
\r
758 // show error when headers already sent out
\r
759 if (headers_sent() && $CONF['alertOnHeadersSent']) {
\r
761 // try to get line number/filename (extra headers_sent params only exists in PHP 4.3+)
\r
762 if (function_exists('version_compare') && version_compare('4.3.0', phpversion(), '<=') ) {
\r
763 headers_sent($hsFile, $hsLine);
\r
764 $extraInfo = ' in <code>' . $hsFile . '</code> line <code>' . $hsLine . '</code>';
\r
770 '<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
771 'Page headers already sent'
\r
776 // make is so ?archivelist without blogname or blogid shows the archivelist
\r
777 // for the default weblog
\r
778 if (serverVar('QUERY_STRING') == 'archivelist') {
\r
779 $archivelist = $CONF['DefaultBlog'];
\r
782 // now decide which type of skin we need
\r
784 // itemid given -> only show that item
\r
787 if (!$manager->existsItem($itemid,0,0) ) {
\r
788 doError(_ERROR_NOSUCHITEM);
\r
791 global $itemidprev, $itemidnext, $catid, $itemtitlenext, $itemtitleprev;
\r
793 // 1. get timestamp, blogid and catid for item
\r
794 $query = 'SELECT itime, iblog, icat FROM ' . sql_table('item') . ' WHERE inumber=' . intval($itemid);
\r
795 $res = sql_query($query);
\r
796 $obj = mysql_fetch_object($res);
\r
798 // if a different blog id has been set through the request or selectBlog(),
\r
800 // if ($blogid && (intval($blogid) != $obj->iblog) ) {
\r
801 // doError(_ERROR_NOSUCHITEM);
\r
803 if ($blogid && (intval($blogid) != $obj->iblog) ) {
\r
804 if (!headers_sent()) {
\r
805 $b =& $manager->getBlog($obj->iblog);
\r
806 $CONF['ItemURL'] = $b->getURL();
\r
807 if ($CONF['URLMode'] == 'pathinfo' and substr($CONF['ItemURL'],-1) == '/')
\r
808 $CONF['ItemURL'] = substr($CONF['ItemURL'], 0, -1);
\r
809 $correctURL = createItemLink($itemid, '');
\r
810 redirect($correctURL);
\r
813 doError(_ERROR_NOSUCHITEM);
\r
817 // if a category has been selected which doesn't match the item, ignore the
\r
819 if (($catid != 0) && ($catid != $obj->icat) ) {
\r
823 $blogid = $obj->iblog;
\r
824 $timestamp = strtotime($obj->itime);
\r
826 $b =& $manager->getBlog($blogid);
\r
828 if ($b->isValidCategory($catid) ) {
\r
829 $catextra = ' and icat=' . $catid;
\r
832 // get previous itemid and title
\r
833 $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
834 $res = sql_query($query);
\r
836 $obj = mysql_fetch_object($res);
\r
839 $itemidprev = $obj->inumber;
\r
840 $itemtitleprev = $obj->ititle;
\r
843 // get next itemid and title
\r
844 $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
845 $res = sql_query($query);
\r
847 $obj = mysql_fetch_object($res);
\r
850 $itemidnext = $obj->inumber;
\r
851 $itemtitlenext = $obj->ititle;
\r
854 } elseif ($archive) {
\r
858 // get next and prev month links ...
\r
859 global $archivenext, $archiveprev, $archivetype, $archivenextexists, $archiveprevexists;
\r
861 // sql queries for the timestamp of the first and the last published item
\r
862 $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
863 $first_timestamp=quickQuery ($query);
\r
864 $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
865 $last_timestamp=quickQuery ($query);
\r
867 sscanf($archive, '%d-%d-%d', $y, $m, $d);
\r
870 $archivetype = _ARCHIVETYPE_DAY;
\r
871 $t = mktime(0, 0, 0, $m, $d, $y);
\r
872 // one day has 24 * 60 * 60 = 86400 seconds
\r
873 $archiveprev = strftime('%Y-%m-%d', $t - 86400 );
\r
874 // check for published items
\r
875 if ($t > $first_timestamp) {
\r
876 $archiveprevexists = true;
\r
879 $archiveprevexists = false;
\r
884 $archivenext = strftime('%Y-%m-%d', $t);
\r
885 if ($t < $last_timestamp) {
\r
886 $archivenextexists = true;
\r
889 $archivenextexists = false;
\r
893 $archivetype = _ARCHIVETYPE_MONTH;
\r
894 $t = mktime(0, 0, 0, $m, 1, $y);
\r
895 // one day before is in the previous month
\r
896 $archiveprev = strftime('%Y-%m', $t - 86400);
\r
897 if ($t > $first_timestamp) {
\r
898 $archiveprevexists = true;
\r
901 $archiveprevexists = false;
\r
904 // timestamp for the next month
\r
905 $t = mktime(0, 0, 0, $m+1, 1, $y);
\r
906 $archivenext = strftime('%Y-%m', $t);
\r
907 if ($t < $last_timestamp) {
\r
908 $archivenextexists = true;
\r
911 $archivenextexists = false;
\r
915 } elseif ($archivelist) {
\r
916 $type = 'archivelist';
\r
918 if (is_numeric($archivelist)) {
\r
919 $blogid = intVal($archivelist);
\r
921 $blogid = getBlogIDFromName($archivelist);
\r
925 doError(_ERROR_NOSUCHBLOG);
\r
928 } elseif ($query) {
\r
931 $query = stripslashes($query);
\r
932 if(preg_match("/^(\xA1{2}|\xe3\x80{2}|\x20)+$/",$query)){
\r
935 $order = (_CHARSET == 'EUC-JP') ? 'EUC-JP, UTF-8,' : 'UTF-8, EUC-JP,';
\r
936 $query = mb_convert_encoding($query, _CHARSET, $order.' JIS, SJIS, ASCII');
\r
937 if (is_numeric($blogid)) {
\r
938 $blogid = intVal($blogid);
\r
940 $blogid = getBlogIDFromName($blogid);
\r
944 doError(_ERROR_NOSUCHBLOG);
\r
947 } elseif ($memberid) {
\r
950 if (!MEMBER::existsID($memberid) ) {
\r
951 doError(_ERROR_NOSUCHMEMBER);
\r
954 $memberinfo = $manager->getMember($memberid);
\r
956 } elseif ($imagepopup) {
\r
957 // media object (images etc.)
\r
958 $type = 'imagepopup';
\r
960 // TODO: check if media-object exists
\r
961 // TODO: set some vars?
\r
963 // show regular index page
\r
968 // decide which blog should be displayed
\r
970 $blogid = $CONF['DefaultBlog'];
\r
973 $b =& $manager->getBlog($blogid);
\r
974 $blog = $b; // references can't be placed in global variables?
\r
976 if (!$blog->isValid) {
\r
977 doError(_ERROR_NOSUCHBLOG);
\r
980 // set catid if necessary
\r
982 $blog->setSelectedCategory($catid);
\r
985 // decide which skin should be used
\r
986 if ($skinid != '' && ($skinid == 0) ) {
\r
987 selectSkin($skinid);
\r
991 $skinid = $blog->getDefaultSkin();
\r
994 $special = requestVar('special');
\r
995 if (!empty($special) && isValidShortName($special)) {
\r
996 $type = strtolower($special);
\r
999 $skin = new SKIN($skinid);
\r
1001 if (!$skin->isValid) {
\r
1002 doError(_ERROR_NOSUCHSKIN);
\r
1006 $skin->parse($type);
\r
1008 // check to see we should throw JustPosted event
\r
1009 $blog->checkJustPosted();
\r
1013 * Show error skin with given message. An optional skin-object to use can be given
\r
1015 function doError($msg, $skin = '') {
\r
1016 global $errormessage, $CONF, $skinid, $blogid, $manager;
\r
1018 if ($skin == '') {
\r
1020 if (SKIN::existsID($skinid) ) {
\r
1021 $skin = new SKIN($skinid);
\r
1022 } elseif ($manager->existsBlogID($blogid) ) {
\r
1023 $blog =& $manager->getBlog($blogid);
\r
1024 $skin = new SKIN($blog->getDefaultSkin() );
\r
1025 } elseif ($CONF['DefaultBlog']) {
\r
1026 $blog =& $manager->getBlog($CONF['DefaultBlog']);
\r
1027 $skin = new SKIN($blog->getDefaultSkin() );
\r
1029 // this statement should actually never be executed
\r
1030 $skin = new SKIN($CONF['BaseSkin']);
\r
1035 $errormessage = $msg;
\r
1036 $skin->parse('error');
\r
1040 function getConfig() {
\r
1043 $query = 'SELECT * FROM ' . sql_table('config');
\r
1044 $res = sql_query($query);
\r
1046 while ($obj = mysql_fetch_object($res) ) {
\r
1047 $CONF[$obj->name] = $obj->value;
\r
1051 // some checks for names of blogs, categories, templates, members, ...
\r
1052 function isValidShortName($name) {
\r
1053 return eregi('^[a-z0-9]+$', $name);
\r
1056 function isValidDisplayName($name) {
\r
1057 return eregi('^[a-z0-9]+[a-z0-9 ]*[a-z0-9]+$', $name);
\r
1060 function isValidCategoryName($name) {
\r
1064 function isValidTemplateName($name) {
\r
1065 return eregi('^[a-z0-9/]+$', $name);
\r
1068 function isValidSkinName($name) {
\r
1069 return eregi('^[a-z0-9/]+$', $name);
\r
1072 // add and remove linebreaks
\r
1073 function addBreaks($var) {
\r
1074 return nl2br($var);
\r
1077 function removeBreaks($var) {
\r
1078 return preg_replace("/<br \/>([\r\n])/", "$1", $var);
\r
1081 // shortens a text string to maxlength ($toadd) is what needs to be added
\r
1082 // at the end (end length is <= $maxlength)
\r
1083 function shorten($text, $maxlength, $toadd) {
\r
1084 // 1. remove entities...
\r
1085 // $trans = get_html_translation_table(HTML_ENTITIES);
\r
1086 $trans = get_html_translation_table(HTML_SPECIALCHARS); // for Japanese
\r
1087 $trans = array_flip($trans);
\r
1088 $text = strtr($text, $trans);
\r
1090 // 2. the actual shortening
\r
1091 if (strlen($text) > $maxlength)
\r
1092 $text = mb_strimwidth($text, 0, $maxlength, $toadd, _CHARSET);
\r
1097 * Converts a unix timestamp to a mysql DATETIME format, and places
\r
1098 * quotes around it.
\r
1100 function mysqldate($timestamp) {
\r
1101 return '"' . date('Y-m-d H:i:s', $timestamp) . '"';
\r
1105 * functions for use in index.php
\r
1107 function selectBlog($shortname) {
\r
1108 global $blogid, $archivelist;
\r
1109 $blogid = getBlogIDFromName($shortname);
\r
1111 // also force archivelist variable, if it is set
\r
1112 if ($archivelist) {
\r
1113 $archivelist = $blogid;
\r
1117 function selectSkin($skinname) {
\r
1119 $skinid = SKIN::getIdFromName($skinname);
\r
1123 * Can take either a category ID or a category name (be aware that
\r
1124 * multiple categories can have the same name)
\r
1126 function selectCategory($cat) {
\r
1128 if (is_numeric($cat) ) {
\r
1129 $catid = intval($cat);
\r
1131 $catid = getCatIDFromName($cat);
\r
1135 function selectItem($id) {
\r
1137 $itemid = intval($id);
\r
1140 // force the use of a language file (warning: can cause warnings)
\r
1141 function selectLanguage($language) {
\r
1143 include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');
\r
1146 function parseFile($filename, $includeMode = 'normal', $includePrefix = '') {
\r
1147 $handler = new ACTIONS('fileparser');
\r
1148 $parser = new PARSER(SKIN::getAllowedActionsForType('fileparser'), $handler);
\r
1149 $handler->parser =& $parser;
\r
1151 // set IncludeMode properties of parser
\r
1152 PARSER::setProperty('IncludeMode', $includeMode);
\r
1153 PARSER::setProperty('IncludePrefix', $includePrefix);
\r
1155 if (!file_exists($filename) ) {
\r
1156 doError('A file is missing');
\r
1159 $fsize = filesize($filename);
\r
1161 if ($fsize <= 0) {
\r
1166 $fd = fopen ($filename, 'r');
\r
1167 $contents = fread ($fd, $fsize);
\r
1170 // parse file contents
\r
1171 $parser->parse($contents);
\r
1175 * Outputs a debug message
\r
1177 function debug($msg) {
\r
1178 echo '<p><b>' . $msg . "</b></p>\n";
\r
1182 function addToLog($level, $msg) {
\r
1183 ACTIONLOG::add($level, $msg);
\r
1186 // shows a link to help file
\r
1187 function help($id) {
\r
1188 echo helpHtml($id);
\r
1191 function helpHtml($id) {
\r
1192 return helplink($id) . '<img src="documentation/icon-help.gif" width="15" height="15" alt="' . _HELP_TT . '" /></a>';
\r
1195 function helplink($id) {
\r
1196 return '<a href="documentation/help.html#'. $id . '" onclick="if (event && event.preventDefault) event.preventDefault(); return help(this.href);">';
\r
1199 function getMailFooter() {
\r
1200 $message = "\n\n-----------------------------";
\r
1201 $message .= "\n Powered by Nucleus CMS";
\r
1202 $message .= "\n(http://www.nucleuscms.org/)";
\r
1207 * Returns the name of the language to use
\r
1208 * preference priority: member - site
\r
1209 * defaults to english when no good language found
\r
1211 * checks if file exists, etc...
\r
1213 function getLanguageName() {
\r
1214 global $CONF, $member;
\r
1216 if ($member && $member->isLoggedIn() ) {
\r
1217 // try to use members language
\r
1218 $memlang = $member->getLanguage();
\r
1220 if (($memlang != '') && (checkLanguage($memlang) ) ) {
\r
1225 // use default language
\r
1226 if (checkLanguage($CONF['Language']) ) {
\r
1227 return $CONF['Language'];
\r
1234 * Includes a PHP file. This method can be called while parsing templates and skins
\r
1236 function includephp($filename) {
\r
1237 // make predefined variables global, so most simple scripts can be used here
\r
1239 // apache (names taken from PHP doc)
\r
1240 global $GATEWAY_INTERFACE, $SERVER_NAME, $SERVER_SOFTWARE, $SERVER_PROTOCOL;
\r
1241 global $REQUEST_METHOD, $QUERY_STRING, $DOCUMENT_ROOT, $HTTP_ACCEPT;
\r
1242 global $HTTP_ACCEPT_CHARSET, $HTTP_ACCEPT_ENCODING, $HTTP_ACCEPT_LANGUAGE;
\r
1243 global $HTTP_CONNECTION, $HTTP_HOST, $HTTP_REFERER, $HTTP_USER_AGENT;
\r
1244 global $REMOTE_ADDR, $REMOTE_PORT, $SCRIPT_FILENAME, $SERVER_ADMIN;
\r
1245 global $SERVER_PORT, $SERVER_SIGNATURE, $PATH_TRANSLATED, $SCRIPT_NAME;
\r
1246 global $REQUEST_URI;
\r
1248 // php (taken from PHP doc)
\r
1249 global $argv, $argc, $PHP_SELF, $HTTP_COOKIE_VARS, $HTTP_GET_VARS, $HTTP_POST_VARS;
\r
1250 global $HTTP_POST_FILES, $HTTP_ENV_VARS, $HTTP_SERVER_VARS, $HTTP_SESSION_VARS;
\r
1253 global $PATH_INFO, $HTTPS, $HTTP_RAW_POST_DATA, $HTTP_X_FORWARDED_FOR;
\r
1255 if (@file_exists($filename) ) {
\r
1256 include($filename);
\r
1261 * Checks if a certain language/plugin exists
\r
1263 function checkLanguage($lang) {
\r
1264 global $DIR_LANG ;
\r
1265 return file_exists($DIR_LANG . ereg_replace( '[\\|/]', '', $lang) . '.php');
\r
1268 function checkPlugin($plug) {
\r
1269 global $DIR_PLUGINS;
\r
1270 return file_exists($DIR_PLUGINS . ereg_replace( '[\\|/]', '', $plug) . '.php');
\r
1274 * Centralisation of the functions that generate links
\r
1276 function createItemLink($itemid, $extra = '') {
\r
1277 return createLink('item', array('itemid' => $itemid, 'extra' => $extra) );
\r
1280 function createMemberLink($memberid, $extra = '') {
\r
1281 return createLink('member', array('memberid' => $memberid, 'extra' => $extra) );
\r
1284 function createCategoryLink($catid, $extra = '') {
\r
1285 return createLink('category', array('catid' => $catid, 'extra' => $extra) );
\r
1288 function createArchiveListLink($blogid = '', $extra = '') {
\r
1289 return createLink('archivelist', array('blogid' => $blogid, 'extra' => $extra) );
\r
1292 function createArchiveLink($blogid, $archive, $extra = '') {
\r
1293 return createLink('archive', array('blogid' => $blogid, 'archive' => $archive, 'extra' => $extra) );
\r
1296 function createBlogidLink($blogid, $params = '') {
\r
1297 return createLink('blog', array('blogid' => $blogid, 'extra' => $params) );
\r
1300 function createLink($type, $params) {
\r
1301 global $manager, $CONF;
\r
1303 $generatedURL = '';
\r
1304 $usePathInfo = ($CONF['URLMode'] == 'pathinfo');
\r
1306 // ask plugins first
\r
1309 if ($usePathInfo) {
\r
1314 'params' => $params,
\r
1315 'completed' => &$created,
\r
1321 // if a plugin created the URL, return it
\r
1326 // default implementation
\r
1329 if ($usePathInfo) {
\r
1330 $url = $CONF['ItemURL'] . '/' . $CONF['ItemKey'] . '/' . $params['itemid'];
\r
1332 $url = $CONF['ItemURL'] . '?itemid=' . $params['itemid'];
\r
1337 if ($usePathInfo) {
\r
1338 $url = $CONF['MemberURL'] . '/' . $CONF['MemberKey'] . '/' . $params['memberid'];
\r
1340 $url = $CONF['MemberURL'] . '?memberid=' . $params['memberid'];
\r
1345 if ($usePathInfo) {
\r
1346 $url = $CONF['CategoryURL'] . '/' . $CONF['CategoryKey'] . '/' . $params['catid'];
\r
1348 $url = $CONF['CategoryURL'] . '?catid=' . $params['catid'];
\r
1352 case 'archivelist':
\r
1353 if (!$params['blogid']) {
\r
1354 $params['blogid'] = $CONF['DefaultBlog'];
\r
1357 if ($usePathInfo) {
\r
1358 $url = $CONF['ArchiveListURL'] . '/' . $CONF['ArchivesKey'] . '/' . $params['blogid'];
\r
1360 $url = $CONF['ArchiveListURL'] . '?archivelist=' . $params['blogid'];
\r
1365 if ($usePathInfo) {
\r
1366 $url = $CONF['ArchiveURL'] . '/' . $CONF['ArchiveKey'] . '/'.$params['blogid'].'/' . $params['archive'];
\r
1368 $url = $CONF['ArchiveURL'] . '?blogid='.$params['blogid'].'&archive=' . $params['archive'];
\r
1373 if ($usePathInfo) {
\r
1374 $url = $CONF['BlogURL'] . '/' . $CONF['BlogKey'] . '/' . $params['blogid'];
\r
1376 $url = $CONF['BlogURL'] . '?blogid=' . $params['blogid'];
\r
1381 return addLinkParams($url, (isset($params['extra'])? $params['extra'] : null));
\r
1384 function createBlogLink($url, $params) {
\r
1386 if ($CONF['URLMode'] == 'normal') {
\r
1387 if (strpos($url, '?') === FALSE && is_array($params)) {
\r
1388 $fParam = reset($params);
\r
1389 $fKey = key($params);
\r
1390 array_shift($params);
\r
1391 $url .= '?' . $fKey . '=' . $fParam;
\r
1393 } elseif ($CONF['URLMode'] == 'pathinfo' && substr($url, -1) == '/') {
\r
1394 $url = substr($url, 0, -1);
\r
1396 return addLinkParams($url, $params);
\r
1399 function addLinkParams($link, $params) {
\r
1402 if (is_array($params) ) {
\r
1404 if ($CONF['URLMode'] == 'pathinfo') {
\r
1406 foreach ($params as $param => $value) {
\r
1407 $link .= '/' . $param . '/' . urlencode($value);
\r
1412 foreach ($params as $param => $value) {
\r
1413 $link .= '&' . $param . '=' . urlencode($value);
\r
1423 * @param $querystr
\r
1424 * querystring to alter (e.g. foo=1&bar=2&x=y)
\r
1426 * name of parameter to change (e.g. 'foo')
\r
1428 * New value for that parameter (e.g. 3)
\r
1430 * altered query string (for the examples above: foo=3&bar=2&x=y)
\r
1432 function alterQueryStr($querystr, $param, $value) {
\r
1433 $vars = explode('&', $querystr);
\r
1436 for ($i = 0; $i < count($vars); $i++) {
\r
1437 $v = explode('=', $vars[$i]);
\r
1439 if ($v[0] == $param) {
\r
1441 $vars[$i] = implode('=', $v);
\r
1448 $vars[] = $param . '=' . $value;
\r
1451 return ltrim(implode('&', $vars), '&');
\r
1454 // passes one variable as hidden input field (multiple fields for arrays)
\r
1455 // @see passRequestVars in varsx.x.x.php
\r
1456 function passVar($key, $value) {
\r
1458 if (is_array($value) ) {
\r
1459 for ($i = 0; $i < sizeof($value); $i++) {
\r
1460 passVar($key . '[' . $i . ']', $value[$i]);
\r
1466 // other values: do stripslashes if needed
\r
1467 ?><input type="hidden" name="<?php echo htmlspecialchars($key)?>" value="<?php echo htmlspecialchars(undoMagic($value) )?>" /><?php
\r
1471 Date format functions (to be used from [%date(..)%] skinvars
\r
1473 function formatDate($format, $timestamp, $defaultFormat, &$blog) {
\r
1474 // apply blog offset (#42)
\r
1475 $boffset = $blog ? $blog->getTimeOffset() * 3600 : 0;
\r
1476 $offset = date('Z', $timestamp) + $boffset;
\r
1478 switch ($format) {
\r
1480 if ($offset >= 0) {
\r
1484 $offset = -$offset;
\r
1487 $tz .= sprintf("%02d%02d", floor($offset / 3600), round(($offset % 3600) / 60) );
\r
1488 return date('D, j M Y H:i:s ', $timestamp) . $tz;
\r
1491 $timestamp -= $offset;
\r
1492 return date('D, j M Y H:i:s ', $timestamp) . 'GMT';
\r
1495 $timestamp -= $offset;
\r
1496 return date('Y-m-d\TH:i:s\Z', $timestamp);
\r
1499 if ($offset >= 0) {
\r
1503 $offset = -$offset;
\r
1506 $tz .= sprintf("%02d:%02d", floor($offset / 3600), round(($offset % 3600) / 60) );
\r
1507 return date('Y-m-d\TH:i:s', $timestamp) . $tz;
\r
1510 return strftime($format ? $format : $defaultFormat, $timestamp);
\r
1514 function encoding_check($val, $key, $encoding=false, $exclude=false) {
\r
1516 When 3rd argument is set, return if checked already.
\r
1517 When 4th argument is set, set the excluded key(s).
\r
1519 static $search=false, $checked=array(), $excludes=array();
\r
1520 if ($exclude!==false) {
\r
1521 if (is_array($exclude)) {
\r
1522 foreach($exclude as $v) $excludes[$v]=true;
\r
1523 } else $excludes[$exclude]=true;
\r
1526 if ($encoding!==false) {
\r
1527 switch($encoding=strtolower($encoding)){
\r
1529 $search='/([\x00-\x7F]+'.
\r
1530 '|[\xC2-\xDF][\x80-\xBF]'.
\r
1531 '|[\xE0-\xEF][\x80-\xBF][\x80-\xBF]'.
\r
1532 '|[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF]'.
\r
1533 '|[\xF8-\xFB][\x80-\xBF][\x80-\xBF][\x80-\xBF][\x80-\xBF]'.
\r
1534 '|[\xFC-\xFD][\x80-\xBF][\x80-\xBF][\x80-\xBF][\x80-\xBF][\x80-\xBF])/';
\r
1537 $search='/([\x00-\x7F]+'.
\r
1538 '|[\x8E][\xA0-\xDF]'.
\r
1539 '|[\x8F]?[\xA1-\xFE][\xA1-\xFE])/';
\r
1542 $search='/([\x00-\x7F]+'.
\r
1543 '|[\xA1-\xF7][\xA1-\xFE])/';
\r
1546 // Note that shift_jis is only supported for output.
\r
1547 // Using shift_jis in DB is prohibited.
\r
1548 $search='/([\x00-\x7F\xA1-\xDF]+'.
\r
1549 '|[\x81-\x9F\xE0-\xFC][\x40-\xFC])/';
\r
1553 if (preg_match('/^iso\-8859\-[0-9]{1,2}$/',$encoding)) break;
\r
1554 if (preg_match('/^windows\-125[0-8]$/',$encoding)) break;
\r
1555 startUpError('<p>Unknown or non-supported encoding.</p>', 'Encoding Error');
\r
1558 if (isset($checked[$encoding])) return true; // Already checked.
\r
1559 $checked[$encoding]=true;
\r
1561 if ($key===false) return false; // Not yet checked.
\r
1562 if ($search===false) return true; // non-multibyte encoding
\r
1563 if (isset($excludes[$key])) return true; // This key isn't checked.
\r
1564 if (is_array($val)) {
\r
1565 array_walk($val, 'encoding_check');
\r
1567 $result=preg_replace($search,'',$val);
\r
1568 if (strlen($result)!=0) {
\r
1569 startUpError('<p>Invalid input.</p>', 'Input Error');
\r
1573 $result=preg_replace($search,'',$key);
\r
1574 if (strlen($result)!=0) {
\r
1575 startUpError('<p>Invalid input.</p>', 'Input Error');
\r
1581 function checkVars($aVars) {
\r
1582 global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_ENV_VARS, $HTTP_POST_FILES, $HTTP_SESSION_VARS;
\r
1584 foreach ($aVars as $varName) {
\r
1586 if (phpversion() >= '4.1.0') {
\r
1588 if ( isset($_GET[$varName])
\r
1589 || isset($_POST[$varName])
\r
1590 || isset($_COOKIE[$varName])
\r
1591 || isset($_ENV[$varName])
\r
1592 || isset($_SESSION[$varName])
\r
1593 || isset($_FILES[$varName])
\r
1595 die('Sorry. An error occurred.');
\r
1600 if ( isset($HTTP_GET_VARS[$varName])
\r
1601 || isset($HTTP_POST_VARS[$varName])
\r
1602 || isset($HTTP_COOKIE_VARS[$varName])
\r
1603 || isset($HTTP_ENV_VARS[$varName])
\r
1604 || isset($HTTP_SESSION_VARS[$varName])
\r
1605 || isset($HTTP_POST_FILES[$varName])
\r
1607 die('Sorry. An error occurred.');
\r
1616 * Sanitize parameters such as $_GET and $_SERVER['REQUEST_URI'] etc.
\r
1619 function sanitizeParams()
\r
1621 global $HTTP_SERVER_VARS;
\r
1627 // REQUEST_URI of $HTTP_SERVER_VARS
\r
1628 $str =& $HTTP_SERVER_VARS["REQUEST_URI"];
\r
1629 serverStringToArray($str, $array, $frontParam);
\r
1630 sanitizeArray($array);
\r
1631 arrayToServerString($array, $frontParam, $str);
\r
1633 // QUERY_STRING of $HTTP_SERVER_VARS
\r
1634 $str =& $HTTP_SERVER_VARS["QUERY_STRING"];
\r
1635 serverStringToArray($str, $array, $frontParam);
\r
1636 sanitizeArray($array);
\r
1637 arrayToServerString($array, $frontParam, $str);
\r
1639 if (phpversion() >= '4.1.0') {
\r
1640 // REQUEST_URI of $_SERVER
\r
1641 $str =& $_SERVER["REQUEST_URI"];
\r
1642 serverStringToArray($str, $array, $frontParam);
\r
1643 sanitizeArray($array);
\r
1644 arrayToServerString($array, $frontParam, $str);
\r
1646 // QUERY_STRING of $_SERVER
\r
1647 $str =& $_SERVER["QUERY_STRING"];
\r
1648 serverStringToArray($str, $array, $frontParam);
\r
1649 sanitizeArray($array);
\r
1650 arrayToServerString($array, $frontParam, $str);
\r
1654 convArrayForSanitizing($_GET, $array);
\r
1655 sanitizeArray($array);
\r
1656 revertArrayForSanitizing($array, $_GET);
\r
1658 // $_REQUEST (only GET param)
\r
1659 convArrayForSanitizing($_REQUEST, $array);
\r
1660 sanitizeArray($array);
\r
1661 revertArrayForSanitizing($array, $_REQUEST);
\r
1665 * Check ticket when not checked in plugin's admin page
\r
1667 * Also avoid the access to plugin/index.php by guest user.
\r
1669 function ticketForPlugin(){
\r
1670 global $CONF,$DIR_PLUGINS,$member,$ticketforplugin;
\r
1673 $ticketforplugin=array();
\r
1674 $ticketforplugin['ticket']=false;
\r
1676 /* Check if using plugin's php file. */
\r
1677 if ($p_translated=serverVar('PATH_TRANSLATED')) {
\r
1678 if (!file_exists($p_translated)) $p_translated='';
\r
1680 if (!$p_translated) {
\r
1681 $p_translated=serverVar('SCRIPT_FILENAME');
\r
1682 if (!file_exists($p_translated)) {
\r
1683 header("HTTP/1.0 404 Not Found");
\r
1687 $p_translated=str_replace('\\','/',$p_translated);
\r
1688 $d_plugins=str_replace('\\','/',$DIR_PLUGINS);
\r
1689 if (strpos($p_translated,$d_plugins)!==0) return;// This isn't plugin php file.
\r
1691 /* Solve the plugin php file or admin directory */
\r
1692 $phppath=substr($p_translated,strlen($d_plugins));
\r
1693 $phppath=preg_replace('!^/!','',$phppath);// Remove the first "/" if exists.
\r
1694 $path=preg_replace('/^NP_(.*)\.php$/','$1',$phppath); // Remove the first "NP_" and the last ".php" if exists.
\r
1695 $path=preg_replace('!^([^/]*)/(.*)$!','$1',$path); // Remove the "/" and beyond.
\r
1697 /* Solve the plugin name. */
\r
1699 $query='SELECT pfile FROM '.sql_table('plugin');
\r
1700 $res=sql_query($query);
\r
1701 while($row=mysql_fetch_row($res)) {
\r
1702 $name=substr($row[0],3);
\r
1703 $plugins[strtolower($name)]=$name;
\r
1705 mysql_free_result($res);
\r
1706 if ($plugins[$path]) $plugin_name=$plugins[$path];
\r
1707 else if (in_array($path,$plugins)) $plugin_name=$path;
\r
1709 header("HTTP/1.0 404 Not Found");
\r
1713 /* Return if not index.php */
\r
1714 if ( $phppath!=strtolower($plugin_name).'/'
\r
1715 && $phppath!=strtolower($plugin_name).'/index.php' ) return;
\r
1717 /* Exit if not logged in. */
\r
1718 if ( !$member->isLoggedIn() ) exit("You aren't logged in.");
\r
1720 global $manager,$DIR_LIBS,$DIR_LANG,$HTTP_GET_VARS,$HTTP_POST_VARS;
\r
1722 /* Check if this feature is needed (ie, if "$manager->checkTicket()" is not included in the script). */
\r
1723 if (!($p_translated=serverVar('PATH_TRANSLATED'))) $p_translated=serverVar('SCRIPT_FILENAME');
\r
1724 if ($file=@file($p_translated)) {
\r
1726 foreach($file as $line) {
\r
1727 if (preg_match('/[\$]manager([\s]*)[\-]>([\s]*)checkTicket([\s]*)[\(]/i',$prevline.$line)) return;
\r
1732 /* Show a form if not valid ticket */
\r
1733 if ( ( strstr(serverVar('REQUEST_URI'),'?') || serverVar('QUERY_STRING')
\r
1734 || strtoupper(serverVar('REQUEST_METHOD'))=='POST' )
\r
1735 && (!$manager->checkTicket()) ){
\r
1737 if (!class_exists('PluginAdmin')) {
\r
1738 $language = getLanguageName();
\r
1739 include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');
\r
1740 include($DIR_LIBS . 'PLUGINADMIN.php');
\r
1742 if (!(function_exists('mb_strimwidth') || extension_loaded('mbstring'))) {
\r
1743 if (file_exists($DIR_LIBS.'mb_emulator/mb-emulator.php')) {
\r
1744 global $mbemu_internals;
\r
1745 include_once($DIR_LIBS.'mb_emulator/mb-emulator.php');
\r
1748 $oPluginAdmin = new PluginAdmin($plugin_name);
\r
1749 $oPluginAdmin->start();
\r
1750 echo '<p>' . _ERROR_BADTICKET . "</p>\n";
\r
1752 /* Show the form to confirm action */
\r
1753 // PHP 4.0.x support
\r
1754 $get= (isset($_GET)) ? $_GET : $HTTP_GET_VARS;
\r
1755 $post= (isset($_POST)) ? $_POST : $HTTP_POST_VARS;
\r
1756 // Resolve URI and QUERY_STRING
\r
1757 if ($uri=serverVar('REQUEST_URI')) {
\r
1758 list($uri,$qstring)=explode('?',$uri);
\r
1760 if ( !($uri=serverVar('PHP_SELF')) ) $uri=serverVar('SCRIPT_NAME');
\r
1761 $qstring=serverVar('QUERY_STRING');
\r
1763 if ($qstring) $qstring='?'.$qstring;
\r
1764 echo '<p>'._SETTINGS_UPDATE.' : '._QMENU_PLUGINS.' <span style="color:red;">'.
\r
1765 htmlspecialchars($plugin_name)."</span> ?</p>\n";
\r
1766 switch(strtoupper(serverVar('REQUEST_METHOD'))){
\r
1768 echo '<form method="POST" action="'.htmlspecialchars($uri.$qstring).'">';
\r
1769 $manager->addTicketHidden();
\r
1770 _addInputTags($post);
\r
1773 echo '<form method="GET" action="'.htmlspecialchars($uri).'">';
\r
1774 $manager->addTicketHidden();
\r
1775 _addInputTags($get);
\r
1779 echo '<input type="submit" value="'._YES.'" /> ';
\r
1780 echo '<input type="button" value="'._NO.'" onclick="history.back(); return false;" />';
\r
1783 $oPluginAdmin->end();
\r
1787 /* Create new ticket */
\r
1788 $ticket=$manager->addTicketToUrl('');
\r
1789 $ticketforplugin['ticket']=substr($ticket,strpos($ticket,'ticket=')+7);
\r
1791 function _addInputTags(&$keys,$prefix=''){
\r
1792 foreach($keys as $key=>$value){
\r
1793 if ($prefix) $key=$prefix.'['.$key.']';
\r
1794 if (is_array($value)) _addInputTags($value,$key);
\r
1796 if (get_magic_quotes_gpc()) $value=stripslashes($value);
\r
1797 if ($key=='ticket') continue;
\r
1798 echo '<input type="hidden" name="'.htmlspecialchars($key).
\r
1799 '" value="'.htmlspecialchars($value).'" />'."\n";
\r
1805 * Convert the server string such as $_SERVER['REQUEST_URI']
\r
1806 * to arry like arry['blogid']=1 and array['page']=2 etc.
\r
1808 function serverStringToArray($str, &$array, &$frontParam)
\r
1814 // split front param, e.g. /index.php, and others, e.g. blogid=1&page=2
\r
1815 if (strstr($str, "?")){
\r
1816 list($frontParam, $args) = preg_split("/\?/", $str, 2);
\r
1823 // If there is no args like blogid=1&page=2, return
\r
1824 if (!strstr($str, "=") && !strlen($frontParam)) {
\r
1825 $frontParam = $str;
\r
1829 $array = explode("&", $args);
\r
1833 * Convert array like array['blogid'] to server string
\r
1834 * such as $_SERVER['REQUEST_URI']
\r
1836 function arrayToServerString($array, $frontParam, &$str)
\r
1838 if (strstr($str, "?")) {
\r
1839 $str = $frontParam . "?";
\r
1841 $str = $frontParam;
\r
1843 if (count($array)) {
\r
1844 $str .= implode("&", $array);
\r
1849 * Sanitize array parameters.
\r
1850 * This function checks both key and value.
\r
1851 * - check key if it inclues " (double quote), remove from array
\r
1852 * - check value if it includes \ (escape sequece), remove remaining string
\r
1854 function sanitizeArray(&$array)
\r
1856 $excludeListForSanitization = array('query');
\r
1857 // $excludeListForSanitization = array();
\r
1859 foreach ($array as $k => $v) {
\r
1861 // split to key and value
\r
1862 list($key, $val) = preg_split("/=/", $v, 2);
\r
1863 if (!isset($val)) {
\r
1867 // when magic quotes is on, need to use stripslashes,
\r
1868 // and then addslashes
\r
1869 if (get_magic_quotes_gpc()) {
\r
1870 $val = stripslashes($val);
\r
1872 $val = addslashes($val);
\r
1874 // if $key is included in exclude list, skip this param
\r
1875 if (!in_array($key, $excludeListForSanitization)) {
\r
1878 @list($val, $tmp) = explode('\\', $val);
\r
1880 // remove control code etc.
\r
1881 $val = strtr($val, "\0\r\n<>'\"", " ");
\r
1884 if (preg_match('/\"/i', $key)) {
\r
1885 unset($array[$k]);
\r
1889 // set sanitized info
\r
1890 $array[$k] = sprintf("%s=%s", $key, $val);
\r
1896 * Convert array for sanitizeArray function
\r
1898 function convArrayForSanitizing($src, &$array)
\r
1901 foreach ($src as $key => $val) {
\r
1902 if (key_exists($key, $_GET)) {
\r
1903 array_push($array, sprintf("%s=%s", $key, $val));
\r
1909 * Revert array after sanitizeArray function
\r
1911 function revertArrayForSanitizing($array, &$dst)
\r
1913 foreach ($array as $v) {
\r
1914 list($key, $val) = preg_split("/=/", $v, 2);
\r
1915 $dst[$key] = $val;
\r
1920 * Stops processing the request and redirects to the given URL.
\r
1921 * - no actual contents should have been sent to the output yet
\r
1922 * - the URL will be stripped of illegal or dangerous characters
\r
1924 function redirect($url) {
\r
1925 $url = preg_replace('|[^a-z0-9-~+_.?#=&;,/:@%]|i', '', $url);
\r
1926 header('Location: ' . $url);
\r
1931 * Strip HTML tags from a string
\r
1932 * This function is a bit more intelligent than a regular call to strip_tags(),
\r
1933 * because it also deletes the contents of certain tags and cleans up any
\r
1934 * unneeded whitespace.
\r
1936 function stringStripTags ($string) {
\r
1937 $string = preg_replace("/<del[^>]*>.+<\/del[^>]*>/isU", '', $string);
\r
1938 $string = preg_replace("/<script[^>]*>.+<\/script[^>]*>/isU", '', $string);
\r
1939 $string = preg_replace("/<style[^>]*>.+<\/style[^>]*>/isU", '', $string);
\r
1940 $string = str_replace('>', '> ', $string);
\r
1941 $string = str_replace('<', ' <', $string);
\r
1942 $string = strip_tags($string);
\r
1943 $string = preg_replace("/\s+/", " ", $string);
\r
1944 $string = trim($string);
\r
1949 * Make a string containing HTML safe for use in a HTML attribute
\r
1950 * Tags are stripped and entities are normalized
\r
1952 function stringToAttribute ($string) {
\r
1953 $string = stringStripTags($string);
\r
1954 $string = entity::named_to_numeric($string);
\r
1955 $string = entity::normalize_numeric($string);
\r
1957 if (_CHARSET == 'UTF-8') {
\r
1958 $string = entity::numeric_to_utf8($string);
\r
1961 $string = entity::specialchars($string, 'html');
\r
1962 $string = entity::numeric_to_named($string);
\r
1967 * Make a string containing HTML safe for use in a XML document
\r
1968 * Tags are stripped, entities are normalized and named entities are
\r
1969 * converted to numeric entities.
\r
1971 function stringToXML ($string) {
\r
1972 $string = stringStripTags($string);
\r
1973 $string = entity::named_to_numeric($string);
\r
1974 $string = entity::normalize_numeric($string);
\r
1976 if (_CHARSET == 'UTF-8') {
\r
1977 $string = entity::numeric_to_utf8($string);
\r
1980 $string = entity::specialchars($string, 'xml');
\r
1984 // START: functions from the end of file BLOG.php
\r
1985 // used for mail notification (html -> text)
\r
1986 function toAscii($html) {
\r
1987 // strip off most tags
\r
1988 $html = strip_tags($html,'<a>');
\r
1989 $to_replace = "/<a[^>]*href=[\"\']([^\"^']*)[\"\'][^>]*>([^<]*)<\/a>/i";
\r
1991 $ascii = preg_replace_callback ($to_replace, '_links_add', $html);
\r
1992 $ascii .= "\n\n" . _links_list();
\r
1993 return strip_tags($ascii);
\r
1996 function _links_init() {
\r
1997 global $tmp_links;
\r
1998 $tmp_links = array();
\r
2001 function _links_add($match) {
\r
2002 global $tmp_links;
\r
2003 array_push($tmp_links, $match[1]);
\r
2004 return $match[2] . ' [' . sizeof($tmp_links) .']';
\r
2007 function _links_list() {
\r
2008 global $tmp_links;
\r
2011 foreach ($tmp_links as $current) {
\r
2012 $output .= "[$i] $current\n";
\r
2017 // END: functions from the end of file BLOG.php
\r
2019 // START: functions from the end of file ADMIN.php
\r
2021 * @todo document this
\r
2023 function encode_desc(&$data)
\r
2024 { //_$to_entities = get_html_translation_table(HTML_ENTITIES);
\r
2025 $to_entities = get_html_translation_table(HTML_SPECIALCHARS);
\r
2026 $from_entities = array_flip($to_entities);
\r
2027 $data = str_replace('<br />','\n',$data); //hack
\r
2028 $data = strtr($data,$from_entities);
\r
2029 $data = strtr($data,$to_entities);
\r
2030 $data = str_replace('\n','<br />',$data); //hack
\r
2035 * Returns the Javascript code for a bookmarklet that works on most modern browsers
\r
2039 function getBookmarklet($blogid) {
\r
2043 $document = 'document';
\r
2044 $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
2045 $bookmarkletline .= $CONF['AdminURL'] . "bookmarklet.php?blogid=$blogid";
\r
2046 $bookmarkletline .="&logtext='+escape(Q)+'&loglink='+escape(x.location.href)+'&loglinktitle='+escape(x.title),'nucleusbm','scrollbars=yes,width=600,height=550,left=10,top=10,status=yes,resizable=yes');wingm.focus();";
\r
2048 return $bookmarkletline;
\r
2050 // END: functions from the end of file ADMIN.php
\r
2053 * Returns a variable or null if not set
\r
2055 * @param mixed Variable
\r
2056 * @return mixed Variable
\r
2058 function ifset(&$var) {
\r
2059 if (isset($var)) {
\r
2067 * Returns number of subscriber to an event
\r
2070 * @return number of subscriber(s)
\r
2072 function numberOfEventSubscriber($event) {
\r
2073 $query = 'SELECT COUNT(*) as count FROM ' . sql_table('plugin_event') . ' WHERE event=\'' . $event . '\'';
\r
2074 $res = sql_query($query);
\r
2075 $obj = mysql_fetch_object($res);
\r
2076 return $obj->count;
\r