OSDN Git Service

1f0e89f6ab05a98350eb90284880e0b84ab33b66
[nucleus-jp/nucleus-jp-ancient.git] / nucleus / libs / globalfunctions.php
1 <?php
2
3 /*
4  * Nucleus: PHP/MySQL Weblog CMS (http://nucleuscms.org/)
5  * Copyright (C) 2002-2007 The Nucleus Group
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  * (see nucleus/documentation/index.html#license for more info)
12  */
13 /**
14  * @license http://nucleuscms.org/license.txt GNU General Public License
15  * @copyright Copyright (C) 2002-2007 The Nucleus Group
16  * @version $Id: globalfunctions.php,v 1.24 2008-02-08 09:31:22 kimitake Exp $
17  * $NucleusJP: globalfunctions.php,v 1.23.2.7 2008/02/05 08:30:08 kimitake Exp $
18  */
19
20 // needed if we include globalfunctions from install.php
21 global $nucleus, $CONF, $DIR_LIBS, $DIR_LANG, $manager, $member;
22
23 $nucleus['version'] = 'v3.4';
24 $nucleus['codename'] = '';
25
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'));
27
28 $CONF['debug'] = 0;
29 if ($CONF['debug']) {
30         error_reporting(E_ALL); // report all errors!
31 } else {
32         error_reporting(E_ERROR | E_WARNING | E_PARSE);
33 }
34
35 // Avoid notices
36 if (!isset($CONF['Self'])) {
37         $CONF['Self'] = htmlspecialchars($_SERVER['PHP_SELF'],ENT_QUOTES);
38 }
39
40 /*
41         Indicates when Nucleus should display startup errors. Set to 1 if you want
42         the error enabled (default), false otherwise
43
44         alertOnHeadersSent
45                 Displays an error when visiting a public Nucleus page and headers have
46                 been sent out to early. This usually indicates an error in either a
47                 configuration file or a language file, and could cause Nucleus to
48                 malfunction
49         alertOnSecurityRisk
50                 Displays an error only when visiting the admin area, and when one or
51                 more of the installation files (install.php, install.sql, upgrades/
52                 directory) are still on the server.
53 */
54 $CONF['alertOnHeadersSent'] = 1;
55 $CONF['alertOnSecurityRisk'] = 1;
56 $CONF['ItemURL'] = $CONF['Self'];
57 $CONF['ArchiveURL'] = $CONF['Self'];
58 $CONF['ArchiveListURL'] = $CONF['Self'];
59 $CONF['MemberURL'] = $CONF['Self'];
60 $CONF['SearchURL'] = $CONF['Self'];
61 $CONF['BlogURL'] = $CONF['Self'];
62 $CONF['CategoryURL'] = $CONF['Self'];
63
64 // switch URLMode back to normal when $CONF['Self'] ends in .php
65 // this avoids urls like index.php/item/13/index.php/item/15
66 if (!isset($CONF['URLMode']) || (($CONF['URLMode'] == 'pathinfo') && (substr($CONF['Self'], strlen($CONF['Self']) - 4) == '.php'))) {
67         $CONF['URLMode'] = 'normal';
68 }
69
70 if (getNucleusPatchLevel() > 0) {
71         $nucleus['version'] .= '/' . getNucleusPatchLevel();
72 }
73
74 // Avoid notices
75 if (!isset($CONF['installscript'])) {
76         $CONF['installscript'] = 0;
77 }
78
79 // we will use postVar, getVar, ... methods instead of HTTP_GET_VARS or _GET
80 if ($CONF['installscript'] != 1) { // vars were already included in install.php
81         if (phpversion() >= '4.1.0') {
82                 include_once($DIR_LIBS . 'vars4.1.0.php');
83         } else {
84                 include_once($DIR_LIBS . 'vars4.0.6.php');
85         }
86 }
87
88 // sanitize option
89 $bLoggingSanitizedResult=0;
90 $bSanitizeAndContinue=0;
91
92 $orgRequestURI = serverVar('REQUEST_URI');
93 sanitizeParams();
94
95 // get all variables that can come from the request and put them in the global scope
96 $blogid = requestVar('blogid');
97 $itemid = intRequestVar('itemid');
98 $catid = intRequestVar('catid');
99 $skinid = requestVar('skinid');
100 $memberid = requestVar('memberid');
101 $archivelist = requestVar('archivelist');
102 $imagepopup = requestVar('imagepopup');
103 $archive = requestVar('archive');
104 $query = requestVar('query');
105 $highlight = requestVar('highlight');
106 $amount = requestVar('amount');
107 $action = requestVar('action');
108 $nextaction = requestVar('nextaction');
109 $maxresults = requestVar('maxresults');
110 $startpos = intRequestVar('startpos');
111 $errormessage = '';
112 $error = '';
113 $virtualpath = ((getVar('virtualpath') != null) ? getVar('virtualpath') : serverVar('PATH_INFO'));
114
115 if (!headers_sent() ) {
116         header('Generator: Nucleus CMS ' . $nucleus['version']);
117 }
118
119 // include core classes that are needed for login & plugin handling
120 include($DIR_LIBS . 'mysql.php');
121 include($DIR_LIBS . 'MEMBER.php');
122 include($DIR_LIBS . 'ACTIONLOG.php');
123 include($DIR_LIBS . 'MANAGER.php');
124 include($DIR_LIBS . 'PLUGIN.php');
125
126 $manager =& MANAGER::instance();
127
128 // make sure there's no unnecessary escaping:
129 set_magic_quotes_runtime(0);
130
131 // Avoid notices
132 if (!isset($CONF['UsingAdminArea'])) {
133         $CONF['UsingAdminArea'] = 0;
134 }
135
136 // only needed when updating logs
137 if ($CONF['UsingAdminArea']) {
138         include($DIR_LIBS . 'xmlrpc.inc.php');  // XML-RPC client classes
139         include_once($DIR_LIBS . 'ADMIN.php');
140 }
141
142 // connect to database
143 sql_connect();
144 $SQLCount = 0;
145
146 // logs sanitized result if need
147 if ($orgRequestURI!==serverVar('REQUEST_URI')) {
148         $msg = "Sanitized [" . serverVar('REMOTE_ADDR') . "] ";
149         $msg .= $orgRequestURI . " -> " . serverVar('REQUEST_URI');
150     if ($bLoggingSanitizedResult) {
151         addToLog(WARNING, $msg);
152     }
153     if (!$bSanitizeAndContinue) {
154         die("");
155     }
156 }
157
158 // makes sure database connection gets closed on script termination
159 register_shutdown_function('sql_disconnect');
160
161 // read config
162 getConfig();
163
164 // automatically use simpler toolbar for mozilla
165 if (($CONF['DisableJsTools'] == 0) && strstr(serverVar('HTTP_USER_AGENT'), 'Mozilla/5.0') && strstr(serverVar('HTTP_USER_AGENT'), 'Gecko') ) {
166         $CONF['DisableJsTools'] = 2;
167 }
168
169 // login if cookies set
170 $member = new MEMBER();
171
172 // secure cookie key settings (either 'none', 0, 8, 16, 24, or 32)
173 if (!isset($CONF['secureCookieKey'])) $CONF['secureCookieKey']=24;
174 switch($CONF['secureCookieKey']){
175 case 8:
176         $CONF['secureCookieKeyIP']=preg_replace('/\.[0-9]+\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
177         break;
178 case 16:
179         $CONF['secureCookieKeyIP']=preg_replace('/\.[0-9]+\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
180         break;
181 case 24:
182         $CONF['secureCookieKeyIP']=preg_replace('/\.[0-9]+$/','',serverVar('REMOTE_ADDR'));
183         break;
184 case 32:
185         $CONF['secureCookieKeyIP']=serverVar('REMOTE_ADDR');
186         break;
187 default:
188         $CONF['secureCookieKeyIP']='';
189 }
190
191 // login/logout when required or renew cookies
192 if ($action == 'login') {
193         // Form Authentication
194         $login = postVar('login');
195         $pw = postVar('password');
196         $shared = intPostVar('shared'); // shared computer or not
197
198         $pw=substr($pw,0,40); // avoid md5 collision by using a long key
199
200         if ($member->login($login, $pw) ) {
201
202                 $member->newCookieKey();
203                 $member->setCookies($shared);
204
205                 if ($CONF['secureCookieKey']!=='none') {
206                         // secure cookie key
207                         $member->setCookieKey(md5($member->getCookieKey().$CONF['secureCookieKeyIP']));
208                         $member->write();
209                 }
210
211                 // allows direct access to parts of the admin area after logging in
212                 if ($nextaction) {
213                         $action = $nextaction;
214                 }
215
216                 $manager->notify('LoginSuccess', array('member' => &$member) );
217                 $errormessage = '';
218                 ACTIONLOG::add(INFO, "Login successful for $login (sharedpc=$shared)");
219         } else {
220                 // errormessage for [%errordiv%]
221                 $errormessage = 'Login failed for ' . $login;
222
223                 $manager->notify('LoginFailed', array('username' => $login) );
224                 ACTIONLOG::add(INFO, $errormessage);
225         }
226 /*
227
228 Backed out for now: See http://forum.nucleuscms.org/viewtopic.php?t=3684 for details
229
230 } elseif (serverVar('PHP_AUTH_USER') && serverVar('PHP_AUTH_PW')) {
231         // HTTP Authentication
232         $login  = serverVar('PHP_AUTH_USER');
233         $pw     = serverVar('PHP_AUTH_PW');
234
235         if ($member->login($login, $pw) ) {
236                 $manager->notify('LoginSuccess',array('member' => &$member));
237                 ACTIONLOG::add(INFO, "HTTP authentication successful for $login");
238         } else {
239                 $manager->notify('LoginFailed',array('username' => $login));
240                 ACTIONLOG::add(INFO, 'HTTP authentication failed for ' . $login);
241
242                 //Since bad credentials, generate an apropriate error page
243                 header("WWW-Authenticate: Basic realm=\"Nucleus CMS {$nucleus['version']}\"");
244                 header('HTTP/1.0 401 Unauthorized');
245                 echo 'Invalid username or password';
246                 exit;
247         }
248 */
249
250 } elseif (($action == 'logout') && (!headers_sent() ) && cookieVar($CONF['CookiePrefix'] . 'user') ) {
251         // remove cookies on logout
252         setcookie($CONF['CookiePrefix'] . 'user', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
253         setcookie($CONF['CookiePrefix'] . 'loginkey', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
254         $manager->notify('Logout', array('username' => cookieVar($CONF['CookiePrefix'] . 'user') ) );
255 } elseif (cookieVar($CONF['CookiePrefix'] . 'user') ) {
256         // Cookie Authentication
257         $ck=cookieVar($CONF['CookiePrefix'] . 'loginkey');
258         // secure cookie key
259         $ck=substr($ck,0,32); // avoid md5 collision by using a long key
260         if ($CONF['secureCookieKey']!=='none') $ck=md5($ck.$CONF['secureCookieKeyIP']);
261         $res = $member->cookielogin(cookieVar($CONF['CookiePrefix'] . 'user'), $ck );
262         unset($ck);
263
264         // renew cookies when not on a shared computer
265         if ($res && (cookieVar($CONF['CookiePrefix'] . 'sharedpc') != 1) && (!headers_sent() ) ) {
266                 $member->setCookieKey(cookieVar($CONF['CookiePrefix'] . 'loginkey'));
267                 $member->setCookies();
268         }
269 }
270
271 // login completed
272 $manager->notify('PostAuthentication', array('loggedIn' => $member->isLoggedIn() ) );
273 ticketForPlugin();
274
275 // first, let's see if the site is disabled or not. always allow admin area access.
276 if ($CONF['DisableSite'] && !$member->isAdmin() && !$CONF['UsingAdminArea']) {
277         redirect($CONF['DisableSiteURL']);
278         exit;
279 }
280
281 // load other classes
282 include($DIR_LIBS . 'PARSER.php');
283 include($DIR_LIBS . 'SKIN.php');
284 include($DIR_LIBS . 'TEMPLATE.php');
285 include($DIR_LIBS . 'BLOG.php');
286 include($DIR_LIBS . 'BODYACTIONS.php');
287 include($DIR_LIBS . 'COMMENTS.php');
288 include($DIR_LIBS . 'COMMENT.php');
289 //include($DIR_LIBS . 'ITEM.php');
290 include($DIR_LIBS . 'NOTIFICATION.php');
291 include($DIR_LIBS . 'BAN.php');
292 include($DIR_LIBS . 'PAGEFACTORY.php');
293 include($DIR_LIBS . 'SEARCH.php');
294 include($DIR_LIBS . 'entity.php');
295
296
297 // set lastVisit cookie (if allowed)
298 if (!headers_sent() ) {
299         if ($CONF['LastVisit']) {
300                 setcookie($CONF['CookiePrefix'] . 'lastVisit', time(), time() + 2592000, $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
301         } else {
302                 setcookie($CONF['CookiePrefix'] . 'lastVisit', '', (time() - 2592000), $CONF['CookiePath'], $CONF['CookieDomain'], $CONF['CookieSecure']);
303         }
304 }
305
306 // read language file, only after user has been initialized
307 $language = getLanguageName();
308 include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');
309
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
314         }\r
315 }\r
316 \r
317 /*
318         Backed out for now: See http://forum.nucleuscms.org/viewtopic.php?t=3684 for details
319
320 // To remove after v2.5 is released and language files have been updated.
321 // Including this makes sure that language files for v2.5beta can still be used for v2.5final
322 // without having weird _SETTINGS_EXTAUTH string showing up in the admin area.
323 if (!defined('_MEMBERS_BYPASS'))
324 {
325         define('_SETTINGS_EXTAUTH',                     'Enable External Authentication');
326         define('_WARNING_EXTAUTH',                      'Warning: Enable only if needed.');
327         define('_MEMBERS_BYPASS',                       'Use External Authentication');
328 }
329
330 */
331
332 // make sure the archivetype skinvar keeps working when _ARCHIVETYPE_XXX not defined
333 if (!defined('_ARCHIVETYPE_MONTH') ) {
334         define('_ARCHIVETYPE_DAY', 'day');
335         define('_ARCHIVETYPE_MONTH', 'month');
336 }
337
338 // decode path_info
339 if ($CONF['URLMode'] == 'pathinfo') {
340         // initialize keywords if this hasn't been done before
341         if ($CONF['ItemKey'] == '') {
342                 $CONF['ItemKey'] = 'item';
343         }
344
345         if ($CONF['ArchiveKey'] == '') {
346                 $CONF['ArchiveKey'] = 'archive';
347         }
348
349         if ($CONF['ArchivesKey'] == '') {
350                 $CONF['ArchivesKey'] = 'archives';
351         }
352
353         if ($CONF['MemberKey'] == '') {
354                 $CONF['MemberKey'] = 'member';
355         }
356
357         if ($CONF['BlogKey'] == '') {
358                 $CONF['BlogKey'] = 'blog';
359         }
360
361         if ($CONF['CategoryKey'] == '') {
362                 $CONF['CategoryKey'] = 'category';
363         }
364
365         if ($CONF['SpecialskinKey'] == '') {
366                 $CONF['SpecialskinKey'] = 'special';
367         }
368
369         $parsed = false;
370         $manager->notify(
371                 'ParseURL',
372                 array(
373                         'type' => basename(serverVar('SCRIPT_NAME') ), // e.g. item, blog, ...
374                         'info' => $virtualpath,
375                         'complete' => &$parsed
376                 )
377         );
378
379         if (!$parsed) {
380                 // default implementation
381                 $data = explode("/", $virtualpath );
382                 for ($i = 0; $i < sizeof($data); $i++) {
383                         switch ($data[$i]) {
384                                 case $CONF['ItemKey']: // item/1 (blogid)
385                                         $i++;
386
387                                         if ($i < sizeof($data) ) {
388                                                 $itemid = intval($data[$i]);
389                                         }
390                                         break;
391
392                                 case $CONF['ArchivesKey']: // archives/1 (blogid)
393                                         $i++;
394
395                                         if ($i < sizeof($data) ) {
396                                                 $archivelist = intval($data[$i]);
397                                         }
398                                         break;
399
400                                 case $CONF['ArchiveKey']: // two possibilities: archive/yyyy-mm or archive/1/yyyy-mm (with blogid)
401                                         if ((($i + 1) < sizeof($data) ) && (!strstr($data[$i + 1], '-') ) ) {
402                                                 $blogid = intval($data[++$i]);
403                                         }
404
405                                         $i++;
406
407                                         if ($i < sizeof($data) ) {
408                                                 $archive = $data[$i];
409                                         }
410                                         break;
411
412                                 case 'blogid': // blogid/1
413                                 case $CONF['BlogKey']: // blog/1
414                                         $i++;
415
416                                         if ($i < sizeof($data) ) {
417                                                 $blogid = intval($data[$i]);
418                                         }
419                                         break;
420
421                                 case $CONF['CategoryKey']: // category/1 (catid)
422                                 case 'catid':
423                                         $i++;
424
425                                         if ($i < sizeof($data) ) {
426                                                 $catid = intval($data[$i]);
427                                         }
428                                         break;
429
430                                 case $CONF['MemberKey']:
431                                         $i++;
432
433                                         if ($i < sizeof($data) ) {
434                                                 $memberid = intval($data[$i]);
435                                         }
436                                         break;
437
438                 case $CONF['SpecialskinKey']:
439                     $i++;
440
441                                         if ($i < sizeof($data) ) {
442                         $_REQUEST['special'] = $data[$i];
443                     }
444                     break;
445
446                                 default:
447                                         // skip...
448                         }
449                 }
450         }
451 }
452
453 function intPostVar($name) {
454         return intval(postVar($name) );
455 }
456
457 function intGetVar($name) {
458         return intval(getVar($name) );
459 }
460
461 function intRequestVar($name) {
462         return intval(requestVar($name) );
463 }
464
465 function intCookieVar($name) {
466         return intval(cookieVar($name) );
467 }
468
469 /**
470   * returns the currently used version (100 = 1.00, 101 = 1.01, etc...)
471   */
472 function getNucleusVersion() {
473         return 340;
474 }
475
476 /**
477  * power users can install patches in between nucleus releases. These patches
478  * usually add new functionality in the plugin API and allow those to
479  * be tested without having to install CVS.
480  */
481 function getNucleusPatchLevel() {
482         return 0;
483 }
484
485 /**
486   * Connects to mysql server
487   */
488 function sql_connect() {
489         global $MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWORD, $MYSQL_DATABASE, $MYSQL_CONN;
490
491         $MYSQL_CONN = @mysql_connect($MYSQL_HOST, $MYSQL_USER, $MYSQL_PASSWORD) or startUpError('<p>Could not connect to MySQL database.</p>', 'Connect Error');
492         mysql_select_db($MYSQL_DATABASE) or startUpError('<p>Could not select database: ' . mysql_error() . '</p>', 'Connect Error');
493
494         return $MYSQL_CONN;
495 }
496
497 /**
498  * returns a prefixed nucleus table name
499  */
500 function sql_table($name) {
501         global $MYSQL_PREFIX;
502
503         if ($MYSQL_PREFIX) {
504                 return $MYSQL_PREFIX . 'nucleus_' . $name;
505         } else {
506                 return 'nucleus_' . $name;
507         }
508 }
509
510 function sendContentType($contenttype, $pagetype = '', $charset = _CHARSET) {
511         global $manager, $CONF;
512
513         if (!headers_sent() ) {
514                 // if content type is application/xhtml+xml, only send it to browsers
515                 // that can handle it (IE6 cannot). Otherwise, send text/html
516
517                 // v2.5: For admin area pages, keep sending text/html (unless it's a debug version)
518                 //       application/xhtml+xml still causes too much problems with the javascript implementations
519
520                 // v3.3: ($CONF['UsingAdminArea'] && !$CONF['debug']) gets removed,
521                 //       application/xhtml+xml seems to be working, so we're going to use it if we can.
522                 //
523                 // Note: reverted the following function in JP version
524                 //
525         /*
526                 // v3.3 code
527                 if (
528                                 ($contenttype == 'application/xhtml+xml')
529                         &&      (!stristr(serverVar('HTTP_ACCEPT'), 'application/xhtml+xml') )
530                         ) {
531                         $contenttype = 'text/html';
532                 }
533         */
534                 // v3.2x code
535                 if (
536                                 ($contenttype == 'application/xhtml+xml')
537                         &&      (($CONF['UsingAdminArea'] && !$CONF['debug']) || !stristr(serverVar('HTTP_ACCEPT'),'application/xhtml+xml'))
538                         )
539                 {
540                         $contenttype = 'text/html';
541                 }
542
543                 $manager->notify(
544                         'PreSendContentType',
545                         array(
546                                 'contentType' => &$contenttype,
547                                 'charset' => &$charset,
548                                 'pageType' => $pagetype
549                         )
550                 );
551
552                 // strip strange characters
553                 $contenttype = preg_replace('|[^a-z0-9-+./]|i', '', $contenttype);
554                 $charset = preg_replace('|[^a-z0-9-_]|i', '', $charset);
555
556                 if ($charset != '') {
557                         header('Content-Type: ' . $contenttype . '; charset=' . $charset);
558                 } else {
559                         header('Content-Type: ' . $contenttype);
560                 }
561 \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
566                         }\r
567                 }\r
568         }
569 }
570
571 /**
572  * Errors before the database connection has been made
573  */
574 function startUpError($msg, $title) {
575         if (!defined('_CHARSET')) define('_CHARSET','iso-8859-1');\r
576         header('Content-Type: text/html; charset=' . _CHARSET);\r
577         ?>
578         <html xmlns="http://www.w3.org/1999/xhtml">
579                 <head><meta http-equiv="Content-Type" content="text/html; charset=<?php echo _CHARSET?>" />\r
580                 <title><?php echo htmlspecialchars($title)?></title></head>
581                 <body>
582                         <h1><?php echo htmlspecialchars($title)?></h1>
583                         <?php echo $msg?>
584                 </body>
585         </html>
586         <?php   exit;
587 }
588
589 /**
590   * disconnects from SQL server
591   */
592 function sql_disconnect() {
593         @mysql_close();
594 }
595
596 /**
597   * executes an SQL query
598   */
599 function sql_query($query) {
600         global $SQLCount;
601         $SQLCount++;
602         $res = mysql_query($query) or print("mySQL error with query $query: " . mysql_error() . '<p />');
603         return $res;
604 }
605
606
607 /**
608  * Highlights a specific query in a given HTML text (not within HTML tags) and returns it
609  *
610  * @param $text
611  *              text to be highlighted
612  * @param $expression
613  *              regular expression to be matched (can be an array of expressions as well)
614  * @param $highlight
615  *              highlight to be used (use \\0 to indicate the matched expression)
616  *
617  */
618 function highlight($text, $expression, $highlight) {
619         if (!$highlight || !$expression) {
620                 return $text;
621         }
622
623         if (is_array($expression) && (count($expression) == 0) ) {
624                 return $text;
625         }
626
627         // add a tag in front (is needed for preg_match_all to work correct)
628         $text = '<!--h-->' . $text;
629
630         // split the HTML up so we have HTML tags
631         // $matches[0][i] = HTML + text
632         // $matches[1][i] = HTML
633         // $matches[2][i] = text
634         preg_match_all('/(<[^>]+>)([^<>]*)/', $text, $matches);
635
636         // throw it all together again while applying the highlight to the text pieces
637         $result = '';
638         for ($i = 0; $i < sizeof($matches[2]); $i++) {
639                 if ($i != 0) {
640                         $result .= $matches[1][$i];
641                 }
642
643                 if (is_array($expression) ) {
644                         foreach ($expression as $regex) {
645                                 if ($regex) {
646                                         $matches[2][$i] = @eregi_replace($regex, $highlight, $matches[2][$i]);
647                                 }
648                         }
649
650                         $result .= $matches[2][$i];
651                 } else {
652                         $result .= @eregi_replace($expression, $highlight, $matches[2][$i]);
653                 }
654         }
655
656         return $result;
657 }
658
659 /**
660  * Parses a query into an array of expressions that can be passed on to the highlight method
661  */
662 function parseHighlight($query) {
663         // TODO: add more intelligent splitting logic
664
665         // get rid of quotes
666         $query = preg_replace('/\'|"/', '', $query);
667
668         if (!query) {
669                 return array();
670         }
671
672         $aHighlight = explode(' ', $query);
673
674         for ($i = 0; $i < count($aHighlight); $i++) {
675                 $aHighlight[$i] = trim($aHighlight[$i]);
676
677                 if (strlen($aHighlight[$i]) < 3) {
678                         unset($aHighlight[$i]);
679                 }
680         }
681
682         if (count($aHighlight) == 1) {
683                 return $aHighlight[0];
684         } else {
685                 return $aHighlight;
686         }
687 }
688
689 /**
690   * Checks if email address is valid
691   */
692 function isValidMailAddress($address) {
693         if (preg_match('/^[a-zA-Z+0-9\._-]+@[a-zA-Z0-9\._-]+\.[A-Za-z]{2,5}$/', $address)) {
694                 return 1;
695         } else {
696                 return 0;
697         }
698 }
699
700
701 // some helper functions
702 function getBlogIDFromName($name) {
703         return quickQuery('SELECT bnumber as result FROM ' . sql_table('blog') . ' WHERE bshortname="' . addslashes($name) . '"');
704 }
705
706 function getBlogNameFromID($id) {
707         return quickQuery('SELECT bname as result FROM ' . sql_table('blog') . ' WHERE bnumber=' . intval($id) );
708 }
709
710 function getBlogIDFromItemID($itemid) {
711         return quickQuery('SELECT iblog as result FROM ' . sql_table('item') . ' WHERE inumber=' . intval($itemid) );
712 }
713
714 function getBlogIDFromCommentID($commentid) {
715         return quickQuery('SELECT cblog as result FROM ' . sql_table('comment') . ' WHERE cnumber=' . intval($commentid) );
716 }
717
718 function getBlogIDFromCatID($catid) {
719         return quickQuery('SELECT cblog as result FROM ' . sql_table('category') . ' WHERE catid=' . intval($catid) );
720 }
721
722 function getCatIDFromName($name) {
723         return quickQuery('SELECT catid as result FROM ' . sql_table('category') . ' WHERE cname="' . addslashes($name) . '"');
724 }
725
726 function quickQuery($q) {
727         $res = sql_query($q);
728         $obj = mysql_fetch_object($res);
729         return $obj->result;
730 }
731
732 function getPluginNameFromPid($pid) {
733         $res = sql_query('SELECT pfile FROM ' . sql_table('plugin') . ' WHERE pid=' . intval($pid) );
734         $obj = mysql_fetch_object($res);
735         return $obj->pfile;
736 }
737
738 function selector() {
739         global $itemid, $blogid, $memberid, $query, $amount, $archivelist, $maxresults;
740         global $archive, $skinid, $blog, $memberinfo, $CONF, $member;
741         global $imagepopup, $catid;
742         global $manager;
743
744         $actionNames = array('addcomment', 'sendmessage', 'createaccount', 'forgotpassword', 'votepositive', 'votenegative', 'plugin');
745         $action = requestVar('action');
746
747         if (in_array($action, $actionNames) ) {
748                 global $DIR_LIBS, $errormessage;
749                 include_once($DIR_LIBS . 'ACTION.php');
750                 $a = new ACTION();
751                 $errorInfo = $a->doAction($action);
752
753                 if ($errorInfo) {
754                         $errormessage = $errorInfo['message'];
755                 }
756         }
757
758         // show error when headers already sent out
759         if (headers_sent() && $CONF['alertOnHeadersSent']) {
760
761                 // try to get line number/filename (extra headers_sent params only exists in PHP 4.3+)
762                 if (function_exists('version_compare') && version_compare('4.3.0', phpversion(), '<=') ) {
763                         headers_sent($hsFile, $hsLine);
764                         $extraInfo = ' in <code>' . $hsFile . '</code> line <code>' . $hsLine . '</code>';
765                 } else {
766                         $extraInfo = '';
767                 }
768
769                 startUpError(
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>',
771                         'Page headers already sent'
772                 );
773                 exit;
774         }
775
776         // make is so ?archivelist without blogname or blogid shows the archivelist
777         // for the default weblog
778         if (serverVar('QUERY_STRING') == 'archivelist') {
779                 $archivelist = $CONF['DefaultBlog'];
780         }
781
782         // now decide which type of skin we need
783         if ($itemid) {
784                 // itemid given -> only show that item
785                 $type = 'item';
786
787                 if (!$manager->existsItem($itemid,0,0) ) {
788                         doError(_ERROR_NOSUCHITEM);
789                 }
790
791                 global $itemidprev, $itemidnext, $catid, $itemtitlenext, $itemtitleprev;
792
793                 // 1. get timestamp, blogid and catid for item
794                 $query = 'SELECT itime, iblog, icat FROM ' . sql_table('item') . ' WHERE inumber=' . intval($itemid);
795                 $res = sql_query($query);
796                 $obj = mysql_fetch_object($res);
797
798                 // if a different blog id has been set through the request or selectBlog(),
799                 // deny access
800 //              if ($blogid && (intval($blogid) != $obj->iblog) ) {
801 //                      doError(_ERROR_NOSUCHITEM);
802 //              }
803                 if ($blogid && (intval($blogid) != $obj->iblog) ) {
804                         if (!headers_sent()) {
805                                 $b =& $manager->getBlog($obj->iblog);
806                                 $CONF['ItemURL'] = $b->getURL();
807                                 if ($CONF['URLMode'] == 'pathinfo' and substr($CONF['ItemURL'],-1) == '/')
808                                         $CONF['ItemURL'] = substr($CONF['ItemURL'], 0, -1);
809                                 $correctURL = createItemLink($itemid, '');
810                                 redirect($correctURL);
811                                 exit;
812                         } else {
813                                 doError(_ERROR_NOSUCHITEM);
814                         }
815                 }
816
817                 // if a category has been selected which doesn't match the item, ignore the
818                 // category. #85
819                 if (($catid != 0) && ($catid != $obj->icat) ) {
820                         $catid = 0;
821                 }
822
823                 $blogid = $obj->iblog;
824                 $timestamp = strtotime($obj->itime);
825
826                 $b =& $manager->getBlog($blogid);
827
828                 if ($b->isValidCategory($catid) ) {
829                         $catextra = ' and icat=' . $catid;
830                 }
831
832                 // get previous itemid and title
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';
834                 $res = sql_query($query);
835
836                 $obj = mysql_fetch_object($res);
837
838                 if ($obj) {
839                         $itemidprev = $obj->inumber;
840                         $itemtitleprev = $obj->ititle;
841                 }
842
843                 // get next itemid and title
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';
845                 $res = sql_query($query);
846
847                 $obj = mysql_fetch_object($res);
848
849                 if ($obj) {
850                         $itemidnext = $obj->inumber;
851                         $itemtitlenext = $obj->ititle;
852                 }
853
854         } elseif ($archive) {
855                 // show archive
856                 $type = 'archive';
857
858                 // get next and prev month links ...
859                 global $archivenext, $archiveprev, $archivetype, $archivenextexists, $archiveprevexists;
860                 
861                 // sql queries for the timestamp of the first and the last published item
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";
863                 $first_timestamp=quickQuery ($query);
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";
865                 $last_timestamp=quickQuery ($query);
866
867                 sscanf($archive, '%d-%d-%d', $y, $m, $d);
868
869                 if ($d != 0) {
870                         $archivetype = _ARCHIVETYPE_DAY;
871                         $t = mktime(0, 0, 0, $m, $d, $y);
872                         // one day has 24 * 60 * 60 = 86400 seconds                     
873                         $archiveprev = strftime('%Y-%m-%d', $t - 86400 );
874                         // check for published items                    
875                         if ($t > $first_timestamp) {
876                                 $archiveprevexists = true;
877                         }
878                         else {
879                                 $archiveprevexists = false;
880                         }
881                         
882                         // one day later
883                         $t += 86400; 
884                         $archivenext = strftime('%Y-%m-%d', $t);
885                         if ($t < $last_timestamp) {
886                                 $archivenextexists = true;
887                         }
888                         else {
889                                 $archivenextexists = false;
890                         }
891                         
892                 } else {
893                         $archivetype = _ARCHIVETYPE_MONTH;
894                         $t = mktime(0, 0, 0, $m, 1, $y);
895                         // one day before is in the previous month
896                         $archiveprev = strftime('%Y-%m', $t - 86400);
897                         if ($t > $first_timestamp) {
898                                 $archiveprevexists = true;
899                         }
900                         else {
901                                 $archiveprevexists = false;
902                         }
903                         
904                         // timestamp for the next month                 
905                         $t = mktime(0, 0, 0, $m+1, 1, $y);
906                         $archivenext = strftime('%Y-%m', $t);
907                         if ($t < $last_timestamp) {
908                                 $archivenextexists = true;
909                         }
910                         else {
911                                 $archivenextexists = false;
912                         }
913                 }
914
915         } elseif ($archivelist) {
916                 $type = 'archivelist';
917
918                 if (is_numeric($archivelist)) {
919                         $blogid = intVal($archivelist);
920                 } else {
921                         $blogid = getBlogIDFromName($archivelist);
922                 }
923
924                 if (!$blogid) {
925                         doError(_ERROR_NOSUCHBLOG);
926                 }
927
928         } elseif ($query) {
929                 global $startpos;
930                 $type = 'search';
931                 $query = stripslashes($query);
932                 if(preg_match("/^(\xA1{2}|\xe3\x80{2}|\x20)+$/",$query)){
933                                         $type = 'index';
934                 }
935                 $order = (_CHARSET == 'EUC-JP') ? 'EUC-JP, UTF-8,' : 'UTF-8, EUC-JP,';
936                 $query = mb_convert_encoding($query, _CHARSET, $order.' JIS, SJIS, ASCII');
937                 if (is_numeric($blogid)) {
938                         $blogid = intVal($blogid);
939                 } else {
940                         $blogid = getBlogIDFromName($blogid);
941                 }
942
943                 if (!$blogid) {
944                         doError(_ERROR_NOSUCHBLOG);
945                 }
946
947         } elseif ($memberid) {
948                 $type = 'member';
949
950                 if (!MEMBER::existsID($memberid) ) {
951                         doError(_ERROR_NOSUCHMEMBER);
952                 }
953
954                 $memberinfo = $manager->getMember($memberid);
955
956         } elseif ($imagepopup) {
957                 // media object (images etc.)
958                 $type = 'imagepopup';
959
960                 // TODO: check if media-object exists
961                 // TODO: set some vars?
962         } else {
963                 // show regular index page
964                 global $startpos;
965                 $type = 'index';
966         }
967
968         // decide which blog should be displayed
969         if (!$blogid) {
970                 $blogid = $CONF['DefaultBlog'];
971         }
972
973         $b =& $manager->getBlog($blogid);
974         $blog = $b;     // references can't be placed in global variables?
975
976         if (!$blog->isValid) {
977                 doError(_ERROR_NOSUCHBLOG);
978         }
979
980         // set catid if necessary
981         if ($catid) {
982                 $blog->setSelectedCategory($catid);
983         }
984
985         // decide which skin should be used
986         if ($skinid != '' && ($skinid == 0) ) {
987                 selectSkin($skinid);
988         }
989
990         if (!$skinid) {
991                 $skinid = $blog->getDefaultSkin();
992         }
993
994         $special = requestVar('special');
995         if (!empty($special) && isValidShortName($special)) {
996                 $type = strtolower($special);
997         }
998
999         $skin = new SKIN($skinid);
1000
1001         if (!$skin->isValid) {
1002                 doError(_ERROR_NOSUCHSKIN);
1003         }
1004
1005         // parse the skin
1006         $skin->parse($type);
1007
1008         // check to see we should throw JustPosted event
1009         $blog->checkJustPosted();
1010 }
1011
1012 /**
1013   * Show error skin with given message. An optional skin-object to use can be given
1014   */
1015 function doError($msg, $skin = '') {
1016         global $errormessage, $CONF, $skinid, $blogid, $manager;
1017
1018         if ($skin == '') {
1019
1020                 if (SKIN::existsID($skinid) ) {
1021                         $skin = new SKIN($skinid);
1022                 } elseif ($manager->existsBlogID($blogid) ) {
1023                         $blog =& $manager->getBlog($blogid);
1024                         $skin = new SKIN($blog->getDefaultSkin() );
1025                 } elseif ($CONF['DefaultBlog']) {
1026                         $blog =& $manager->getBlog($CONF['DefaultBlog']);
1027                         $skin = new SKIN($blog->getDefaultSkin() );
1028                 } else {
1029                         // this statement should actually never be executed
1030                         $skin = new SKIN($CONF['BaseSkin']);
1031                 }
1032
1033         }
1034
1035         $errormessage = $msg;
1036         $skin->parse('error');
1037         exit;
1038 }
1039
1040 function getConfig() {
1041         global $CONF;
1042
1043         $query = 'SELECT * FROM ' . sql_table('config');
1044         $res = sql_query($query);
1045
1046         while ($obj = mysql_fetch_object($res) ) {
1047                 $CONF[$obj->name] = $obj->value;
1048         }
1049 }
1050
1051 // some checks for names of blogs, categories, templates, members, ...
1052 function isValidShortName($name) {
1053         return eregi('^[a-z0-9]+$', $name);
1054 }
1055
1056 function isValidDisplayName($name) {
1057         return eregi('^[a-z0-9]+[a-z0-9 ]*[a-z0-9]+$', $name);
1058 }
1059
1060 function isValidCategoryName($name) {
1061         return 1;
1062 }
1063
1064 function isValidTemplateName($name) {
1065         return eregi('^[a-z0-9/]+$', $name);
1066 }
1067
1068 function isValidSkinName($name) {
1069         return eregi('^[a-z0-9/]+$', $name);
1070 }
1071
1072 // add and remove linebreaks
1073 function addBreaks($var) {
1074         return nl2br($var);
1075 }
1076
1077 function removeBreaks($var) {
1078         return preg_replace("/<br \/>([\r\n])/", "$1", $var);
1079 }
1080
1081 // shortens a text string to maxlength ($toadd) is what needs to be added
1082 // at the end (end length is <= $maxlength)
1083 function shorten($text, $maxlength, $toadd) {
1084         // 1. remove entities...
1085 //      $trans = get_html_translation_table(HTML_ENTITIES);
1086         $trans = get_html_translation_table(HTML_SPECIALCHARS); // for Japanese
1087         $trans = array_flip($trans);
1088         $text = strtr($text, $trans);
1089
1090         // 2. the actual shortening
1091         if (strlen($text) > $maxlength)
1092                 $text = mb_strimwidth($text, 0, $maxlength, $toadd, _CHARSET);
1093         return $text;
1094 }
1095
1096 /**
1097   * Converts a unix timestamp to a mysql DATETIME format, and places
1098   * quotes around it.
1099   */
1100 function mysqldate($timestamp) {
1101         return '"' . date('Y-m-d H:i:s', $timestamp) . '"';
1102 }
1103
1104 /**
1105   * functions for use in index.php
1106   */
1107 function selectBlog($shortname) {
1108         global $blogid, $archivelist;
1109         $blogid = getBlogIDFromName($shortname);
1110
1111         // also force archivelist variable, if it is set
1112         if ($archivelist) {
1113                 $archivelist = $blogid;
1114         }
1115 }
1116
1117 function selectSkin($skinname) {
1118         global $skinid;
1119         $skinid = SKIN::getIdFromName($skinname);
1120 }
1121
1122 /**
1123  * Can take either a category ID or a category name (be aware that
1124  * multiple categories can have the same name)
1125  */
1126 function selectCategory($cat) {
1127         global $catid;
1128         if (is_numeric($cat) ) {
1129                 $catid = intval($cat);
1130         } else {
1131                 $catid = getCatIDFromName($cat);
1132         }
1133 }
1134
1135 function selectItem($id) {
1136         global $itemid;
1137         $itemid = intval($id);
1138 }
1139
1140 // force the use of a language file (warning: can cause warnings)
1141 function selectLanguage($language) {
1142         global $DIR_LANG;
1143         include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');
1144 }
1145
1146 function parseFile($filename, $includeMode = 'normal', $includePrefix = '') {
1147         $handler = new ACTIONS('fileparser');
1148         $parser = new PARSER(SKIN::getAllowedActionsForType('fileparser'), $handler);
1149         $handler->parser =& $parser;
1150
1151         // set IncludeMode properties of parser
1152         PARSER::setProperty('IncludeMode', $includeMode);
1153         PARSER::setProperty('IncludePrefix', $includePrefix);
1154
1155         if (!file_exists($filename) ) {
1156                 doError('A file is missing');
1157         }
1158
1159         $fsize = filesize($filename);
1160
1161         if ($fsize <= 0) {
1162                 return;
1163         }
1164
1165         // read file
1166         $fd = fopen ($filename, 'r');
1167         $contents = fread ($fd, $fsize);
1168         fclose ($fd);
1169
1170         // parse file contents
1171         $parser->parse($contents);
1172 }
1173
1174 /**
1175   * Outputs a debug message
1176   */
1177 function debug($msg) {
1178         echo '<p><b>' . $msg . "</b></p>\n";
1179 }
1180
1181 // shortcut
1182 function addToLog($level, $msg) {
1183         ACTIONLOG::add($level, $msg);
1184 }
1185
1186 // shows a link to help file
1187 function help($id) {
1188         echo helpHtml($id);
1189 }
1190
1191 function helpHtml($id) {
1192         return helplink($id) . '<img src="documentation/icon-help.gif" width="15" height="15" alt="' . _HELP_TT . '" /></a>';
1193 }
1194
1195 function helplink($id) {
1196         return '<a href="documentation/help.html#'. $id . '" onclick="if (event &amp;&amp; event.preventDefault) event.preventDefault(); return help(this.href);">';
1197 }
1198
1199 function getMailFooter() {
1200         $message = "\n\n-----------------------------";
1201         $message .=  "\n   Powered by Nucleus CMS";
1202         $message .=  "\n(http://www.nucleuscms.org/)";
1203         return $message;
1204 }
1205
1206 /**
1207   * Returns the name of the language to use
1208   * preference priority: member - site
1209   * defaults to english when no good language found
1210   *
1211   * checks if file exists, etc...
1212   */
1213 function getLanguageName() {
1214         global $CONF, $member;
1215
1216         if ($member && $member->isLoggedIn() ) {
1217                 // try to use members language
1218                 $memlang = $member->getLanguage();
1219
1220                 if (($memlang != '') && (checkLanguage($memlang) ) ) {
1221                         return $memlang;
1222                 }
1223         }
1224
1225         // use default language
1226         if (checkLanguage($CONF['Language']) ) {
1227                 return $CONF['Language'];
1228         } else {
1229                 return 'english';
1230         }
1231 }
1232
1233 /**
1234   * Includes a PHP file. This method can be called while parsing templates and skins
1235   */
1236 function includephp($filename) {
1237         // make predefined variables global, so most simple scripts can be used here
1238
1239         // apache (names taken from PHP doc)
1240         global $GATEWAY_INTERFACE, $SERVER_NAME, $SERVER_SOFTWARE, $SERVER_PROTOCOL;
1241         global $REQUEST_METHOD, $QUERY_STRING, $DOCUMENT_ROOT, $HTTP_ACCEPT;
1242         global $HTTP_ACCEPT_CHARSET, $HTTP_ACCEPT_ENCODING, $HTTP_ACCEPT_LANGUAGE;
1243         global $HTTP_CONNECTION, $HTTP_HOST, $HTTP_REFERER, $HTTP_USER_AGENT;
1244         global $REMOTE_ADDR, $REMOTE_PORT, $SCRIPT_FILENAME, $SERVER_ADMIN;
1245         global $SERVER_PORT, $SERVER_SIGNATURE, $PATH_TRANSLATED, $SCRIPT_NAME;
1246         global $REQUEST_URI;
1247
1248         // php (taken from PHP doc)
1249         global $argv, $argc, $PHP_SELF, $HTTP_COOKIE_VARS, $HTTP_GET_VARS, $HTTP_POST_VARS;
1250         global $HTTP_POST_FILES, $HTTP_ENV_VARS, $HTTP_SERVER_VARS, $HTTP_SESSION_VARS;
1251
1252         // other
1253         global $PATH_INFO, $HTTPS, $HTTP_RAW_POST_DATA, $HTTP_X_FORWARDED_FOR;
1254
1255         if (@file_exists($filename) ) {
1256                 include($filename);
1257         }
1258 }
1259
1260 /**
1261   * Checks if a certain language/plugin exists
1262   */
1263 function checkLanguage($lang) {
1264         global $DIR_LANG ;
1265         return file_exists($DIR_LANG . ereg_replace( '[\\|/]', '', $lang) . '.php');
1266 }
1267
1268 function checkPlugin($plug) {
1269         global $DIR_PLUGINS;
1270         return file_exists($DIR_PLUGINS . ereg_replace( '[\\|/]', '', $plug) . '.php');
1271 }
1272
1273 /**
1274   * Centralisation of the functions that generate links
1275   */
1276 function createItemLink($itemid, $extra = '') {
1277         return createLink('item', array('itemid' => $itemid, 'extra' => $extra) );
1278 }
1279
1280 function createMemberLink($memberid, $extra = '') {
1281         return createLink('member', array('memberid' => $memberid, 'extra' => $extra) );
1282 }
1283
1284 function createCategoryLink($catid, $extra = '') {
1285         return createLink('category', array('catid' => $catid, 'extra' => $extra) );
1286 }
1287
1288 function createArchiveListLink($blogid = '', $extra = '') {
1289         return createLink('archivelist', array('blogid' => $blogid, 'extra' => $extra) );
1290 }
1291
1292 function createArchiveLink($blogid, $archive, $extra = '') {
1293         return createLink('archive', array('blogid' => $blogid, 'archive' => $archive, 'extra' => $extra) );
1294 }
1295
1296 function createBlogidLink($blogid, $params = '') {
1297         return createLink('blog', array('blogid' => $blogid, 'extra' => $params) );
1298 }
1299
1300 function createLink($type, $params) {
1301         global $manager, $CONF;
1302
1303         $generatedURL = '';
1304         $usePathInfo = ($CONF['URLMode'] == 'pathinfo');
1305
1306         // ask plugins first
1307         $created = false;
1308
1309         if ($usePathInfo) {
1310                 $manager->notify(
1311                         'GenerateURL',
1312                         array(
1313                                 'type' => $type,
1314                                 'params' => $params,
1315                                 'completed' => &$created,
1316                                 'url' => &$url
1317                         )
1318                 );
1319         }
1320
1321         // if a plugin created the URL, return it
1322         if ($created) {
1323                 return $url;
1324         }
1325
1326         // default implementation
1327         switch ($type) {
1328                 case 'item':
1329                         if ($usePathInfo) {
1330                                 $url = $CONF['ItemURL'] . '/' . $CONF['ItemKey'] . '/' . $params['itemid'];
1331                         } else {
1332                                 $url = $CONF['ItemURL'] . '?itemid=' . $params['itemid'];
1333                         }
1334                         break;
1335
1336                 case 'member':
1337                         if ($usePathInfo) {
1338                                 $url = $CONF['MemberURL'] . '/' . $CONF['MemberKey'] . '/' . $params['memberid'];
1339                         } else {
1340                                 $url = $CONF['MemberURL'] . '?memberid=' . $params['memberid'];
1341                         }
1342                         break;
1343
1344                 case 'category':
1345                         if ($usePathInfo) {
1346                                 $url = $CONF['CategoryURL'] . '/' . $CONF['CategoryKey'] . '/' . $params['catid'];
1347                         } else {
1348                                 $url = $CONF['CategoryURL'] . '?catid=' . $params['catid'];
1349                         }
1350                         break;
1351
1352                 case 'archivelist':
1353                         if (!$params['blogid']) {
1354                                 $params['blogid'] = $CONF['DefaultBlog'];
1355                         }
1356
1357                         if ($usePathInfo) {
1358                                 $url = $CONF['ArchiveListURL'] . '/' . $CONF['ArchivesKey'] . '/' . $params['blogid'];
1359                         } else {
1360                                 $url = $CONF['ArchiveListURL'] . '?archivelist=' . $params['blogid'];
1361                         }
1362                         break;
1363
1364                 case 'archive':
1365                         if ($usePathInfo) {
1366                                 $url = $CONF['ArchiveURL'] . '/' . $CONF['ArchiveKey'] . '/'.$params['blogid'].'/' . $params['archive'];
1367                         } else {
1368                                 $url = $CONF['ArchiveURL'] . '?blogid='.$params['blogid'].'&amp;archive=' . $params['archive'];
1369                         }
1370                         break;
1371
1372                 case 'blog':
1373                         if ($usePathInfo) {
1374                                 $url = $CONF['BlogURL'] . '/' . $CONF['BlogKey'] . '/' . $params['blogid'];
1375                         } else {
1376                                 $url = $CONF['BlogURL'] . '?blogid=' . $params['blogid'];
1377                         }
1378                         break;
1379         }
1380
1381         return addLinkParams($url, (isset($params['extra'])? $params['extra'] : null));
1382 }
1383
1384 function createBlogLink($url, $params) {
1385     global $CONF;
1386     if ($CONF['URLMode'] == 'normal') {
1387         if (strpos($url, '?') === FALSE && is_array($params)) {
1388             $fParam = reset($params);
1389             $fKey   = key($params);
1390             array_shift($params);
1391             $url .= '?' . $fKey . '=' . $fParam;
1392         }
1393     } elseif ($CONF['URLMode'] == 'pathinfo' && substr($url, -1) == '/') {
1394         $url = substr($url, 0, -1);
1395     }
1396         return addLinkParams($url, $params);
1397 }
1398
1399 function addLinkParams($link, $params) {
1400         global $CONF;
1401
1402         if (is_array($params) ) {
1403
1404                 if ($CONF['URLMode'] == 'pathinfo')     {
1405
1406                         foreach ($params as $param => $value) {
1407                                 $link .= '/' . $param . '/' . urlencode($value);
1408                         }
1409
1410                 } else {
1411
1412                         foreach ($params as $param => $value) {
1413                                 $link .= '&amp;' . $param . '=' . urlencode($value);
1414                         }
1415
1416                 }
1417         }
1418
1419         return $link;
1420 }
1421
1422 /**
1423  * @param $querystr
1424  *              querystring to alter (e.g. foo=1&bar=2&x=y)
1425  * @param $param
1426  *              name of parameter to change (e.g. 'foo')
1427  * @param $value
1428  *              New value for that parameter (e.g. 3)
1429  * @result
1430  *              altered query string (for the examples above: foo=3&bar=2&x=y)
1431  */
1432 function alterQueryStr($querystr, $param, $value) {
1433         $vars = explode('&', $querystr);
1434         $set  = false;
1435
1436         for ($i = 0; $i < count($vars); $i++) {
1437                 $v = explode('=', $vars[$i]);
1438
1439                 if ($v[0] == $param) {
1440                         $v[1] = $value;
1441                         $vars[$i] = implode('=', $v);
1442                         $set = true;
1443                         break;
1444                 }
1445         }
1446
1447         if (!$set) {
1448                 $vars[] = $param . '=' . $value;
1449         }
1450
1451         return ltrim(implode('&', $vars), '&');
1452 }
1453
1454 // passes one variable as hidden input field (multiple fields for arrays)
1455 // @see passRequestVars in varsx.x.x.php
1456 function passVar($key, $value) {
1457         // array ?
1458         if (is_array($value) ) {
1459                 for ($i = 0; $i < sizeof($value); $i++) {
1460                         passVar($key . '[' . $i . ']', $value[$i]);
1461                 }
1462
1463                 return;
1464         }
1465
1466         // other values: do stripslashes if needed
1467         ?><input type="hidden" name="<?php echo htmlspecialchars($key)?>" value="<?php echo htmlspecialchars(undoMagic($value) )?>" /><?php
1468 }
1469
1470 /*
1471         Date format functions (to be used from [%date(..)%] skinvars
1472 */
1473 function formatDate($format, $timestamp, $defaultFormat, &$blog) {
1474         // apply blog offset (#42)
1475         $boffset = $blog ? $blog->getTimeOffset() * 3600 : 0;
1476         $offset = date('Z', $timestamp) + $boffset;
1477
1478         switch ($format) {
1479                 case 'rfc822':
1480                         if ($offset >= 0) {
1481                                 $tz = '+';
1482                         } else {
1483                                 $tz = '-';
1484                                 $offset = -$offset;
1485                         }
1486
1487                         $tz .= sprintf("%02d%02d", floor($offset / 3600), round(($offset % 3600) / 60) );
1488                         return date('D, j M Y H:i:s ', $timestamp) . $tz;
1489
1490                 case 'rfc822GMT':
1491                         $timestamp -= $offset;
1492                         return date('D, j M Y H:i:s ', $timestamp) . 'GMT';
1493
1494                 case 'utc':
1495                         $timestamp -= $offset;
1496                         return date('Y-m-d\TH:i:s\Z', $timestamp);
1497
1498                 case 'iso8601':
1499                         if ($offset >= 0) {
1500                                 $tz = '+';
1501                         } else {
1502                                 $tz = '-';
1503                                 $offset = -$offset;
1504                         }
1505
1506                         $tz .= sprintf("%02d:%02d", floor($offset / 3600), round(($offset % 3600) / 60) );
1507                         return date('Y-m-d\TH:i:s', $timestamp) . $tz;
1508
1509                 default :
1510                         return strftime($format ? $format : $defaultFormat, $timestamp);
1511         }
1512 }
1513
1514 function encoding_check($val, $key, $encoding=false, $exclude=false) {\r
1515         /*\r
1516           When 3rd argument is set, return if checked already.\r
1517           When 4th argument is set, set the excluded key(s).\r
1518         */\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[$excludes]=true;\r
1524                 return;\r
1525         }\r
1526         if ($encoding!==false) {\r
1527                 switch($encoding=strtolower($encoding)){\r
1528                         case 'utf-8':\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
1535                                         break;\r
1536                         case 'euc-jp':\r
1537                                 $search='/^([\x00-\x7F]+'.\r
1538                                         '|[\x8E][\xA0-\xDF]'.\r
1539                                         '|[\x8F]?[\xA1-\xFE][\xA1-\xFE])*/';\r
1540                                 break;\r
1541                         case 'gb2312':\r
1542                                 $search='/^([\x00-\x7F]+'.\r
1543                                         '|[\xA1-\xF7][\xA1-\xFE])*/';\r
1544                                 break;\r
1545                         default:\r
1546                                 $search=false;\r
1547                                 if (preg_match('/^iso\-8859\-[0-9]{1,2}$/',$encoding)) break;\r
1548                                 if (preg_match('/^windows\-125[0-8]$/',$encoding)) break;\r
1549                                 startUpError('<p>Unknown or non-supported encoding.</p>', 'Encoding Error');\r
1550                                 exit;\r
1551                 }\r
1552                 if (isset($checked[$encoding])) return true; // Already checked.\r
1553                 $checked[$encoding]=true;\r
1554         }\r
1555         if ($key===false) return false; // Not yet checked.\r
1556         if ($search===false) return true; // non-multibyte encoding\r
1557         if (isset($excludes[$key])) return true; // This key isn't checked.\r
1558         if (is_array($val)) {\r
1559                 array_walk($val, 'encoding_check');\r
1560         } else {\r
1561                 preg_match($search,$val,$m);\r
1562                 $val2 = (string)$m[0];\r
1563                 if (!($val2 === (string)$val)) {\r
1564                         startUpError('<p>Invalid input.</p>', 'Input Error');\r
1565                         exit;\r
1566                 }\r
1567         }\r
1568         preg_match($search,$key,$m);\r
1569         $key2 = (string)$m[0];\r
1570         if (!($key2 === (string)$key)) {\r
1571                 startUpError('<p>Invalid input.</p>', 'Input Error');\r
1572                 exit;\r
1573         }\r
1574         return true;\r
1575 }\r
1576 \r
1577 function checkVars($aVars) {
1578         global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_ENV_VARS, $HTTP_POST_FILES, $HTTP_SESSION_VARS;
1579
1580         foreach ($aVars as $varName) {
1581
1582                 if (phpversion() >= '4.1.0') {
1583
1584                         if (   isset($_GET[$varName])
1585                                 || isset($_POST[$varName])
1586                                 || isset($_COOKIE[$varName])
1587                                 || isset($_ENV[$varName])
1588                                 || isset($_SESSION[$varName])
1589                                 || isset($_FILES[$varName])
1590                         ) {
1591                                 die('Sorry. An error occurred.');
1592                         }
1593
1594                 } else {
1595
1596                         if (   isset($HTTP_GET_VARS[$varName])
1597                                 || isset($HTTP_POST_VARS[$varName])
1598                                 || isset($HTTP_COOKIE_VARS[$varName])
1599                                 || isset($HTTP_ENV_VARS[$varName])
1600                                 || isset($HTTP_SESSION_VARS[$varName])
1601                                 || isset($HTTP_POST_FILES[$varName])
1602                         ) {
1603                                 die('Sorry. An error occurred.');
1604                         }
1605
1606                 }
1607         }
1608 }
1609
1610
1611 /** 
1612  * Sanitize parameters such as $_GET and $_SERVER['REQUEST_URI'] etc.
1613  * to avoid XSS 
1614  */
1615 function sanitizeParams()
1616 {
1617         global $HTTP_SERVER_VARS;
1618         
1619         $array = array();
1620         $str = '';
1621         $frontParam = '';
1622         
1623         // REQUEST_URI of $HTTP_SERVER_VARS
1624         $str =& $HTTP_SERVER_VARS["REQUEST_URI"];
1625         serverStringToArray($str, $array, $frontParam);
1626         sanitizeArray($array);
1627         arrayToServerString($array, $frontParam, $str);
1628         
1629         // QUERY_STRING of $HTTP_SERVER_VARS
1630         $str =& $HTTP_SERVER_VARS["QUERY_STRING"];
1631         serverStringToArray($str, $array, $frontParam);
1632         sanitizeArray($array);
1633         arrayToServerString($array, $frontParam, $str);
1634         
1635         if (phpversion() >= '4.1.0') {
1636                 // REQUEST_URI of $_SERVER
1637                 $str =& $_SERVER["REQUEST_URI"];
1638                 serverStringToArray($str, $array, $frontParam);
1639                 sanitizeArray($array);
1640                 arrayToServerString($array, $frontParam, $str);
1641         
1642                 // QUERY_STRING of $_SERVER
1643                 $str =& $_SERVER["QUERY_STRING"];
1644                 serverStringToArray($str, $array, $frontParam);
1645                 sanitizeArray($array);
1646                 arrayToServerString($array, $frontParam, $str);
1647         }
1648         
1649         // $_GET
1650         convArrayForSanitizing($_GET, $array);
1651         sanitizeArray($array);
1652         revertArrayForSanitizing($array, $_GET);
1653         
1654         // $_REQUEST (only GET param)
1655         convArrayForSanitizing($_REQUEST, $array);
1656         sanitizeArray($array);
1657         revertArrayForSanitizing($array, $_REQUEST);
1658 }
1659
1660 /** 
1661  * Check ticket when not checked in plugin's admin page
1662  * to avoid CSRF.
1663  * Also avoid the access to plugin/index.php by guest user.
1664  */
1665 function ticketForPlugin(){
1666         global $CONF,$DIR_PLUGINS,$member,$ticketforplugin;
1667         
1668         /* initialize */
1669         $ticketforplugin=array();
1670         $ticketforplugin['ticket']=false;
1671         
1672         /* Check if using plugin's php file. */
1673         if ($p_translated=serverVar('PATH_TRANSLATED')) {
1674                 if (!file_exists($p_translated)) $p_translated='';
1675         }
1676         if (!$p_translated) {
1677                 $p_translated=serverVar('SCRIPT_FILENAME');
1678                 if (!file_exists($p_translated)) {
1679                         header("HTTP/1.0 404 Not Found");
1680                         exit('');
1681                 }
1682         }
1683         $p_translated=str_replace('\\','/',$p_translated);
1684         $d_plugins=str_replace('\\','/',$DIR_PLUGINS);
1685         if (strpos($p_translated,$d_plugins)!==0) return;// This isn't plugin php file.
1686         
1687         /* Solve the plugin php file or admin directory */
1688         $phppath=substr($p_translated,strlen($d_plugins));
1689         $phppath=preg_replace('!^/!','',$phppath);// Remove the first "/" if exists.
1690         $path=preg_replace('/^NP_(.*)\.php$/','$1',$phppath); // Remove the first "NP_" and the last ".php" if exists.
1691         $path=preg_replace('!^([^/]*)/(.*)$!','$1',$path); // Remove the "/" and beyond.
1692         
1693         /* Solve the plugin name. */
1694         $plugins=array();
1695         $query='SELECT pfile FROM '.sql_table('plugin');
1696         $res=sql_query($query);
1697         while($row=mysql_fetch_row($res)) {
1698                 $name=substr($row[0],3);
1699                 $plugins[strtolower($name)]=$name;
1700         }
1701         mysql_free_result($res);
1702         if ($plugins[$path]) $plugin_name=$plugins[$path];
1703         else if (in_array($path,$plugins)) $plugin_name=$path;
1704         else {
1705                 header("HTTP/1.0 404 Not Found");
1706                 exit('');
1707         }
1708         
1709         /* Return if not index.php */
1710         if ( $phppath!=strtolower($plugin_name).'/'
1711                 && $phppath!=strtolower($plugin_name).'/index.php' ) return;
1712         
1713         /* Exit if not logged in. */
1714         if ( !$member->isLoggedIn() ) exit("You aren't logged in.");
1715         
1716         global $manager,$DIR_LIBS,$DIR_LANG,$HTTP_GET_VARS,$HTTP_POST_VARS;
1717         
1718         /* Check if this feature is needed (ie, if "$manager->checkTicket()" is not included in the script). */
1719         if (!($p_translated=serverVar('PATH_TRANSLATED'))) $p_translated=serverVar('SCRIPT_FILENAME');
1720         if ($file=@file($p_translated)) {
1721                 $prevline='';
1722                 foreach($file as $line) {
1723                         if (preg_match('/[\$]manager([\s]*)[\-]>([\s]*)checkTicket([\s]*)[\(]/i',$prevline.$line)) return;
1724                         $prevline=$line;
1725                 }
1726         }
1727         
1728         /* Show a form if not valid ticket */
1729         if ( ( strstr(serverVar('REQUEST_URI'),'?') || serverVar('QUERY_STRING')
1730                         || strtoupper(serverVar('REQUEST_METHOD'))=='POST' )
1731                                 && (!$manager->checkTicket()) ){
1732
1733                 if (!class_exists('PluginAdmin')) {
1734                         $language = getLanguageName();
1735                         include($DIR_LANG . ereg_replace( '[\\|/]', '', $language) . '.php');
1736                         include($DIR_LIBS . 'PLUGINADMIN.php');
1737                 }
1738                 if (!(function_exists('mb_strimwidth') || extension_loaded('mbstring'))) {
1739                         if (file_exists($DIR_LIBS.'mb_emulator/mb-emulator.php')) {
1740                                 global $mbemu_internals;
1741                                 include_once($DIR_LIBS.'mb_emulator/mb-emulator.php');
1742                         }
1743                 }
1744                 $oPluginAdmin = new PluginAdmin($plugin_name);
1745                 $oPluginAdmin->start();
1746                 echo '<p>' . _ERROR_BADTICKET . "</p>\n";
1747                 
1748                 /* Show the form to confirm action */
1749                 // PHP 4.0.x support
1750                 $get=  (isset($_GET))  ? $_GET  : $HTTP_GET_VARS;
1751                 $post= (isset($_POST)) ? $_POST : $HTTP_POST_VARS;
1752                 // Resolve URI and QUERY_STRING
1753                 if ($uri=serverVar('REQUEST_URI')) {
1754                         list($uri,$qstring)=explode('?',$uri);
1755                 } else {
1756                         if ( !($uri=serverVar('PHP_SELF')) ) $uri=serverVar('SCRIPT_NAME');
1757                         $qstring=serverVar('QUERY_STRING');
1758                 }
1759                 if ($qstring) $qstring='?'.$qstring;
1760                 echo '<p>'._SETTINGS_UPDATE.' : '._QMENU_PLUGINS.' <span style="color:red;">'.
1761                         htmlspecialchars($plugin_name)."</span> ?</p>\n";
1762                 switch(strtoupper(serverVar('REQUEST_METHOD'))){
1763                 case 'POST':
1764                         echo '<form method="POST" action="'.htmlspecialchars($uri.$qstring).'">';
1765                         $manager->addTicketHidden();
1766                         _addInputTags($post);
1767                         break;
1768                 case 'GET':
1769                         echo '<form method="GET" action="'.htmlspecialchars($uri).'">';
1770                         $manager->addTicketHidden();
1771                         _addInputTags($get);
1772                 default:
1773                         break;
1774                 }
1775                 echo '<input type="submit" value="'._YES.'" />&nbsp;&nbsp;&nbsp;&nbsp;';
1776                 echo '<input type="button" value="'._NO.'" onclick="history.back(); return false;" />';
1777                 echo "</form>\n";
1778                 
1779                 $oPluginAdmin->end();
1780                 exit;
1781         }
1782         
1783         /* Create new ticket */
1784         $ticket=$manager->addTicketToUrl('');
1785         $ticketforplugin['ticket']=substr($ticket,strpos($ticket,'ticket=')+7);
1786 }
1787 function _addInputTags(&$keys,$prefix=''){
1788         foreach($keys as $key=>$value){
1789                 if ($prefix) $key=$prefix.'['.$key.']';
1790                 if (is_array($value)) _addInputTags($value,$key);
1791                 else {
1792                         if (get_magic_quotes_gpc()) $value=stripslashes($value);
1793                         if ($key=='ticket') continue;
1794                         echo '<input type="hidden" name="'.htmlspecialchars($key).
1795                                 '" value="'.htmlspecialchars($value).'" />'."\n";
1796                 }
1797         }
1798 }
1799
1800 /** 
1801  * Convert the server string such as $_SERVER['REQUEST_URI']
1802  * to arry like arry['blogid']=1 and array['page']=2 etc.
1803  */
1804 function serverStringToArray($str, &$array, &$frontParam)
1805 {
1806         // init param
1807         $array = array();
1808         $fronParam = "";
1809
1810         // split front param, e.g. /index.php, and others, e.g. blogid=1&page=2
1811         if (strstr($str, "?")){
1812                 list($frontParam, $args) = preg_split("/\?/", $str, 2);
1813         }
1814         else {
1815                 $args = $str;
1816                 $frontParam = "";
1817         }
1818         
1819         // If there is no args like blogid=1&page=2, return
1820         if (!strstr($str, "=") && !strlen($frontParam)) {
1821                 $frontParam = $str;
1822                 return;
1823         }
1824
1825         $array = explode("&", $args);
1826 }
1827
1828 /** 
1829  * Convert array like array['blogid'] to server string
1830  * such as $_SERVER['REQUEST_URI']
1831  */
1832 function arrayToServerString($array, $frontParam, &$str)
1833 {
1834         if (strstr($str, "?")) {
1835                 $str = $frontParam . "?";
1836         } else {
1837                 $str = $frontParam;
1838         }
1839         if (count($array)) {
1840                 $str .= implode("&", $array);
1841         }
1842 }
1843
1844 /** 
1845  * Sanitize array parameters.
1846  * This function checks both key and value.
1847  * - check key if it inclues " (double quote),  remove from array
1848  * - check value if it includes \ (escape sequece), remove remaining string
1849  */
1850 function sanitizeArray(&$array)
1851 {       
1852         $excludeListForSanitization = array('query');
1853 //      $excludeListForSanitization = array();
1854
1855         foreach ($array as $k => $v) {
1856
1857                 // split to key and value
1858                 list($key, $val) = preg_split("/=/", $v, 2);
1859                 if (!isset($val)) {
1860                         continue;
1861                 }
1862
1863                 // when magic quotes is on, need to use stripslashes,
1864                 // and then addslashes
1865                 if (get_magic_quotes_gpc()) {
1866                         $val = stripslashes($val);
1867                 }
1868                 $val = addslashes($val);
1869                 
1870                 // if $key is included in exclude list, skip this param
1871                 if (!in_array($key, $excludeListForSanitization)) {
1872                                 
1873                         // check value
1874                         @list($val, $tmp) = explode('\\', $val);
1875                         
1876                         // remove control code etc.
1877                         $val = strtr($val, "\0\r\n<>'\"", "       ");
1878                                 
1879                         // check key
1880                         if (preg_match('/\"/i', $key)) {
1881                                 unset($array[$k]);
1882                                 continue;
1883                         }
1884                                 
1885                         // set sanitized info
1886                         $array[$k] = sprintf("%s=%s", $key, $val);
1887                 }
1888         }
1889 }
1890
1891 /**
1892  * Convert array for sanitizeArray function
1893  */
1894 function convArrayForSanitizing($src, &$array)
1895 {
1896         $array = array();
1897         foreach ($src as $key => $val) {
1898                 if (key_exists($key, $_GET)) {
1899                         array_push($array, sprintf("%s=%s", $key, $val));
1900                 }
1901         }
1902 }
1903
1904 /**
1905  * Revert array after sanitizeArray function
1906  */
1907 function revertArrayForSanitizing($array, &$dst)
1908 {
1909         foreach ($array as $v) {
1910                 list($key, $val) = preg_split("/=/", $v, 2);
1911                 $dst[$key] = $val;
1912         }
1913 }
1914
1915 /**
1916  * Stops processing the request and redirects to the given URL.
1917  * - no actual contents should have been sent to the output yet
1918  * - the URL will be stripped of illegal or dangerous characters
1919  */
1920 function redirect($url) {
1921         $url = preg_replace('|[^a-z0-9-~+_.?#=&;,/:@%]|i', '', $url);
1922         header('Location: ' . $url);
1923         exit;
1924 }
1925
1926 /**
1927  * Strip HTML tags from a string
1928  * This function is a bit more intelligent than a regular call to strip_tags(),
1929  * because it also deletes the contents of certain tags and cleans up any
1930  * unneeded whitespace.
1931  */
1932 function stringStripTags ($string) {
1933         $string = preg_replace("/<del[^>]*>.+<\/del[^>]*>/isU", '', $string);
1934         $string = preg_replace("/<script[^>]*>.+<\/script[^>]*>/isU", '', $string);
1935         $string = preg_replace("/<style[^>]*>.+<\/style[^>]*>/isU", '', $string);
1936         $string = str_replace('>', '> ', $string);
1937         $string = str_replace('<', ' <', $string);
1938         $string = strip_tags($string);
1939         $string = preg_replace("/\s+/", " ", $string);
1940         $string = trim($string);
1941         return $string;
1942 }
1943
1944 /**
1945  * Make a string containing HTML safe for use in a HTML attribute
1946  * Tags are stripped and entities are normalized
1947  */
1948 function stringToAttribute ($string) {
1949         $string = stringStripTags($string);
1950         $string = entity::named_to_numeric($string);
1951         $string = entity::normalize_numeric($string);
1952
1953         if (_CHARSET == 'UTF-8') {
1954                 $string = entity::numeric_to_utf8($string);
1955         }
1956
1957         $string = entity::specialchars($string, 'html');
1958         $string = entity::numeric_to_named($string);
1959         return $string;
1960 }
1961
1962 /**
1963  * Make a string containing HTML safe for use in a XML document
1964  * Tags are stripped, entities are normalized and named entities are
1965  * converted to numeric entities.
1966  */
1967 function stringToXML ($string) {
1968         $string = stringStripTags($string);
1969         $string = entity::named_to_numeric($string);
1970         $string = entity::normalize_numeric($string);
1971
1972         if (_CHARSET == 'UTF-8') {
1973                 $string = entity::numeric_to_utf8($string);
1974         }
1975
1976         $string = entity::specialchars($string, 'xml');
1977         return $string;
1978 }
1979
1980 // START: functions from the end of file BLOG.php
1981 // used for mail notification (html -> text)
1982 function toAscii($html) {
1983         // strip off most tags
1984         $html = strip_tags($html,'<a>');
1985         $to_replace = "/<a[^>]*href=[\"\']([^\"^']*)[\"\'][^>]*>([^<]*)<\/a>/i";
1986         _links_init();
1987         $ascii = preg_replace_callback ($to_replace, '_links_add', $html);
1988         $ascii .= "\n\n" . _links_list();
1989         return strip_tags($ascii);
1990 }
1991
1992 function _links_init() {
1993    global $tmp_links;
1994    $tmp_links = array();
1995 }
1996
1997 function _links_add($match) {
1998    global $tmp_links;
1999    array_push($tmp_links, $match[1]);
2000    return $match[2] . ' [' . sizeof($tmp_links) .']';
2001 }
2002
2003 function _links_list() {
2004    global $tmp_links;
2005    $output = '';
2006    $i = 1;
2007    foreach ($tmp_links as $current) {
2008           $output .= "[$i] $current\n";
2009           $i++;
2010    }
2011    return $output;
2012 }
2013 // END: functions from the end of file BLOG.php
2014
2015 // START: functions from the end of file ADMIN.php
2016 /**
2017  * @todo document this
2018  */
2019 function encode_desc(&$data)
2020     {   //_$to_entities = get_html_translation_table(HTML_ENTITIES);
2021         $to_entities = get_html_translation_table(HTML_SPECIALCHARS);
2022         $from_entities = array_flip($to_entities);
2023         $data = str_replace('<br />','\n',$data); //hack
2024         $data = strtr($data,$from_entities);
2025         $data = strtr($data,$to_entities);
2026         $data = str_replace('\n','<br />',$data); //hack
2027         return $data;
2028     }
2029  
2030 /**
2031  * Returns the Javascript code for a bookmarklet that works on most modern browsers
2032  *
2033  * @param blogid
2034  */
2035 function getBookmarklet($blogid) {
2036         global $CONF;
2037
2038         // normal
2039         $document = 'document';
2040         $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('";
2041         $bookmarkletline .= $CONF['AdminURL'] . "bookmarklet.php?blogid=$blogid";
2042         $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();";
2043
2044         return $bookmarkletline;
2045 }
2046 // END: functions from the end of file ADMIN.php
2047
2048 /**
2049  * Returns a variable or null if not set
2050  *
2051  * @param mixed Variable
2052  * @return mixed Variable
2053  */
2054 function ifset(&$var) {
2055         if (isset($var)) {
2056                 return $var;
2057         }
2058
2059         return null;
2060 }
2061
2062 /**
2063  * Returns number of subscriber to an event
2064  *
2065  * @param event
2066  * @return number of subscriber(s)
2067  */
2068 function numberOfEventSubscriber($event) {
2069         $query = 'SELECT COUNT(*) as count FROM ' . sql_table('plugin_event') . ' WHERE event=\'' . $event . '\'';
2070         $res = sql_query($query);
2071         $obj = mysql_fetch_object($res);
2072         return $obj->count;
2073 }
2074
2075 ?>