[ Index ] |
PHP Cross Reference of Textpattern 4.0.8 |
[Summary view] [Print] [Text view]
1 <?php 2 /* 3 _______________________________________ 4 ________| |_________ 5 \ | | / 6 \ | Textpattern | / 7 \ | | / 8 / |_______________________________________| \ 9 /___________) (___________\ 10 11 Copyright 2005 by Dean Allen 12 All rights reserved. 13 14 Use of this software denotes acceptance of the Textpattern license agreement 15 16 $HeadURL: https://textpattern.googlecode.com/svn/releases/4.0.8/source/textpattern/publish.php $ 17 $LastChangedRevision: 3050 $ 18 19 */ 20 21 if (!defined('txpath')) 22 define("txpath", dirname(__FILE__)); 23 if (!defined("txpinterface")) 24 die('If you just updated and expect to see your site here, please also update the files in your main installation directory.'. 25 ' (Otherwise note that publish.php cannot be called directly.)'); 26 27 28 include_once txpath.'/lib/constants.php'; 29 include_once txpath.'/lib/txplib_misc.php'; 30 include_once txpath.'/lib/txplib_db.php'; 31 include_once txpath.'/lib/txplib_html.php'; 32 include_once txpath.'/lib/txplib_forms.php'; 33 include_once txpath.'/lib/admin_config.php'; 34 35 include_once txpath.'/publish/taghandlers.php'; 36 include_once txpath.'/publish/log.php'; 37 include_once txpath.'/publish/comment.php'; 38 39 // set_error_handler('myErrorHandler'); 40 41 ob_start(); 42 43 // start the clock for runtime 44 $microstart = getmicrotime(); 45 46 // initialize parse trace globals 47 $txptrace = array(); 48 $txptracelevel = ''; 49 $txp_current_tag = ''; 50 51 // get all prefs as an array 52 $prefs = get_prefs(); 53 54 // add prefs to globals 55 extract($prefs); 56 57 // check the size of the url request 58 bombShelter(); 59 60 // set a higher error level during initialization 61 set_error_level(@$production_status == 'live' ? 'testing' : @$production_status); 62 63 // use the current URL path if $siteurl is unknown 64 if (empty($siteurl)) 65 $prefs['siteurl'] = $siteurl = $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['SCRIPT_NAME']), '/'); 66 67 if (empty($path_to_site)) 68 updateSitePath(dirname(dirname(__FILE__))); 69 70 if (!defined('PROTOCOL')) { 71 switch (serverSet('HTTPS')) { 72 case '': 73 case 'off': // ISAPI with IIS 74 define('PROTOCOL', 'http://'); 75 break; 76 77 default: 78 define('PROTOCOL', 'https://'); 79 break; 80 } 81 } 82 83 // v1.0: this should be the definitive http address of the site 84 if (!defined('hu')) 85 define("hu",PROTOCOL.$siteurl.'/'); 86 87 // v1.0 experimental relative url global 88 if (!defined('rhu')) 89 define("rhu",preg_replace("|^https?://[^/]+|","",hu)); 90 91 // 1.0: a new $here variable in the top-level index.php 92 // should let us know the server path to the live site 93 // let's save it to prefs 94 if (isset($here) and $path_to_site != $here) updateSitePath($here); 95 96 // 1.0 removed $doc_root variable from config, but we'll 97 // leave it here for a bit until plugins catch up 98 $txpcfg['doc_root'] = @$_SERVER['DOCUMENT_ROOT']; 99 // work around the IIS lobotomy 100 if (empty($txpcfg['doc_root'])) 101 $txpcfg['doc_root'] = @$_SERVER['PATH_TRANSLATED']; 102 103 if (!defined('LANG')) 104 define("LANG",$language); 105 if (!empty($locale)) setlocale(LC_ALL, $locale); 106 107 //Initialize the current user 108 $txp_user = NULL; 109 110 //i18n: $textarray = load_lang('en-gb'); 111 $textarray = load_lang(LANG); 112 113 // here come the plugins 114 if ($use_plugins) load_plugins(); 115 116 // this step deprecated as of 1.0 : really only useful with old-style 117 // section placeholders, which passed $s='section_name' 118 $s = (empty($s)) ? '' : $s; 119 120 $pretext = !isset($pretext) ? array() : $pretext; 121 $pretext = array_merge($pretext, pretext($s,$prefs)); 122 callback_event('pretext_end'); 123 extract($pretext); 124 125 // Now that everything is initialized, we can crank down error reporting 126 set_error_level($production_status); 127 128 if (gps('parentid') && gps('submit')) { 129 saveComment(); 130 } elseif (gps('parentid') and $comments_mode==1) { // popup comments? 131 header("Content-type: text/html; charset=utf-8"); 132 exit(popComments(gps('parentid'))); 133 } 134 135 // we are dealing with a download 136 if (@$s == 'file_download') { 137 callback_event('file_download'); 138 if (!isset($file_error)) { 139 140 $fullpath = build_file_path($file_base_path,$filename); 141 142 if (is_file($fullpath)) { 143 144 // discard any error php messages 145 ob_clean(); 146 $filesize = filesize($fullpath); $sent = 0; 147 header('Content-Description: File Download'); 148 header('Content-Type: application/octet-stream'); 149 header('Content-Disposition: attachment; filename="' . basename($filename) . '"; size = "'.$filesize.'"'); 150 // Fix for lame IE 6 pdf bug on servers configured to send cache headers 151 header('Cache-Control: private'); 152 @ini_set("zlib.output_compression", "Off"); 153 @set_time_limit(0); 154 @ignore_user_abort(true); 155 if ($file = fopen($fullpath, 'rb')) { 156 while(!feof($file) and (connection_status()==0)) { 157 echo fread($file, 1024*64); $sent+=(1024*64); 158 ob_flush(); 159 flush(); 160 } 161 fclose($file); 162 // record download 163 if ((connection_status()==0) and !connection_aborted() ) { 164 safe_update("txp_file", "downloads=downloads+1", 'id='.intval($id)); 165 log_hit('200'); 166 } else { 167 $pretext['request_uri'] .= ($sent >= $filesize) 168 ? '#aborted' 169 : "#aborted-at-".floor($sent*100/$filesize)."%"; 170 log_hit('200'); 171 } 172 } 173 } else { 174 $file_error = 404; 175 } 176 } 177 178 // deal with error 179 if (isset($file_error)) { 180 switch($file_error) { 181 case 403: 182 txp_die(gTxt('403_forbidden'), '403'); 183 break; 184 case 404: 185 txp_die(gTxt('404_not_found'), '404'); 186 break; 187 default: 188 txp_die(gTxt('500_internal_server_error'), '500'); 189 break; 190 } 191 } 192 193 // download done 194 exit(0); 195 } 196 197 198 // send 304 Not Modified if appropriate 199 handle_lastmod(); 200 201 // log the page view 202 log_hit($status); 203 204 205 // ------------------------------------------------------------- 206 function preText($s,$prefs) 207 { 208 extract($prefs); 209 210 callback_event('pretext'); 211 212 if(gps('rss')) { 213 include txpath.'/publish/rss.php'; 214 exit(rss()); 215 } 216 217 if(gps('atom')) { 218 include txpath.'/publish/atom.php'; 219 exit(atom()); 220 } 221 // set messy variables 222 $out = makeOut('id','s','c','q','pg','p','month','author'); 223 224 // some useful vars for taghandlers, plugins 225 $out['request_uri'] = preg_replace("|^https?://[^/]+|i","",serverSet('REQUEST_URI')); 226 $out['qs'] = serverSet('QUERY_STRING'); 227 // IIS fix 228 if (!$out['request_uri'] and serverSet('SCRIPT_NAME')) 229 $out['request_uri'] = serverSet('SCRIPT_NAME').( (serverSet('QUERY_STRING')) ? '?'.serverSet('QUERY_STRING') : ''); 230 // another IIS fix 231 if (!$out['request_uri'] and serverSet('argv')) 232 { 233 $argv = serverSet('argv'); 234 $out['request_uri'] = @substr($argv[0], strpos($argv[0], ';') + 1); 235 } 236 237 // define the useable url, minus any subdirectories. 238 // this is pretty fugly, if anyone wants to have a go at it - dean 239 $out['subpath'] = $subpath = preg_quote(preg_replace("/https?:\/\/.*(\/.*)/Ui","$1",hu),"/"); 240 $out['req'] = $req = preg_replace("/^$subpath/i","/",$out['request_uri']); 241 242 $is_404 = 0; 243 244 // if messy vars exist, bypass url parsing 245 if (!$out['id'] && !$out['s'] && !(txpinterface=='css') &&! ( txpinterface=='admin') ) { 246 247 // return clean URL test results for diagnostics 248 if (gps('txpcleantest')) { 249 exit(show_clean_test($out)); 250 } 251 252 extract(chopUrl($req)); 253 254 //first we sniff out some of the preset url schemes 255 if (strlen($u1)) { 256 257 switch($u1) { 258 259 case 'atom': 260 include txpath.'/publish/atom.php'; exit(atom()); 261 262 case 'rss': 263 include txpath.'/publish/rss.php'; exit(rss()); 264 265 // urldecode(strtolower(urlencode())) looks ugly but is the only way to 266 // make it multibyte-safe without breaking backwards-compatibility 267 case urldecode(strtolower(urlencode(gTxt('section')))): 268 $out['s'] = (ckEx('section',$u2)) ? $u2 : ''; $is_404 = empty($out['s']); break; 269 270 case urldecode(strtolower(urlencode(gTxt('category')))): 271 $out['c'] = (ckEx('category',$u2)) ? $u2 : ''; $is_404 = empty($out['c']); break; 272 273 case urldecode(strtolower(urlencode(gTxt('author')))): 274 $out['author'] = (!empty($u2)) ? $u2 : ''; break; 275 // AuthorID gets resolved from Name further down 276 277 case urldecode(strtolower(urlencode(gTxt('file_download')))): 278 $out['s'] = 'file_download'; 279 $out['id'] = (!empty($u2)) ? $u2 : ''; break; 280 281 default: 282 // then see if the prefs-defined permlink scheme is usable 283 switch ($permlink_mode) { 284 285 case 'section_id_title': 286 if (empty($u2)) { 287 $out['s'] = (ckEx('section',$u1)) ? $u1 : ''; 288 $is_404 = empty($out['s']); 289 } 290 else { 291 $rs = lookupByIDSection($u2, $u1); 292 $out['s'] = @$rs['Section']; 293 $out['id'] = @$rs['ID']; 294 $is_404 = (empty($out['s']) or empty($out['id'])); 295 } 296 break; 297 298 case 'year_month_day_title': 299 if (empty($u2)) { 300 $out['s'] = (ckEx('section',$u1)) ? $u1 : ''; 301 $is_404 = empty($out['s']); 302 } 303 elseif (empty($u4)){ 304 $month = "$u1-$u2"; 305 if (!empty($u3)) $month.= "-$u3"; 306 if (preg_match('/\d+-\d+(?:-\d+)?/', $month)) { 307 $out['month'] = $month; 308 $out['s'] = 'default'; 309 } 310 else { 311 $is_404 = 1; 312 } 313 }else{ 314 $when = "$u1-$u2-$u3"; 315 $rs = lookupByDateTitle($when,$u4); 316 $out['id'] = (!empty($rs['ID'])) ? $rs['ID'] : ''; 317 $out['s'] = (!empty($rs['Section'])) ? $rs['Section'] : ''; 318 $is_404 = (empty($out['s']) or empty($out['id'])); 319 } 320 break; 321 322 case 'section_title': 323 if (empty($u2)) { 324 $out['s'] = (ckEx('section',$u1)) ? $u1 : ''; 325 $is_404 = empty($out['s']); 326 } 327 else { 328 $rs = lookupByTitleSection($u2,$u1); 329 $out['id'] = @$rs['ID']; 330 $out['s'] = @$rs['Section']; 331 $is_404 = (empty($out['s']) or empty($out['id'])); 332 } 333 break; 334 335 case 'title_only': 336 $rs = lookupByTitle($u1); 337 $out['id'] = @$rs['ID']; 338 $out['s'] = (empty($rs['Section']) ? ckEx('section', $u1) : 339 $rs['Section']); 340 $is_404 = empty($out['s']); 341 break; 342 343 case 'id_title': 344 if (is_numeric($u1) && ckExID($u1)) 345 { 346 $rs = lookupByID($u1); 347 $out['id'] = (!empty($rs['ID'])) ? $rs['ID'] : ''; 348 $out['s'] = (!empty($rs['Section'])) ? $rs['Section'] : ''; 349 $is_404 = (empty($out['s']) or empty($out['id'])); 350 }else{ 351 # We don't want to miss the /section/ pages 352 $out['s']= ckEx('section',$u1)? $u1 : ''; 353 $is_404 = empty($out['s']); 354 } 355 break; 356 357 } 358 } 359 } else { 360 $out['s'] = 'default'; 361 } 362 } 363 else { 364 // Messy mode, but prevent to get the id for file_downloads 365 if ($out['id'] && !$out['s']) { 366 $rs = lookupByID($out['id']); 367 $out['id'] = (!empty($rs['ID'])) ? $rs['ID'] : ''; 368 $out['s'] = (!empty($rs['Section'])) ? $rs['Section'] : ''; 369 $is_404 = (empty($out['s']) or empty($out['id'])); 370 } 371 } 372 373 // Resolve AuthorID from Authorname 374 if ($out['author']) 375 { 376 $name = urldecode(strtolower(urlencode($out['author']))); 377 378 $name = safe_field('name', 'txp_users', "RealName like '".doSlash($out['author'])."'"); 379 380 if ($name) 381 { 382 $out['author'] = $name; 383 } 384 385 else 386 { 387 $out['author'] = ''; 388 $is_404 = true; 389 } 390 } 391 392 // allow article preview 393 if (gps('txpreview') and is_logged_in()) 394 { 395 global $nolog; 396 397 $nolog = true; 398 $rs = safe_row("ID as id,Section as s",'textpattern','ID = '.intval(gps('txpreview')).' limit 1'); 399 400 if ($rs and $is_404) 401 { 402 $is_404 = false; 403 $out = array_merge($out, $rs); 404 } 405 } 406 407 // Stats: found or not 408 $out['status'] = ($is_404 ? '404' : '200'); 409 410 $out['pg'] = is_numeric($out['pg']) ? intval($out['pg']) : ''; 411 $out['id'] = is_numeric($out['id']) ? intval($out['id']) : ''; 412 413 if ($out['s'] == 'file_download') { 414 // get id of potential filename 415 if (!is_numeric($out['id'])) { 416 $rs = safe_row("*", "txp_file", "filename='".doSlash($out['id'])."' and status = 4"); 417 } else { 418 $rs = safe_row("*", "txp_file", 'id='.intval($out['id']).' and status = 4'); 419 } 420 421 $out = ($rs)? array_merge($out, $rs) : array('s'=>'file_download','file_error'=> 404); 422 return $out; 423 } 424 425 if (!$is_404) 426 $out['s'] = (empty($out['s'])) ? 'default' : $out['s']; 427 $s = $out['s']; 428 $id = $out['id']; 429 430 // hackish 431 global $is_article_list; 432 if(empty($id)) $is_article_list = true; 433 434 // by this point we should know the section, so grab its page and css 435 $rs = safe_row("page, css", "txp_section", "name = '".doSlash($s)."' limit 1"); 436 $out['page'] = @$rs['page']; 437 $out['css'] = @$rs['css']; 438 439 if(is_numeric($id) and !$is_404) { 440 $a = safe_row('*, unix_timestamp(Posted) as uPosted, unix_timestamp(Expires) as uExpires, unix_timestamp(LastMod) as uLastMod', 'textpattern', 'ID='.intval($id).(gps('txpreview') ? '' : ' and Status in (4,5)')); 441 if ($a) { 442 $Posted = $a['Posted']; 443 $out['id_keywords'] = $a['Keywords']; 444 $out['id_author'] = $a['AuthorID']; 445 populateArticleData($a); 446 447 $uExpires = $a['uExpires']; 448 if ($uExpires and time() > $uExpires and !$publish_expired_articles) { 449 $out['status'] = '410'; 450 } 451 452 if ($np = getNextPrev($id, $Posted, $s)) 453 $out = array_merge($out, $np); 454 } 455 } 456 457 $out['path_from_root'] = rhu; // these are deprecated as of 1.0 458 $out['pfr'] = rhu; // leaving them here for plugin compat 459 460 $out['path_to_site'] = $path_to_site; 461 $out['permlink_mode'] = $permlink_mode; 462 $out['sitename'] = $sitename; 463 464 return $out; 465 466 } 467 468 // textpattern() is the function that assembles a page, based on 469 // the variables passed to it by pretext(); 470 471 // ------------------------------------------------------------- 472 function textpattern() 473 { 474 global $pretext,$microstart,$prefs,$qcount,$qtime,$production_status,$txptrace,$siteurl,$has_article_tag; 475 476 $has_article_tag = false; 477 478 callback_event('textpattern'); 479 480 if ($pretext['status'] == '404') 481 txp_die(gTxt('404_not_found'), '404'); 482 483 if ($pretext['status'] == '410') 484 txp_die(gTxt('410_gone'), '410'); 485 486 $html = safe_field('user_html','txp_page',"name='".doSlash($pretext['page'])."'"); 487 if (!$html) 488 txp_die(gTxt('unknown_section'), '404'); 489 490 // useful for clean urls with error-handlers 491 txp_status_header('200 OK'); 492 493 trace_add('['.gTxt('page').': '.$pretext['page'].']'); 494 set_error_handler("tagErrorHandler"); 495 $pretext['secondpass'] = false; 496 $html = parse($html); 497 $pretext['secondpass'] = true; 498 trace_add('[ ~~~ '.gTxt('secondpass').' ~~~ ]'); 499 $html = parse($html); // the function so nice, he ran it twice 500 if ($prefs['allow_page_php_scripting']) $html = evalString($html); 501 502 // make sure the page has an article tag if necessary 503 if (!$has_article_tag and $production_status != 'live' and (!empty($pretext['id']) or !empty($pretext['c']) or !empty($pretext['q']) or !empty($pretext['pg']))) 504 trigger_error(gTxt('missing_article_tag', array('{page}' => $pretext['page']))); 505 restore_error_handler(); 506 507 header("Content-type: text/html; charset=utf-8"); 508 echo $html; 509 510 if (in_array($production_status, array('debug', 'testing'))) { 511 $microdiff = (getmicrotime() - $microstart); 512 echo n,comment('Runtime: '.substr($microdiff,0,6)); 513 echo n,comment('Query time: '.sprintf('%02.6f', $qtime)); 514 echo n,comment('Queries: '.$qcount); 515 echo maxMemUsage('end of textpattern()',1); 516 if (!empty($txptrace) and is_array($txptrace)) 517 echo n, comment('txp tag trace: '.n.str_replace('--','­­',join(n, $txptrace)).n); 518 // '­­' is *no* tribute to Kajagoogoo, but an attempt to avoid prematurely terminating HTML comments 519 } 520 521 callback_event('textpattern_end'); 522 } 523 524 // ------------------------------------------------------------- 525 function output_css($s='',$n='') 526 { 527 if ($n) { 528 $cssname = $n; 529 } elseif ($s) { 530 $cssname = safe_field('css','txp_section',"name='".doSlash($s)."'"); 531 } 532 533 $css = safe_field('css','txp_css',"name='".doSlash($cssname)."'"); 534 if ($css) echo base64_decode($css); 535 } 536 537 // article() is called when parse() finds a <txp:article /> tag. 538 // If an $id has been established, we output a single article, 539 // otherwise, output a list. 540 541 // ------------------------------------------------------------- 542 function article($atts, $thing = NULL) 543 { 544 global $is_article_body, $has_article_tag; 545 if ($is_article_body) { 546 trigger_error(gTxt('article_tag_illegal_body')); 547 return ''; 548 } 549 $has_article_tag = true; 550 return parseArticles($atts, '0', $thing); 551 } 552 553 // ------------------------------------------------------------- 554 function doArticles($atts, $iscustom, $thing = NULL) 555 { 556 global $pretext, $prefs; 557 extract($pretext); 558 extract($prefs); 559 $customFields = getCustomFields(); 560 $customlAtts = array_null(array_flip($customFields)); 561 562 //getting attributes 563 $theAtts = lAtts(array( 564 'form' => 'default', 565 'listform' => '', 566 'searchform'=> '', 567 'limit' => 10, 568 'pageby' => '', 569 'category' => '', 570 'section' => '', 571 'excerpted' => '', 572 'author' => '', 573 'sort' => '', 574 'sortby' => '', 575 'sortdir' => '', 576 'month' => '', 577 'keywords' => '', 578 'frontpage' => '', 579 'id' => '', 580 'time' => 'past', 581 'status' => '4', 582 'pgonly' => 0, 583 'searchall' => 1, 584 'searchsticky' => 0, 585 'allowoverride' => (!$q and !$iscustom), 586 'offset' => 0, 587 'wraptag' => '', 588 'break' => '', 589 'label' => '', 590 'labeltag' => '', 591 'class' => '' 592 )+$customlAtts,$atts); 593 594 // if an article ID is specified, treat it as a custom list 595 $iscustom = (!empty($theAtts['id'])) ? true : $iscustom; 596 597 //for the txp:article tag, some attributes are taken from globals; 598 //override them before extract 599 if (!$iscustom) 600 { 601 $theAtts['category'] = ($c)? $c : ''; 602 $theAtts['section'] = ($s && $s!='default')? $s : ''; 603 $theAtts['author'] = (!empty($author)? $author: ''); 604 $theAtts['month'] = (!empty($month)? $month: ''); 605 $theAtts['frontpage'] = ($s && $s=='default')? true: false; 606 $theAtts['excerpted'] = ''; 607 } 608 extract($theAtts); 609 610 // if a listform is specified, $thing is for doArticle() - hence ignore here. 611 if (!empty($listform)) $thing = ''; 612 613 $pageby = (empty($pageby) ? $limit : $pageby); 614 615 // treat sticky articles differently wrt search filtering, etc 616 $status = in_array(strtolower($status), array('sticky', '5')) ? 5 : 4; 617 $issticky = ($status == 5); 618 619 // give control to search, if necessary 620 if ($q && !$iscustom && !$issticky) 621 { 622 include_once txpath.'/publish/search.php'; 623 624 $s_filter = ($searchall ? filterSearch() : ''); 625 $q = doSlash($q); 626 627 // searchable article fields are limited to the columns of 628 // the textpattern table and a matching fulltext index must exist. 629 $cols = do_list($searchable_article_fields); 630 if (empty($cols) or $cols[0] == '') $cols = array('Title', 'Body'); 631 632 $match = ', match (`'.join('`, `', $cols)."`) against ('$q') as score"; 633 for ($i = 0; $i < count($cols); $i++) 634 { 635 $cols[$i] = "`$cols[$i]` rlike '$q'"; 636 } 637 $cols = join(" or ", $cols); 638 $search = " and ($cols) $s_filter"; 639 640 // searchall=0 can be used to show search results for the current section only 641 if ($searchall) $section = ''; 642 if (!$sort) $sort = 'score desc'; 643 } 644 else { 645 $match = $search = ''; 646 if (!$sort) $sort = 'Posted desc'; 647 } 648 649 // for backwards compatibility 650 // sortby and sortdir are deprecated 651 if ($sortby) 652 { 653 if (!$sortdir) 654 { 655 $sortdir = 'desc'; 656 } 657 658 $sort = "$sortby $sortdir"; 659 } 660 661 elseif ($sortdir) 662 { 663 $sort = "Posted $sortdir"; 664 } 665 666 //Building query parts 667 $frontpage = ($frontpage and (!$q or $issticky)) ? filterFrontPage() : ''; 668 $category = join("','", doSlash(do_list($category))); 669 $category = (!$category) ? '' : " and (Category1 IN ('".$category."') or Category2 IN ('".$category."'))"; 670 $section = (!$section) ? '' : " and Section IN ('".join("','", doSlash(do_list($section)))."')"; 671 $excerpted = ($excerpted=='y') ? " and Excerpt !=''" : ''; 672 $author = (!$author) ? '' : " and AuthorID IN ('".join("','", doSlash(do_list($author)))."')"; 673 $month = (!$month) ? '' : " and Posted like '".doSlash($month)."%'"; 674 $id = (!$id) ? '' : " and ID IN (".join(',', array_map('intval', do_list($id))).")"; 675 switch ($time) { 676 case 'any': 677 $time = ""; break; 678 case 'future': 679 $time = " and Posted > now()"; break; 680 default: 681 $time = " and Posted <= now()"; 682 } 683 if (!$publish_expired_articles) { 684 $time .= " and (now() <= Expires or Expires = ".NULLDATETIME.")"; 685 } 686 687 $custom = ''; 688 689 if ($customFields) { 690 foreach($customFields as $cField) { 691 if (isset($atts[$cField])) 692 $customPairs[$cField] = $atts[$cField]; 693 } 694 if(!empty($customPairs)) { 695 $custom = buildCustomSql($customFields,$customPairs); 696 } 697 } 698 699 //Allow keywords for no-custom articles. That tagging mode, you know 700 if ($keywords) { 701 $keys = doSlash(do_list($keywords)); 702 foreach ($keys as $key) { 703 $keyparts[] = "FIND_IN_SET('".$key."',Keywords)"; 704 } 705 $keywords = " and (" . join(' or ',$keyparts) . ")"; 706 } 707 708 if ($q and $searchsticky) 709 $statusq = ' and Status >= 4'; 710 elseif ($id) 711 $statusq = ' and Status >= 4'; 712 else 713 $statusq = ' and Status = '.intval($status); 714 715 $where = "1=1" . $statusq. $time. 716 $search . $id . $category . $section . $excerpted . $month . $author . $keywords . $custom . $frontpage; 717 718 //do not paginate if we are on a custom list 719 if (!$iscustom and !$issticky) 720 { 721 $grand_total = safe_count('textpattern',$where); 722 $total = $grand_total - $offset; 723 $numPages = ceil($total/$pageby); 724 $pg = (!$pg) ? 1 : $pg; 725 $pgoffset = $offset + (($pg - 1) * $pageby); 726 // send paging info to txp:newer and txp:older 727 $pageout['pg'] = $pg; 728 $pageout['numPages'] = $numPages; 729 $pageout['s'] = $s; 730 $pageout['c'] = $c; 731 $pageout['grand_total'] = $grand_total; 732 $pageout['total'] = $total; 733 734 global $thispage; 735 if (empty($thispage)) 736 $thispage = $pageout; 737 if ($pgonly) 738 return; 739 }else{ 740 $pgoffset = $offset; 741 } 742 743 $rs = safe_rows_start("*, unix_timestamp(Posted) as uPosted, unix_timestamp(Expires) as uExpires, unix_timestamp(LastMod) as uLastMod".$match, 'textpattern', 744 $where.' order by '.doSlash($sort).' limit '.intval($pgoffset).', '.intval($limit)); 745 // get the form name 746 if ($q and !$iscustom and !$issticky) 747 $fname = ($searchform ? $searchform : 'search_results'); 748 else 749 $fname = ($listform ? $listform : $form); 750 751 if ($rs) { 752 $count = 0; 753 $last = numRows($rs); 754 755 $articles = array(); 756 while($a = nextRow($rs)) { 757 ++$count; 758 populateArticleData($a); 759 global $thisarticle, $uPosted, $limit; 760 $thisarticle['is_first'] = ($count == 1); 761 $thisarticle['is_last'] = ($count == $last); 762 763 if (@constant('txpinterface') === 'admin' and gps('Form')) { 764 $articles[] = parse(gps('Form')); 765 } 766 elseif ($allowoverride and $a['override_form']) { 767 $articles[] = parse_form($a['override_form']); 768 } 769 else { 770 $articles[] = ($thing) ? parse($thing) : parse_form($fname); 771 } 772 773 // sending these to paging_link(); Required? 774 $uPosted = $a['uPosted']; 775 776 unset($GLOBALS['thisarticle']); 777 } 778 779 return doLabel($label, $labeltag).doWrap($articles, $wraptag, $break, $class); 780 } 781 } 782 783 // ------------------------------------------------------------- 784 785 function filterFrontPage() 786 { 787 static $filterFrontPage; 788 789 if (isset($filterFrontPage)) { 790 return $filterFrontPage; 791 } 792 793 $filterFrontPage = false; 794 795 $rs = safe_column('name', 'txp_section', "on_frontpage != '1'"); 796 797 if ($rs) { 798 $filters = array(); 799 800 foreach ($rs as $name) { 801 $filters[] = " and Section != '".doSlash($name)."'"; 802 } 803 804 $filterFrontPage = join('', $filters); 805 } 806 807 return $filterFrontPage; 808 } 809 810 // ------------------------------------------------------------- 811 function doArticle($atts, $thing = NULL) 812 { 813 global $pretext,$prefs, $thisarticle; 814 extract($prefs); 815 extract($pretext); 816 817 extract(gpsa(array('parentid', 'preview'))); 818 819 extract(lAtts(array( 820 'allowoverride' => '1', 821 'form' => 'default', 822 'status' => '4', 823 ),$atts, 0)); 824 825 // if a form is specified, $thing is for doArticles() - hence ignore $thing here. 826 if (!empty($atts['form'])) $thing = ''; 827 828 if ($status) 829 { 830 $status = in_array(strtolower($status), array('sticky', '5')) ? 5 : 4; 831 } 832 833 if (empty($thisarticle) or $thisarticle['thisid'] != $id) 834 { 835 $thisarticle = NULL; 836 837 $q_status = ($status ? 'and Status = '.intval($status) : 'and Status in (4,5)'); 838 839 $rs = safe_row("*, unix_timestamp(Posted) as uPosted, unix_timestamp(Expires) as uExpires, unix_timestamp(LastMod) as uLastMod", 840 "textpattern", 'ID = '.intval($id)." $q_status limit 1"); 841 842 if ($rs) { 843 extract($rs); 844 populateArticleData($rs); 845 } 846 } 847 848 if (!empty($thisarticle) and ($thisarticle['status'] == $status or gps('txpreview'))) 849 { 850 extract($thisarticle); 851 $thisarticle['is_first'] = 1; 852 $thisarticle['is_last'] = 1; 853 854 if ($allowoverride and $override_form) 855 { 856 $article = parse_form($override_form); 857 } 858 else 859 { 860 $article = ($thing) ? parse($thing) : parse_form($form); 861 } 862 863 if ($use_comments and $comments_auto_append) 864 { 865 $article .= parse_form('comments_display'); 866 } 867 868 unset($GLOBALS['thisarticle']); 869 870 return $article; 871 } 872 } 873 874 // ------------------------------------------------------------- 875 function article_custom($atts, $thing = NULL) 876 { 877 return parseArticles($atts, '1', $thing); 878 } 879 880 // ------------------------------------------------------------- 881 function parseArticles($atts, $iscustom = 0, $thing = NULL) 882 { 883 global $pretext, $is_article_list; 884 $old_ial = $is_article_list; 885 $is_article_list = ($pretext['id'] && !$iscustom)? false : true; 886 article_push(); 887 $r = ($is_article_list)? doArticles($atts, $iscustom, $thing) : doArticle($atts, $thing); 888 article_pop(); 889 $is_article_list = $old_ial; 890 891 return $r; 892 } 893 894 // ------------------------------------------------------------- 895 // Keep all the article tag-related values in one place, 896 // in order to do easy bugfix and easily the addition of 897 // new article tags. 898 function populateArticleData($rs) 899 { 900 global $thisarticle; 901 extract($rs); 902 903 trace_add("[".gTxt('Article')." $ID]"); 904 $thisarticle['thisid'] = $ID; 905 $thisarticle['posted'] = $uPosted; 906 $thisarticle['expires'] = $uExpires; 907 $thisarticle['modified'] = $uLastMod; 908 $thisarticle['annotate'] = $Annotate; 909 $thisarticle['comments_invite'] = $AnnotateInvite; 910 $thisarticle['authorid'] = $AuthorID; 911 $thisarticle['title'] = $Title; 912 $thisarticle['url_title'] = $url_title; 913 $thisarticle['category1'] = $Category1; 914 $thisarticle['category2'] = $Category2; 915 $thisarticle['section'] = $Section; 916 $thisarticle['keywords'] = $Keywords; 917 $thisarticle['article_image'] = $Image; 918 $thisarticle['comments_count'] = $comments_count; 919 $thisarticle['body'] = $Body_html; 920 $thisarticle['excerpt'] = $Excerpt_html; 921 $thisarticle['override_form'] = $override_form; 922 $thisarticle['status'] = $Status; 923 924 $custom = getCustomFields(); 925 if ($custom) { 926 foreach ($custom as $i => $name) 927 $thisarticle[$name] = $rs['custom_' . $i]; 928 } 929 930 } 931 932 // ------------------------------------------------------------- 933 function getNeighbour($Posted, $s, $type) 934 { 935 global $prefs; 936 extract($prefs); 937 $expired = ($publish_expired_articles) ? '' : ' and (now() <= Expires or Expires = '.NULLDATETIME.')'; 938 $type = ($type == '>') ? '>' : '<'; 939 $safe_name = safe_pfx('textpattern'); 940 $q = array( 941 "select ID, Title, url_title, unix_timestamp(Posted) as uposted 942 from ".$safe_name." where Posted $type '".doSlash($Posted)."'", 943 ($s!='' && $s!='default') ? "and Section = '".doSlash($s)."'" : filterFrontPage(), 944 'and Status=4 and Posted < now()'.$expired.' order by Posted', 945 ($type=='<') ? 'desc' : 'asc', 946 'limit 1' 947 ); 948 949 $out = getRow(join(' ',$q)); 950 return (is_array($out)) ? $out : ''; 951 } 952 953 // ------------------------------------------------------------- 954 function getNextPrev($id, $Posted, $s) 955 { 956 static $next, $cache; 957 958 if (@isset($cache[$next[$id]])) 959 $thenext = $cache[$next[$id]]; 960 else 961 $thenext = getNeighbour($Posted,$s,'>'); 962 963 $out['next_id'] = ($thenext) ? $thenext['ID'] : ''; 964 $out['next_title'] = ($thenext) ? $thenext['Title'] : ''; 965 $out['next_utitle'] = ($thenext) ? $thenext['url_title'] : ''; 966 $out['next_posted'] = ($thenext) ? $thenext['uposted'] : ''; 967 968 $theprev = getNeighbour($Posted,$s,'<'); 969 $out['prev_id'] = ($theprev) ? $theprev['ID'] : ''; 970 $out['prev_title'] = ($theprev) ? $theprev['Title'] : ''; 971 $out['prev_utitle'] = ($theprev) ? $theprev['url_title'] : ''; 972 $out['prev_posted'] = ($theprev) ? $theprev['uposted'] : ''; 973 974 if ($theprev) { 975 $cache[$theprev['ID']] = $theprev; 976 $next[$theprev['ID']] = $id; 977 } 978 979 return $out; 980 } 981 982 // ------------------------------------------------------------- 983 function lastMod() 984 { 985 $last = safe_field("unix_timestamp(val)", "txp_prefs", "`name`='lastmod' and prefs_id=1"); 986 return gmdate("D, d M Y H:i:s \G\M\T",$last); 987 } 988 989 // ------------------------------------------------------------- 990 function parse($thing) 991 { 992 $f = '@(</?txp:\w+(?:\s+\w+\s*=\s*(?:"(?:[^"]|"")*"|\'(?:[^\']|\'\')*\'|[^\s\'"/>]+))*\s*/?'.chr(62).')@s'; 993 $t = '@:(\w+)(.*?)/?.$@s'; 994 995 $parsed = preg_split($f, $thing, -1, PREG_SPLIT_DELIM_CAPTURE); 996 997 $level = 0; 998 $out = ''; 999 $inside = ''; 1000 $istag = FALSE; 1001 1002 foreach ($parsed as $chunk) 1003 { 1004 if ($istag) 1005 { 1006 if ($level === 0) 1007 { 1008 preg_match($t, $chunk, $tag); 1009 1010 if (substr($chunk, -2, 1) === '/') 1011 { # self closing 1012 $out .= processTags($tag[1], $tag[2]); 1013 } 1014 else 1015 { # opening 1016 $level++; 1017 } 1018 } 1019 else 1020 { 1021 if (substr($chunk, 1, 1) === '/') 1022 { # closing 1023 if (--$level === 0) 1024 { 1025 $out .= processTags($tag[1], $tag[2], $inside); 1026 $inside = ''; 1027 } 1028 else 1029 { 1030 $inside .= $chunk; 1031 } 1032 } 1033 elseif (substr($chunk, -2, 1) !== '/') 1034 { # opening inside open 1035 ++$level; 1036 $inside .= $chunk; 1037 } 1038 else 1039 { 1040 $inside .= $chunk; 1041 } 1042 } 1043 } 1044 else 1045 { 1046 if ($level) 1047 { 1048 $inside .= $chunk; 1049 } 1050 else 1051 { 1052 $out .= $chunk; 1053 } 1054 } 1055 1056 $istag = !$istag; 1057 } 1058 1059 return $out; 1060 } 1061 1062 // ------------------------------------------------------------- 1063 1064 function processTags($tag, $atts, $thing = NULL) 1065 { 1066 global $production_status, $txptrace, $txptracelevel, $txp_current_tag; 1067 1068 if ($production_status !== 'live') 1069 { 1070 $old_tag = $txp_current_tag; 1071 1072 $txp_current_tag = '<txp:'.$tag.$atts.(isset($thing) ? '>' : '/>'); 1073 1074 trace_add($txp_current_tag); 1075 ++$txptracelevel; 1076 1077 if ($production_status === 'debug') 1078 { 1079 maxMemUsage($txp_current_tag); 1080 } 1081 } 1082 1083 if ($tag === 'link') 1084 { 1085 $tag = 'tpt_'.$tag; 1086 } 1087 1088 if (function_exists($tag)) 1089 { 1090 $out = $tag(splat($atts), $thing); 1091 } 1092 1093 // deprecated, remove in crockery 1094 elseif (isset($GLOBALS['pretext'][$tag])) 1095 { 1096 $out = htmlspecialchars($pretext[$tag]); 1097 1098 trigger_error(gTxt('deprecated_tag'), E_USER_NOTICE); 1099 } 1100 1101 else 1102 { 1103 $out = ''; 1104 trigger_error(gTxt('unknown_tag'), E_USER_WARNING); 1105 } 1106 1107 if ($production_status !== 'live') 1108 { 1109 --$txptracelevel; 1110 1111 if (isset($thing)) 1112 { 1113 trace_add('</txp:'.$tag.'>'); 1114 } 1115 1116 $txp_current_tag = $old_tag; 1117 } 1118 1119 return $out; 1120 } 1121 1122 // ------------------------------------------------------------- 1123 function bombShelter() // protection from those who'd bomb the site by GET 1124 { 1125 global $prefs; 1126 $in = serverset('REQUEST_URI'); 1127 if (!empty($prefs['max_url_len']) and strlen($in) > $prefs['max_url_len']) exit('Nice try.'); 1128 } 1129 1130 // ------------------------------------------------------------- 1131 function evalString($html) 1132 { 1133 global $prefs; 1134 if (strpos($html, chr(60).'?php') !== false) { 1135 trigger_error(gTxt('raw_php_deprecated'), E_USER_WARNING); 1136 if (!empty($prefs['allow_raw_php_scripting'])) 1137 $html = eval(' ?'.chr(62).$html.chr(60).'?php '); 1138 else 1139 trigger_error(gTxt('raw_php_disabled'), E_USER_WARNING); 1140 } 1141 return $html; 1142 } 1143 1144 // ------------------------------------------------------------- 1145 function getCustomFields() 1146 { 1147 global $prefs; 1148 $out = array(); 1149 for ($i=1; $i<=10; $i++) { 1150 if (!empty($prefs['custom_'.$i.'_set'])) { 1151 $out[$i] = strtolower($prefs['custom_'.$i.'_set']); 1152 } 1153 } 1154 return $out; 1155 } 1156 1157 // ------------------------------------------------------------- 1158 function buildCustomSql($custom,$pairs) 1159 { 1160 if ($pairs) { 1161 $pairs = doSlash($pairs); 1162 foreach($pairs as $k => $v) { 1163 if(in_array($k,$custom)) { 1164 $no = array_keys($custom,$k); 1165 # nb - use 'like' here to allow substring matches 1166 $out[] = "and custom_".$no[0]." like '$v'"; 1167 } 1168 } 1169 } 1170 return (!empty($out)) ? ' '.join(' ',$out).' ' : false; 1171 } 1172 1173 // ------------------------------------------------------------- 1174 function getStatusNum($name) 1175 { 1176 $labels = array('draft' => 1, 'hidden' => 2, 'pending' => 3, 'live' => 4, 'sticky' => 5); 1177 $status = strtolower($name); 1178 $num = empty($labels[$status]) ? 4 : $labels[$status]; 1179 return $num; 1180 } 1181 1182 // ------------------------------------------------------------- 1183 function ckEx($table,$val,$debug='') 1184 { 1185 return safe_field("name",'txp_'.$table,"`name` like '".doSlash($val)."' limit 1",$debug); 1186 } 1187 1188 // ------------------------------------------------------------- 1189 function ckExID($val,$debug='') 1190 { 1191 return safe_row("ID,Section",'textpattern','ID = '.intval($val).' and Status >= 4 limit 1',$debug); 1192 } 1193 1194 // ------------------------------------------------------------- 1195 function lookupByTitle($val,$debug='') 1196 { 1197 return safe_row("ID,Section",'textpattern',"url_title like '".doSlash($val)."' and Status >= 4 limit 1",$debug); 1198 } 1199 // ------------------------------------------------------------- 1200 function lookupByTitleSection($val,$section,$debug='') 1201 { 1202 return safe_row("ID,Section",'textpattern',"url_title like '".doSlash($val)."' AND Section='".doSlash($section)."' and Status >= 4 limit 1",$debug); 1203 } 1204 1205 // ------------------------------------------------------------- 1206 1207 function lookupByIDSection($id, $section, $debug = '') 1208 { 1209 return safe_row('ID, Section', 'textpattern', 1210 'ID = '.intval($id)." and Section = '".doSlash($section)."' and Status >= 4 limit 1", $debug); 1211 } 1212 1213 // ------------------------------------------------------------- 1214 function lookupByID($id,$debug='') 1215 { 1216 return safe_row("ID,Section",'textpattern','ID = '.intval($id).' and Status >= 4 limit 1',$debug); 1217 } 1218 1219 // ------------------------------------------------------------- 1220 function lookupByDateTitle($when,$title,$debug='') 1221 { 1222 return safe_row("ID,Section","textpattern", 1223 "posted like '".doSlash($when)."%' and url_title like '".doSlash($title)."' and Status >= 4 limit 1"); 1224 } 1225 1226 // ------------------------------------------------------------- 1227 function makeOut() 1228 { 1229 foreach(func_get_args() as $a) { 1230 $array[$a] = strval(gps($a)); 1231 } 1232 return $array; 1233 } 1234 1235 // ------------------------------------------------------------- 1236 function chopUrl($req) 1237 { 1238 $req = strtolower($req); 1239 //strip off query_string, if present 1240 $qs = strpos($req,'?'); 1241 if ($qs) $req = substr($req, 0, $qs); 1242 $req = preg_replace('/index\.php$/', '', $req); 1243 $r = array_map('urldecode', explode('/',$req)); 1244 $o['u0'] = (isset($r[0])) ? $r[0] : ''; 1245 $o['u1'] = (isset($r[1])) ? $r[1] : ''; 1246 $o['u2'] = (isset($r[2])) ? $r[2] : ''; 1247 $o['u3'] = (isset($r[3])) ? $r[3] : ''; 1248 $o['u4'] = (isset($r[4])) ? $r[4] : ''; 1249 1250 return $o; 1251 } 1252 1253 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu May 21 23:03:01 2009 | Cross-referenced by PHPXref 0.7 |