| [ Index ] |
|
Code source de Serendipity 1.2 |
1 <?php # $Id: functions.inc.php 1721 2007-06-11 14:32:32Z garvinhicking $ 2 # Copyright (c) 2003-2005, Jannis Hermanns (on behalf the Serendipity Developer Team) 3 # All rights reserved. See LICENSE file for licensing details 4 5 if (IN_serendipity !== true) { 6 die ("Don't hack!"); 7 } 8 9 if (defined('S9Y_FRAMEWORK_FUNCTIONS')) { 10 return; 11 } 12 @define('S9Y_FRAMEWORK_FUNCTIONS', true); 13 14 $serendipity['imageList'] = array(); 15 if (!defined('S9Y_FRAMEWORK_DB')) { 16 include (S9Y_INCLUDE_PATH . "include/db/db.inc.php"); 17 } 18 if (!defined('S9Y_FRAMEWORK_COMPAT')) { 19 include (S9Y_INCLUDE_PATH . "include/compat.inc.php"); 20 } 21 if (!defined('S9Y_FRAMEWORK_CONFIG')) { 22 include (S9Y_INCLUDE_PATH . "include/functions_config.inc.php"); 23 } 24 if (!defined('S9Y_FRAMEWORK_PLUGIN_API')) { 25 include (S9Y_INCLUDE_PATH . "include/plugin_api.inc.php"); 26 } 27 if (!defined('S9Y_FRAMEWORK_IMAGES')) { 28 include (S9Y_INCLUDE_PATH . "include/functions_images.inc.php"); 29 } 30 if (!defined('S9Y_FRAMEWORK_INSTALLER')) { 31 include (S9Y_INCLUDE_PATH . "include/functions_installer.inc.php"); 32 } 33 if (!defined('S9Y_FRAMEWORK_ENTRIES')) { 34 include (S9Y_INCLUDE_PATH . "include/functions_entries.inc.php"); 35 } 36 if (!defined('S9Y_FRAMEWORK_COMMENTS')) { 37 include (S9Y_INCLUDE_PATH . "include/functions_comments.inc.php"); 38 } 39 if (!defined('S9Y_FRAMEWORK_PERMALINKS')) { 40 include (S9Y_INCLUDE_PATH . "include/functions_permalinks.inc.php"); 41 } 42 if (!defined('S9Y_FRAMEWORK_SMARTY')) { 43 include (S9Y_INCLUDE_PATH . "include/functions_smarty.inc.php"); 44 } 45 /** 46 * Truncate a string to a specific length, multibyte aware. Appends '...' if successfully truncated 47 * 48 * @access public 49 * @param string Input string 50 * @param int Length the final string should have 51 * @return string Truncated string 52 */ 53 function serendipity_truncateString($s, $len) { 54 if ( strlen($s) > ($len+3) ) { 55 $s = serendipity_mb('substr', $s, 0, $len) . '...'; 56 } 57 return $s; 58 } 59 60 /** 61 * Optionally turn on GZip Compression, if configured 62 * 63 * @access public 64 */ 65 function serendipity_gzCompression() { 66 global $serendipity; 67 if (isset($serendipity['useGzip']) && serendipity_db_bool($serendipity['useGzip']) && function_exists('ob_gzhandler') && extension_loaded('zlib') && serendipity_ini_bool(ini_get('zlib.output_compression')) == false && serendipity_ini_bool(ini_get('session.use_trans_sid')) == false) { 68 ob_start("ob_gzhandler"); 69 } 70 } 71 72 /** 73 * Returns a timestamp formatted according to the current Server timezone offset 74 * 75 * @access public 76 * @param int The timestamp you want to convert into the current server timezone. Defaults to "now". 77 * @param boolean A toggle to indicate, if the timezone offset should be ADDED or SUBSTRACTED from the timezone. Substracting is required to restore original time when posting an entry. 78 * @return int The final timestamp 79 */ 80 function serendipity_serverOffsetHour($timestamp = null, $negative = false) { 81 global $serendipity; 82 83 if ($timestamp == null) { 84 $timestamp = time(); 85 } 86 87 if (empty($serendipity['serverOffsetHours']) || !is_numeric($serendipity['serverOffsetHours']) || $serendipity['serverOffsetHours'] == 0) { 88 return $timestamp; 89 } else { 90 return $timestamp + (($negative ? -$serendipity['serverOffsetHours'] : $serendipity['serverOffsetHours']) * 60 * 60); 91 } 92 } 93 94 /* Converts a date string (DD.MM.YYYY, YYYY-MM-DD, MM/DD/YYYY) into a unix timestamp 95 * 96 * @access public 97 * @param string The input date 98 * @return int The output unix timestamp 99 */ 100 function &serendipity_convertToTimestamp($in) { 101 if (preg_match('@([0-9]+)([/\.-])([0-9]+)([/\.-])([0-9]+)@', $in, $m)) { 102 if ($m[2] != $m[4]) { 103 return $in; 104 } 105 106 switch($m[2]) { 107 case '.': 108 return mktime(0, 0, 0, /* month */ $m[3], /* day */ $m[1], /* year */ $m[5]); 109 break; 110 111 case '/': 112 return mktime(0, 0, 0, /* month */ $m[1], /* day */ $m[3], /* year */ $m[5]); 113 break; 114 115 case '-': 116 return mktime(0, 0, 0, /* month */ $m[3], /* day */ $m[5], /* year */ $m[1]); 117 break; 118 } 119 120 return $in; 121 } 122 123 return $in; 124 } 125 126 /** 127 * Format a timestamp 128 * 129 * This function can convert an input timestamp into specific PHP strftime() outputs, including applying necessary timezone calculations. 130 * 131 * @access public 132 * @param string Output format for the timestamp 133 * @param int Timestamp to use for displaying 134 * @param boolean Indicates, if timezone calculations shall be used. 135 * @param boolean Whether to use strftime or simply date 136 * @return string The formatted timestamp 137 */ 138 function serendipity_strftime($format, $timestamp = null, $useOffset = true, $useDate = false) { 139 global $serendipity; 140 static $is_win_utf = null; 141 142 if ($is_win_utf === null) { 143 // Windows does not have UTF-8 locales. 144 $is_win_utf = (LANG_CHARSET == 'UTF-8' && strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' ? true : false); 145 } 146 147 if ($useDate) { 148 $out = date($format, $timestamp); 149 } else { 150 switch($serendipity['calendar']) { 151 default: 152 case 'gregorian': 153 if ($timestamp == null) { 154 $timestamp = serendipity_serverOffsetHour(); 155 } elseif ($useOffset) { 156 $timestamp = serendipity_serverOffsetHour($timestamp); 157 } 158 $out = strftime($format, $timestamp); 159 break; 160 161 case 'persian-utf8': 162 if ($timestamp == null) { 163 $timestamp = serendipity_serverOffsetHour(); 164 } elseif ($useOffset) { 165 $timestamp = serendipity_serverOffsetHour($timestamp); 166 } 167 168 require_once S9Y_INCLUDE_PATH . 'include/functions_calendars.inc.php'; 169 $out = persian_strftime_utf($format, $timestamp); 170 break; 171 } 172 } 173 174 if ($is_win_utf && (empty($serendipity['calendar']) || $serendipity['calendar'] == 'gregorian')) { 175 $out = utf8_encode($out); 176 } 177 178 return $out; 179 } 180 181 /** 182 * A wrapper function call for formatting Timestamps. 183 * 184 * Utilizes serendipity_strftime() and prepares the output timestamp with a few tweaks, and applies automatic uppercasing of the return. 185 * 186 * @see serendipity_strftime() 187 * @param string Output format for the timestamp 188 * @param int Timestamp to use for displaying 189 * @param boolean Indicates, if timezone calculations shall be used. 190 * @param boolean Whether to use strftime or simply date 191 * @return string The formatted timestamp 192 */ 193 function serendipity_formatTime($format, $time, $useOffset = true, $useDate = false) { 194 static $cache; 195 if (!isset($cache)) { 196 $cache = array(); 197 } 198 199 if (!isset($cache[$format])) { 200 $cache[$format] = $format; 201 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { 202 $cache[$format] = str_replace('%e', '%d', $cache[$format]); 203 } 204 } 205 206 return serendipity_mb('ucfirst', serendipity_strftime($cache[$format], (int)$time, $useOffset, $useDate)); 207 } 208 209 /** 210 * Fetches the list of available templates/themes/styles. 211 * 212 * @access public 213 * @param string Directory to search for a template [recursive use] 214 * @return array Sorted array of available template names 215 */ 216 function serendipity_fetchTemplates($dir = '') { 217 global $serendipity; 218 219 $cdir = @opendir($serendipity['serendipityPath'] . $serendipity['templatePath'] . $dir); 220 $rv = array(); 221 if (!$cdir) { 222 return $rv; 223 } 224 while (($file = readdir($cdir)) !== false) { 225 if (is_dir($serendipity['serendipityPath'] . $serendipity['templatePath'] . $dir . $file) && !ereg('^(\.|CVS)', $file) && !file_exists($serendipity['serendipityPath'] . $serendipity['templatePath'] . $dir . $file . '/inactive.txt')) { 226 if (file_exists($serendipity['serendipityPath'] . $serendipity['templatePath'] . $dir . $file . '/info.txt')) { 227 $key = strtolower($file); 228 if (isset($rv[$key])) { 229 $key = $dir . $key; 230 } 231 $rv[$key] = $dir . $file; 232 } else { 233 $temp = serendipity_fetchTemplates($dir . $file . '/'); 234 if (count($temp) > 0) { 235 $rv = array_merge($rv, $temp); 236 } 237 } 238 } 239 } 240 closedir($cdir); 241 ksort($rv); 242 return $rv; 243 } 244 245 /** 246 * Get information about a specific theme/template/style 247 * 248 * @access public 249 * @param string Directory name of a theme 250 * @param string Absolute path to the templates [for use on CVS mounted directories] 251 * @return array Associative array if template information 252 */ 253 function serendipity_fetchTemplateInfo($theme, $abspath = null) { 254 global $serendipity; 255 256 if ($abspath === null) { 257 $abspath = $serendipity['serendipityPath'] . $serendipity['templatePath']; 258 } 259 260 $lines = @file($abspath . $theme . '/info.txt'); 261 if ( !$lines ) { 262 return array(); 263 } 264 265 for($x=0; $x<count($lines); $x++) { 266 $j = preg_split('/([^\:]+)\:/', $lines[$x], -1, PREG_SPLIT_DELIM_CAPTURE); 267 if ($j[2]) { 268 $currSec = $j[1]; 269 $data[strtolower($currSec)][] = trim($j[2]); 270 } else { 271 $data[strtolower($currSec)][] = trim($j[0]); 272 } 273 } 274 275 foreach ($data as $k => $v) { 276 $data[$k] = implode("\n", $v); 277 } 278 279 if ( $theme != 'default' && $theme != 'default-rtl' 280 && @is_dir($serendipity['templatePath'] . $theme . '/admin') 281 && @is_readable($serendipity['templatePath'] . $theme . '/admin/style.css') ) { 282 283 $data['custom_admin_interface'] = YES; 284 } else { 285 $data['custom_admin_interface'] = NO; 286 } 287 288 return $data; 289 } 290 291 /** 292 * Recursively walks an 1-dimensional array to map parent IDs and depths, depending on the nested array set. 293 * 294 * Used for sorting a list of comments, for example. The list of comment is iterated, and the nesting level is calculated, and the array will be sorted to represent the amount of nesting. 295 * 296 * @access public 297 * @param array Input array to investigate [consecutively sliced for recursive calls] 298 * @param string Array index name to indicate the ID value of an array index 299 * @param string Array index name to indicate the PARENT ID value of an array index, matched against the $child_name value 300 * @param int The parent id to check an element against for recursive nesting 301 * @param int The current depth of the cycled array 302 * @return array The sorted and shiny polished result array 303 */ 304 function serendipity_walkRecursive($ary, $child_name = 'id', $parent_name = 'parent_id', $parentid = 0, $depth = 0) { 305 global $serendipity; 306 static $_resArray; 307 static $_remain; 308 309 if (!is_array($ary) || sizeof($ary) == 0) { 310 return array(); 311 } 312 313 if ($parentid === VIEWMODE_THREADED) { 314 $parentid = 0; 315 } 316 317 if ($depth == 0) { 318 $_resArray = array(); 319 $_remain = $ary; 320 } 321 322 foreach($ary AS $key => $data) { 323 if ($parentid === VIEWMODE_LINEAR || !isset($data[$parent_name]) || $data[$parent_name] == $parentid) { 324 $data['depth'] = $depth; 325 $_resArray[] = $data; 326 unset($_remain[$key]); 327 if ($data[$child_name] && $parentid !== VIEWMODE_LINEAR ) { 328 serendipity_walkRecursive($ary, $child_name, $parent_name, $data[$child_name], ($depth+1)); 329 } 330 } 331 } 332 333 /* We are inside a recusive child, and we need to break out */ 334 if ($depth !== 0) { 335 return true; 336 } 337 338 if (count($_remain) > 0) { 339 // Remaining items need to be appended 340 foreach($_remain AS $key => $data) { 341 $data['depth'] = 0; 342 $_resArray[] = $data; 343 } 344 } 345 346 return $_resArray; 347 } 348 349 /** 350 * Fetch the list of Serendipity Authors 351 * 352 * @access public 353 * @param int Fetch only a specific User 354 * @param array Can contain an array of group IDs you only want to fetch authors of. 355 * @param boolean If set to TRUE, the amount of entries per author will also be returned 356 * @return array Result of the SQL query 357 */ 358 function serendipity_fetchUsers($user = '', $group = null, $is_count = false) { 359 global $serendipity; 360 361 $where = ''; 362 if (!empty($user)) { 363 $where = "WHERE a.authorid = '" . (int)$user ."'"; 364 } 365 366 $query_select = ''; 367 $query_join = ''; 368 $query_group = ''; 369 $query_distinct = ''; 370 if ($is_count) { 371 $query_select = ", count(e.authorid) as artcount"; 372 $query_join = "LEFT OUTER JOIN {$serendipity['dbPrefix']}entries AS e 373 ON a.authorid = e.authorid"; 374 } 375 376 if ($is_count || $group != null) { 377 if ($serendipity['dbType'] == 'postgres' || 378 $serendipity['dbType'] == 'pdo-postgres') { 379 // Why does PostgreSQL keep doing this to us? :-) 380 $query_group = 'GROUP BY a.authorid, a.realname, a.username, a.password, a.mail_comments, a.mail_trackbacks, a.email, a.userlevel, a.right_publish'; 381 $query_distinct = 'DISTINCT'; 382 } else { 383 $query_group = 'GROUP BY a.authorid'; 384 $query_distinct = ''; 385 } 386 } 387 388 389 if ($group === null) { 390 $querystring = "SELECT $query_distinct 391 a.authorid, 392 a.realname, 393 a.username, 394 a.password, 395 a.mail_comments, 396 a.mail_trackbacks, 397 a.email, 398 a.userlevel, 399 a.right_publish 400 $query_select 401 FROM {$serendipity['dbPrefix']}authors AS a 402 $query_join 403 $where 404 $query_group 405 ORDER BY a.realname ASC"; 406 } else { 407 if (is_array($group)) { 408 foreach($group AS $idx => $groupid) { 409 $group[$idx] = (int)$groupid; 410 } 411 $group_sql = implode(', ', $group); 412 } else { 413 $group_sql = (int)$group; 414 } 415 416 $querystring = "SELECT $query_distinct 417 a.authorid, 418 a.realname, 419 a.username, 420 a.password, 421 a.mail_comments, 422 a.mail_trackbacks, 423 a.email, 424 a.userlevel, 425 a.right_publish 426 $query_select 427 FROM {$serendipity['dbPrefix']}authors AS a 428 LEFT OUTER JOIN {$serendipity['dbPrefix']}authorgroups AS ag 429 ON a.authorid = ag.authorid 430 LEFT OUTER JOIN {$serendipity['dbPrefix']}groups AS g 431 ON ag.groupid = g.id 432 $query_join 433 WHERE g.id IN ($group_sql) 434 $where 435 $query_group 436 ORDER BY a.realname ASC"; 437 } 438 439 return serendipity_db_query($querystring); 440 } 441 442 443 /** 444 * Sends a Mail with Serendipity formatting 445 * 446 * @access public 447 * @param string The recipient address of the mail 448 * @param string The subject of the mail 449 * @param string The body of the mail 450 * @param string The sender mail address of the mail 451 * @param array additional headers to pass to the E-Mail 452 * @param string The name of the sender 453 * @return int Return code of the PHP mail() function 454 */ 455 function serendipity_sendMail($to, $subject, $message, $fromMail, $headers = NULL, $fromName = NULL) { 456 global $serendipity; 457 458 if (!is_null($headers) && !is_array($headers)) { 459 trigger_error(__FUNCTION__ . ': $headers must be either an array or null', E_USER_ERROR); 460 } 461 462 if (is_null($fromName) || empty($fromName)) { 463 $fromName = $serendipity['blogTitle']; 464 } 465 466 if (is_null($fromMail) || empty($fromMail)) { 467 $fromMail = $to; 468 } 469 470 if (is_null($headers)) { 471 $headers = array(); 472 } 473 474 // Fix special characters 475 $fromName = str_replace(array('"', "\r", "\n"), array("'", '', ''), $fromName); 476 $fromMail = str_replace(array("\r","\n"), array('', ''), $fromMail); 477 478 // Prefix all mail with weblog title 479 $subject = '['. $serendipity['blogTitle'] . '] '. $subject; 480 481 // Append signature to every mail 482 $message .= "\n" . sprintf(SIGNATURE, $serendipity['blogTitle']); 483 484 $maildata = array( 485 'to' => &$to, 486 'subject' => &$subject, 487 'fromName' => &$fromName, 488 'fromMail' => &$fromMail, 489 'blogMail' => $serendipity['blogMail'], 490 'version' => 'Serendipity/' . $serendipity['version'], 491 'legacy' => true, 492 'headers' => &$headers, 493 'message' => &$message 494 ); 495 496 serendipity_plugin_api::hook_event('backend_sendmail', $maildata, LANG_CHARSET); 497 498 // This routine can be overridden by a plugin. 499 if ($maildata['legacy']) { 500 // Check for mb_* function, and use it to encode headers etc. */ 501 if (function_exists('mb_encode_mimeheader')) { 502 // mb_encode_mimeheader function insertes linebreaks after 74 chars. 503 // Usually this is according to spec, but for us it caused more trouble than 504 // it prevented. 505 // Regards to Mark Kronsbein for finding this issue! 506 $maildata['subject'] = str_replace(array("\n", "\r"), array('', ''), mb_encode_mimeheader($maildata['subject'], LANG_CHARSET)); 507 $maildata['fromName'] = str_replace(array("\n", "\r"), array('', ''), mb_encode_mimeheader($maildata['fromName'], LANG_CHARSET)); 508 } 509 510 511 // Always add these headers 512 if (!empty($maildata['blogMail'])) { 513 $maildata['headers'][] = 'From: "'. $maildata['fromName'] .'" <'. $maildata['blogMail'] .'>'; 514 } 515 $maildata['headers'][] = 'Reply-To: "'. $maildata['fromName'] .'" <'. $maildata['fromMail'] .'>'; 516 $maildata['headers'][] = 'X-Mailer: ' . $maildata['version']; 517 $maildata['headers'][] = 'X-Engine: PHP/'. phpversion(); 518 $maildata['headers'][] = 'Message-ID: <'. md5(microtime() . uniqid(time())) .'@'. $_SERVER['HTTP_HOST'] .'>'; 519 $maildata['headers'][] = 'MIME-Version: 1.0'; 520 $maildata['headers'][] = 'Precedence: bulk'; 521 $maildata['headers'][] = 'Content-Type: text/plain; charset=' . LANG_CHARSET; 522 523 if (LANG_CHARSET == 'UTF-8') { 524 if (function_exists('imap_8bit')) { 525 $maildata['headers'][] = 'Content-Transfer-Encoding: quoted-printable'; 526 $maildata['message'] = str_replace("=\r\n", "", imap_8bit($maildata['message'])); 527 } else { 528 $maildata['headers'][] = 'Content-Transfer-Encoding: base64'; 529 $maildata['message'] = chunk_split(base64_encode($maildata['message'])); 530 } 531 } 532 } 533 534 return mail($maildata['to'], $maildata['subject'], $maildata['message'], implode("\n", $maildata['headers'])); 535 } 536 537 /** 538 * Fetch all references (links) from a given entry ID 539 * 540 * @access public 541 * @param int The entry ID 542 * @return array The SQL result containing the references/links of an entry 543 */ 544 function serendipity_fetchReferences($id) { 545 global $serendipity; 546 547 $query = "SELECT name,link FROM {$serendipity['dbPrefix']}references WHERE entry_id = '" . (int)$id . "' AND type = ''"; 548 549 return serendipity_db_query($query); 550 } 551 552 553 /** 554 * Encode a string to UTF-8, if not already in UTF-8 format. 555 * 556 * @access public 557 * @param string The input string 558 * @return string The output string 559 */ 560 function serendipity_utf8_encode($string) { 561 if (strtolower(LANG_CHARSET) != 'utf-8') { 562 if (function_exists('iconv')) { 563 $new = iconv(LANG_CHARSET, 'UTF-8', $string); 564 if ($new !== false) { 565 return $new; 566 } else { 567 return utf8_encode($string); 568 } 569 } else if (function_exists('mb_convert_encoding')) { 570 return mb_convert_encoding($string, 'UTF-8', LANG_CHARSET); 571 } else { 572 return utf8_encode($string); 573 } 574 } else { 575 return $string; 576 } 577 } 578 579 /** 580 * Create a link that can be used within a RSS feed to indicate a permalink for an entry or comment 581 * 582 * @access public 583 * @param array The input entry array 584 * @param boolean Toggle whether the link will be for a COMMENT [true] or an ENTRY [false] 585 * @return string A permalink for the given entry 586 */ 587 function serendipity_rss_getguid($entry, $comments = false) { 588 global $serendipity; 589 590 $id = (isset($entry['entryid']) && $entry['entryid'] != '' ? $entry['entryid'] : $entry['id']); 591 592 // When using %id%, we can make the GUID shorter and independent from the title. 593 // If not using %id%, the entryid needs to be used for uniqueness. 594 if (stristr($serendipity['permalinkStructure'], '%id%') !== FALSE) { 595 $title = 'guid'; 596 } else { 597 $title = $id; 598 } 599 600 $guid = serendipity_archiveURL( 601 $id, 602 $title, 603 'baseURL', 604 true, 605 array('timestamp' => $entry['timestamp']) 606 ); 607 608 if ($comments == true) { 609 $guid .= '#c' . $entry['commentid']; 610 } 611 612 return $guid; 613 } 614 615 /** 616 * Perform some replacement calls to make valid XHTML content 617 * 618 * jbalcorn: starter function to clean up xhtml for atom feed. Add things to this as we find common 619 * mistakes, unless someone finds a better way to do this. 620 * DONE: 621 * since someone encoded all the urls, we can now assume any amp followed by 622 * whitespace or a HTML tag (i.e. &<br /> )should be 623 * encoded and most not with a space are intentional 624 * 625 * @access public 626 * @param string Input HTML code 627 * @return string Cleaned HTML code 628 */ 629 function xhtml_cleanup($html) { 630 static $p = array( 631 '/\&([\s\<])/', // ampersand followed by whitespace or tag 632 '/\&$/', // ampersand at end of body 633 '/<(br|hr|img)([^\/>]*)>/i', // unclosed br tag - attributes included 634 '/\ /' // Protect whitespace 635 ); 636 637 static $r = array( 638 '&\1', 639 '&', 640 '<\1\2 />', 641 ' ' 642 ); 643 644 return preg_replace($p, $r, $html); 645 } 646 647 /** 648 * Fetch user data for a specific Serendipity author 649 * 650 * @access public 651 * @param int The requested author id 652 * @return array The SQL result array 653 */ 654 function serendipity_fetchAuthor($author) { 655 global $serendipity; 656 657 return serendipity_db_query("SELECT * FROM {$serendipity['dbPrefix']}authors WHERE " . (is_numeric($author) ? "authorid={$author};" : "username='" . serendipity_db_escape_string($author) . "';")); 658 } 659 660 /** 661 * Split a filename into basename and extension parts 662 * 663 * @access public 664 * @param string Filename 665 * @return array Return array containing the basename and file extension 666 */ 667 function serendipity_parseFileName($file) { 668 $x = explode('.', $file); 669 $suf = array_pop($x); 670 $f = @implode('.', $x); 671 return array($f, $suf); 672 } 673 674 /** 675 * Track the referer to a specific Entry ID 676 * 677 * @access public 678 * @param int Entry ID 679 * @return null 680 */ 681 function serendipity_track_referrer($entry = 0) { 682 global $serendipity; 683 684 // Tracking disabled. 685 if ($serendipity['trackReferrer'] === false) { 686 return; 687 } 688 689 if (isset($_SERVER['HTTP_REFERER'])) { 690 if (stristr($_SERVER['HTTP_REFERER'], $serendipity['baseURL']) !== false) { 691 return; 692 } 693 694 if (!isset($serendipity['_blockReferer']) || !is_array($serendipity['_blockReferer'])) { 695 // Only generate an array once per call 696 $serendipity['_blockReferer'] = array(); 697 $serendipity['_blockReferer'] = @explode(';', $serendipity['blockReferer']); 698 } 699 700 $url_parts = parse_url($_SERVER['HTTP_REFERER']); 701 $host_parts = explode('.', $url_parts['host']); 702 if (!$url_parts['host'] || 703 strstr($url_parts['host'], $_SERVER['SERVER_NAME'])) { 704 return; 705 } 706 707 foreach($serendipity['_blockReferer'] AS $idx => $hostname) { 708 if (@strstr($url_parts['host'], $hostname)) { 709 return; 710 } 711 } 712 713 if (rand(0, 100) < 1) { 714 serendipity_track_referrer_gc(); 715 } 716 717 $ts = serendipity_db_get_interval('ts'); 718 $interval = serendipity_db_get_interval('interval', 900); 719 720 $suppressq = "SELECT count(1) 721 FROM $serendipity[dbPrefix]suppress 722 WHERE ip = '" . serendipity_db_escape_string($_SERVER['REMOTE_ADDR']) . "' 723 AND scheme = '" . serendipity_db_escape_string($url_parts['scheme']) . "' 724 AND port = '" . serendipity_db_escape_string($url_parts['port']) . "' 725 AND host = '" . serendipity_db_escape_string($url_parts['host']) . "' 726 AND path = '" . serendipity_db_escape_string($url_parts['path']) . "' 727 AND query = '" . serendipity_db_escape_string($url_parts['query']) . "' 728 AND last > $ts - $interval"; 729 730 $suppressp = "DELETE FROM $serendipity[dbPrefix]suppress 731 WHERE ip = '" . serendipity_db_escape_string($_SERVER['REMOTE_ADDR']) . "' 732 AND scheme = '" . serendipity_db_escape_string($url_parts['scheme']) . "' 733 AND host = '" . serendipity_db_escape_string($url_parts['host']) . "' 734 AND port = '" . serendipity_db_escape_string($url_parts['port']) . "' 735 AND query = '" . serendipity_db_escape_string($url_parts['query']) . "' 736 AND path = '" . serendipity_db_escape_string($url_parts['path']) . "'"; 737 $suppressu = "INSERT INTO $serendipity[dbPrefix]suppress 738 (ip, last, scheme, host, port, path, query) 739 VALUES ( 740 '" . serendipity_db_escape_string($_SERVER['REMOTE_ADDR']) . "', 741 $ts, 742 '" . serendipity_db_escape_string($url_parts['scheme']) . "', 743 '" . serendipity_db_escape_string($url_parts['host']) . "', 744 '" . serendipity_db_escape_string($url_parts['port']) . "', 745 '" . serendipity_db_escape_string($url_parts['path']) . "', 746 '" . serendipity_db_escape_string($url_parts['query']) . "' 747 )"; 748 749 $count = serendipity_db_query($suppressq, true); 750 751 if ($count[0] == 0) { 752 serendipity_db_query($suppressu); 753 return; 754 } 755 756 serendipity_db_query($suppressp); 757 serendipity_db_query($suppressu); 758 759 serendipity_track_url('referrers', $_SERVER['HTTP_REFERER'], $entry); 760 } 761 } 762 763 /** 764 * Garbage Collection for suppressed referrers 765 * 766 * "Bad" referrers, that only occured once to your entry are put within a 767 * SUPPRESS database table. Entries contained there will be cleaned up eventually. 768 * 769 * @access public 770 * @return null 771 */ 772 function serendipity_track_referrer_gc() { 773 global $serendipity; 774 775 $ts = serendipity_db_get_interval('ts'); 776 $interval = serendipity_db_get_interval('interval', 900); 777 $gc = "DELETE FROM $serendipity[dbPrefix]suppress WHERE last <= $ts - $interval"; 778 serendipity_db_query($gc); 779 } 780 781 /** 782 * Track a URL used in your Blog (Exit-Tracking) 783 * 784 * @access public 785 * @param string Name of the DB table where to store the link (exits|referrers) 786 * @param string The URL to track 787 * @param int The Entry ID to relate the track to 788 * @return null 789 */ 790 function serendipity_track_url($list, $url, $entry_id = 0) { 791 global $serendipity; 792 793 $url_parts = parse_url($url); 794 795 serendipity_db_query( 796 @sprintf( 797 "UPDATE %s%s 798 SET count = count + 1 799 WHERE scheme = '%s' 800 AND host = '%s' 801 AND port = '%s' 802 AND path = '%s' 803 AND query = '%s' 804 AND day = '%s' 805 %s", 806 807 $serendipity['dbPrefix'], 808 $list, 809 serendipity_db_escape_string($url_parts['scheme']), 810 serendipity_db_escape_string($url_parts['host']), 811 serendipity_db_escape_string($url_parts['port']), 812 serendipity_db_escape_string($url_parts['path']), 813 serendipity_db_escape_string($url_parts['query']), 814 date('Y-m-d'), 815 ($entry_id != 0) ? "AND entry_id = '". (int)$entry_id ."'" : '' 816 ) 817 ); 818 819 if (serendipity_db_affected_rows() == 0) { 820 serendipity_db_query( 821 sprintf( 822 "INSERT INTO %s%s 823 (entry_id, day, count, scheme, host, port, path, query) 824 VALUES (%d, '%s', 1, '%s', '%s', '%s', '%s', '%s')", 825 826 $serendipity['dbPrefix'], 827 $list, 828 (int)$entry_id, 829 date('Y-m-d'), 830 serendipity_db_escape_string($url_parts['scheme']), 831 serendipity_db_escape_string($url_parts['host']), 832 serendipity_db_escape_string($url_parts['port']), 833 serendipity_db_escape_string($url_parts['path']), 834 serendipity_db_escape_string($url_parts['query']) 835 ) 836 ); 837 } 838 } 839 840 /** 841 * Display the list of top referrers 842 * 843 * @access public 844 * @see serendipity_displayTopUrlList() 845 * @param int Number of referrers to show 846 * @param boolean Whether to use HTML links for URLs 847 * @param int Interval for which the top referrers are aggregated 848 * @return string List of Top referrers 849 */ 850 function serendipity_displayTopReferrers($limit = 10, $use_links = true, $interval = 7) { 851 serendipity_displayTopUrlList('referrers', $limit, $use_links, $interval); 852 } 853 854 /** 855 * Display the list of top exits 856 * 857 * @access public 858 * @see serendipity_displayTopUrlList() 859 * @param int Number of exits to show 860 * @param boolean Whether to use HTML links for URLs 861 * @param int Interval for which the top exits are aggregated 862 * @return string List of Top exits 863 */ 864 function serendipity_displayTopExits($limit = 10, $use_links = true, $interval = 7) { 865 serendipity_displayTopUrlList('exits', $limit, $use_links, $interval); 866 } 867 868 /** 869 * Display HTML output data of a Exit/Referrer list 870 * 871 * @access public 872 * @see serendipity_displayTopExits() 873 * @see serendipity_displayTopReferrers() 874 * @param string Name of the DB table to show data from (exits|referrers) 875 * @param boolean Whether to use HTML links for URLs 876 * @param int Interval for which the top exits are aggregated 877 * @return 878 */ 879 function serendipity_displayTopUrlList($list, $limit, $use_links = true, $interval = 7) { 880 global $serendipity; 881 882 if ($limit){ 883 $limit = serendipity_db_limit_sql($limit); 884 } 885 886 /* HACK */ 887 if (preg_match('/^mysqli?/', $serendipity['dbType'])) { 888 /* Nonportable SQL due to MySQL date functions, 889 * but produces rolling 7 day totals, which is more 890 * interesting 891 */ 892 $query = "SELECT scheme, host, SUM(count) AS total 893 FROM {$serendipity['dbPrefix']}$list 894 WHERE day > date_sub(current_date, interval " . (int)$interval . " day) 895 GROUP BY host 896 ORDER BY total DESC, host 897 $limit"; 898 } else { 899 /* Portable version of the same query */ 900 $query = "SELECT scheme, host, SUM(count) AS total 901 FROM {$serendipity['dbPrefix']}$list 902 GROUP BY scheme, host 903 ORDER BY total DESC, host 904 $limit"; 905 } 906 907 $rows = serendipity_db_query($query); 908 echo "<span class='serendipityReferer'>"; 909 if (is_array($rows)) { 910 foreach ($rows as $row) { 911 if ($use_links) { 912 printf( 913 '<a href="%1$s://%2$s" title="%2$s" >%2$s</a> (%3$s)<br />', 914 $row['scheme'], 915 $row['host'], 916 $row['total'] 917 ); 918 } else { 919 printf( 920 '%1$s (%2$s)<br />', 921 $row['host'], 922 $row['total'] 923 ); 924 } 925 } 926 } 927 echo "</span>"; 928 } 929 930 /** 931 * Return either HTML or XHTML code for an '<a target...> attribute. 932 * 933 * @access public 934 * @param string The target to use (_blank, _parent, ...) 935 * @return string HTML string containig the valid markup for the target attribute. 936 */ 937 function serendipity_xhtml_target($target) { 938 global $serendipity; 939 940 if ($serendipity['enablePopup'] != true) 941 return ""; 942 943 return ' onclick="window.open(this.href, \'target' . time() . '\'); return false;" '; 944 } 945 946 /** 947 * Parse a URI portion to return which RSS Feed version was requested 948 * 949 * @access public 950 * @param string Name of the core URI part 951 * @param string File extension name of the URI 952 * @return string RSS feed type/version 953 */ 954 function serendipity_discover_rss($name, $ext) { 955 static $default = '2.0'; 956 957 /* Detect type */ 958 if ($name == 'comments') { 959 $type = 'comments'; 960 } elseif ($name == 'comments_and_trackbacks') { 961 $type = 'comments_and_trackbacks'; 962 } elseif ($name == 'trackbacks') { 963 $type = 'trackbacks'; 964 } else { 965 $type = 'content'; 966 } 967 968 /* Detect version */ 969 if ($name == 'atom' || $name == 'atom10' || $ext == 'atom') { 970 $ver = 'atom1.0'; 971 } elseif ($name == 'atom03') { 972 $ver = 'atom0.3'; 973 } elseif ($name == 'opml' || $ext == 'opml') { 974 $ver = 'opml1.0'; 975 } elseif ($ext == 'rss') { 976 $ver = '0.91'; 977 } elseif ($ext == 'rss1') { 978 $ver = '1.0'; 979 } else { 980 $ver = $default; 981 } 982 983 return array($ver, $type); 984 } 985 986 /** 987 * Check whether an input string contains "evil" characters used for HTTP Response Splitting 988 * 989 * @access public 990 * @param string String to check for evil characters 991 * @return boolean Return true on success, false on failure 992 */ 993 function serendipity_isResponseClean($d) { 994 return (strpos($d, "\r") === false && strpos($d, "\n") === false); 995 } 996 997 /** 998 * Create a new Category 999 * 1000 * @access public 1001 * @param string The new category name 1002 * @param string The new category description 1003 * @param int The category owner 1004 * @param string An icon representing the category 1005 * @param int A possible parentid to a category 1006 * @return int The new category's ID 1007 */ 1008 function serendipity_addCategory($name, $desc, $authorid, $icon, $parentid) { 1009 global $serendipity; 1010 $query = "INSERT INTO {$serendipity['dbPrefix']}category 1011 (category_name, category_description, authorid, category_icon, parentid, category_left, category_right) 1012 VALUES 1013 ('". serendipity_db_escape_string($name) ."', 1014 '". serendipity_db_escape_string($desc) ."', 1015 ". (int)$authorid .", 1016 '". serendipity_db_escape_string($icon) ."', 1017 ". (int)$parentid .", 1018 0, 1019 0)"; 1020 1021 serendipity_db_query($query); 1022 $cid = serendipity_db_insert_id('category', 'categoryid'); 1023 serendipity_plugin_api::hook_event('backend_category_addNew', $cid); 1024 1025 $data = array( 1026 'categoryid' => $cid, 1027 'category_name' => $name, 1028 'category_description' => $desc 1029 ); 1030 1031 serendipity_insertPermalink($data, 'category'); 1032 return $cid; 1033 } 1034 1035 /** 1036 * Update an existing category 1037 * 1038 * @access public 1039 * @param int Category ID to update 1040 * @param string The new category name 1041 * @param string The new category description 1042 * @param int The new category owner 1043 * @param string The new category icon 1044 * @param int The new category parent ID 1045 * @param int The new category sort order 1046 * @param int The new category subcat hiding 1047 * @return null 1048 */ 1049 function serendipity_updateCategory($cid, $name, $desc, $authorid, $icon, $parentid, $sort_order = 0, $hide_sub = 0) { 1050 global $serendipity; 1051 1052 $query = "UPDATE {$serendipity['dbPrefix']}category 1053 SET category_name = '". serendipity_db_escape_string($name) ."', 1054 category_description = '". serendipity_db_escape_string($desc) ."', 1055 authorid = ". (int)$authorid .", 1056 category_icon = '". serendipity_db_escape_string($icon) ."', 1057 parentid = ". (int)$parentid .", 1058 sort_order = ". (int)$sort_order . ", 1059 hide_sub = ". (int)$hide_sub . " 1060 WHERE categoryid = ". (int)$cid ." 1061 $admin_category"; 1062 serendipity_db_query($query); 1063 serendipity_plugin_api::hook_event('backend_category_update', $cid); 1064 1065 $data = array( 1066 'id' => $cid, 1067 'categoryid' => $cid, 1068 'category_name' => $name, 1069 'category_description' => $desc 1070 ); 1071 1072 serendipity_updatePermalink($data, 'category'); 1073 } 1074 1075 /** 1076 * Ends a session, so that while a file requests happens, Serendipity can work on in that session 1077 */ 1078 function serendipity_request_start() { 1079 @session_write_close(); 1080 return true; 1081 } 1082 1083 /** 1084 * Continues a session after a file request 1085 */ 1086 function serendipity_request_end() { 1087 @session_start(); 1088 return true; 1089 } 1090 1091 if (!function_exists('microtime_float')) { 1092 /** 1093 * Get current timestamp as microseconds 1094 * 1095 * @access public 1096 * @return float the time 1097 */ 1098 function microtime_float() { 1099 list($usec, $sec) = explode(" ", microtime()); 1100 return ((float)$usec + (float)$sec); 1101 } 1102 } 1103 1104 /** 1105 * Converts Array data to be used as a GET string 1106 * 1107 * @access public 1108 * @param array The input array 1109 * @param string An array prefix 1110 * @param string How to join the array 1111 * @return string The HTTP query string 1112 */ 1113 function serendipity_build_query(&$array, $array_prefix = null, $comb_char = '&') { 1114 $ret = array(); 1115 if (!is_array($array)) { 1116 return ''; 1117 } 1118 1119 foreach ($array as $k => $v) { 1120 $newkey = urlencode($k); 1121 if ($array_prefix) { 1122 $newkey = $array_prefix . '[' . $newkey . ']'; 1123 } 1124 if (is_array($v)) { 1125 $ret[] = serendipity_build_query($v, $newkey, $comb_char); 1126 } else { 1127 $ret[] = $newkey . '=' . urlencode($v); 1128 } 1129 } 1130 1131 return implode($comb_char, $ret); 1132 } 1133 1134 /* Picks a specified key from an array and returns it 1135 * 1136 * @access public 1137 * @param array The input array 1138 * @param string The key to search for 1139 * @param string The default value to return when not found 1140 * @return null 1141 */ 1142 function &serendipity_pickKey(&$array, $key, $default) { 1143 if (!is_array($array)) { 1144 return $default; 1145 } 1146 1147 foreach($array AS $child) { 1148 if (is_array($child) && isset($child[$key]) && !empty($child[$key])) { 1149 return $child[$key]; 1150 } 1151 } 1152 1153 return $default; 1154 } 1155 1156 /* Retrieves the current timestamp but only deals with minutes to optimize Database caching 1157 * @access public 1158 * @return timestamp 1159 * @author Matthew Groeninger 1160 */ 1161 function serendipity_db_time() { 1162 static $ts = null; 1163 static $cache = 300; // Seconds to cache 1164 1165 if ($ts === null) { 1166 $now = time(); 1167 $ts = $now - ($now % $cache) + $cache; 1168 } 1169 1170 return $ts; 1171 } 1172 1173 define("serendipity_FUNCTIONS_LOADED", true); 1174 /* vim: set sts=4 ts=4 expandtab : */
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sat Nov 24 09:00:37 2007 | par Balluche grâce à PHPXref 0.7 |
|