Textpattern | PHP Cross Reference | Content Management Systems |
Description: Collection of tag functions.
1 <?php 2 3 /* 4 * Textpattern Content Management System 5 * http://textpattern.com 6 * 7 * Copyright (C) 2005 Dean Allen 8 * Copyright (C) 2016 The Textpattern Development Team 9 * 10 * This file is part of Textpattern. 11 * 12 * Textpattern is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation, version 2. 15 * 16 * Textpattern is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with Textpattern. If not, see <http://www.gnu.org/licenses/>. 23 */ 24 25 /** 26 * Collection of tag functions. 27 * 28 * @package Tag 29 */ 30 31 Txp::get('\Textpattern\Tag\Registry') 32 ->register('page_title') 33 ->register('css') 34 ->register('image') 35 ->register('thumbnail') 36 ->register('output_form') 37 ->register(array('\Textpattern\Tag\Syntax\Partial', 'renderYield'), 'yield') 38 ->register(array('\Textpattern\Tag\Syntax\Partial', 'renderIfYield'), 'if_yield') 39 ->register('feed_link') 40 ->register('link_feed_link') 41 ->register('linklist') 42 ->register('tpt_link', 'link') 43 ->register('linkdesctitle') 44 ->register('link_name') 45 ->register('link_url') 46 ->register('link_author') 47 ->register('link_description') 48 ->register('link_date') 49 ->register('link_category') 50 ->register('link_id') 51 ->register(array('\Textpattern\Tag\Syntax\Link', 'renderIfFirstLink'), 'if_first_link') 52 ->register(array('\Textpattern\Tag\Syntax\Link', 'renderIfLastLink'), 'if_last_link') 53 ->register('email') 54 ->register('password_protect') 55 ->register('recent_articles') 56 ->register('recent_comments') 57 ->register('related_articles') 58 ->register('popup') 59 ->register('category_list') 60 ->register('section_list') 61 ->register('search_input') 62 ->register('search_term') 63 ->register('link_to_next') 64 ->register('link_to_prev') 65 ->register('next_title') 66 ->register('prev_title') 67 ->register('site_name') 68 ->register('site_slogan') 69 ->register('link_to_home') 70 ->register('newer') 71 ->register('older') 72 ->register('text') 73 ->register('article_id') 74 ->register('article_url_title') 75 ->register('if_article_id') 76 ->register('posted') 77 ->register('expires') 78 ->register('if_expires') 79 ->register('if_expired') 80 ->register('modified') 81 ->register('comments_count') 82 ->register('comments_invite') 83 ->register('comments_form') 84 ->register('comments_error') 85 ->register('if_comments_error') 86 ->register('comments') 87 ->register('comments_preview') 88 ->register('if_comments_preview') 89 ->register('comment_permlink') 90 ->register('comment_id') 91 ->register('comment_name') 92 ->register('comment_email') 93 ->register('comment_web') 94 ->register('comment_time') 95 ->register('comment_message') 96 ->register('comment_anchor') 97 ->register(array('\Textpattern\Tag\Syntax\Authors', 'renderAuthors'), 'authors') 98 ->register('author') 99 ->register('author_email') 100 ->register('if_author') 101 ->register('if_article_author') 102 ->register('body') 103 ->register('title') 104 ->register('excerpt') 105 ->register('category1') 106 ->register('category2') 107 ->register('category') 108 ->register('section') 109 ->register('keywords') 110 ->register('if_keywords') 111 ->register('if_description') 112 ->register('if_article_image') 113 ->register('article_image') 114 ->register('search_result_title') 115 ->register('search_result_excerpt') 116 ->register('search_result_url') 117 ->register('search_result_date') 118 ->register('search_result_count') 119 ->register('image_index') 120 ->register('image_display') 121 ->register('images') 122 ->register('image_info') 123 ->register('image_url') 124 ->register('image_author') 125 ->register('image_date') 126 ->register(array('\Textpattern\Tag\Syntax\Image', 'renderIfFirstImage'), 'if_first_image') 127 ->register(array('\Textpattern\Tag\Syntax\Image', 'renderIfLastImage'), 'if_last_image') 128 ->register('if_thumbnail') 129 ->register('if_comments') 130 ->register('if_comments_allowed') 131 ->register('if_comments_disallowed') 132 ->register('if_individual_article') 133 ->register('if_article_list') 134 ->register('meta_keywords') 135 ->register('meta_description') 136 ->register('meta_author') 137 ->register('permlink') 138 ->register('lang') 139 ->register('breadcrumb') 140 ->register('if_excerpt') 141 ->register('if_search') 142 ->register('if_search_results') 143 ->register('if_category') 144 ->register('if_article_category') 145 ->register('if_first_category') 146 ->register('if_last_category') 147 ->register('if_section') 148 ->register('if_article_section') 149 ->register('if_first_section') 150 ->register('if_last_section') 151 ->register('php') 152 ->register('custom_field') 153 ->register('if_custom_field') 154 ->register('site_url') 155 ->register('error_message') 156 ->register('error_status') 157 ->register('if_status') 158 ->register('page_url') 159 ->register('if_different') 160 ->register('if_first_article') 161 ->register('if_last_article') 162 ->register('if_plugin') 163 ->register('file_download_list') 164 ->register('file_download') 165 ->register('file_download_link') 166 ->register('file_download_size') 167 ->register('file_download_created') 168 ->register('file_download_modified') 169 ->register('file_download_id') 170 ->register('file_download_name') 171 ->register('file_download_category') 172 ->register('file_download_author') 173 ->register('file_download_downloads') 174 ->register('file_download_description') 175 ->register(array('\Textpattern\Tag\Syntax\File', 'renderIfFirstFile'), 'if_first_file') 176 ->register(array('\Textpattern\Tag\Syntax\File', 'renderIfLastFile'), 'if_last_file') 177 ->register('hide') 178 ->register('rsd') 179 ->register('variable') 180 ->register('if_variable') 181 ->register('article') 182 ->register('article_custom') 183 ->register('txp_die') 184 ->register('comments_help') 185 ->register('comment_name_input') 186 ->register('comment_email_input') 187 ->register('comment_web_input') 188 ->register('comment_message_input') 189 ->register('comment_remember') 190 ->register('comment_preview') 191 ->register('comment_submit'); 192 193 // ------------------------------------------------------------- 194 195 function page_title($atts) 196 { 197 global $parentid, $thisarticle, $id, $q, $c, $author, $context, $s, $pg, $sitename; 198 199 extract(lAtts(array( 200 'separator' => ': ', 201 ), $atts)); 202 203 $out = txpspecialchars($sitename.$separator); 204 $parent_id = (int) $parentid; 205 206 if ($parent_id) { 207 $out .= gTxt('comments_on').' '.escape_title(safe_field("Title", 'textpattern', "ID = $parent_id")); 208 } elseif ($thisarticle['title']) { 209 $out .= escape_title($thisarticle['title']); 210 } elseif ($q) { 211 $out .= gTxt('search_results').txpspecialchars($separator.$q); 212 } elseif ($c) { 213 $out .= txpspecialchars(fetch_category_title($c, $context)); 214 } elseif ($s and $s != 'default') { 215 $out .= txpspecialchars(fetch_section_title($s)); 216 } elseif ($author) { 217 $out .= txpspecialchars(get_author_name($author)); 218 } elseif ($pg) { 219 $out .= gTxt('page').' '.$pg; 220 } else { 221 $out = txpspecialchars($sitename); 222 } 223 224 return $out; 225 } 226 227 // ------------------------------------------------------------- 228 229 function css($atts) 230 { 231 global $css, $doctype; 232 233 extract(lAtts(array( 234 'format' => 'url', 235 'media' => 'screen', 236 'n' => $css, // Deprecated in 4.3.0. 237 'name' => $css, 238 'rel' => 'stylesheet', 239 'title' => '', 240 ), $atts)); 241 242 if (isset($atts['n'])) { 243 $name = $n; 244 trigger_error(gTxt('deprecated_attribute', array('{name}' => 'n')), E_USER_NOTICE); 245 } 246 247 if (empty($name)) { 248 $name = 'default'; 249 } 250 251 if (has_handler('css.url')) { 252 $url = callback_event('css.url', '', false, compact('name')); 253 } else { 254 $url = hu.'css.php?n='.urlencode($name); 255 } 256 257 if ($format == 'link') { 258 return tag_void('link', array( 259 'rel' => $rel, 260 'type' => $doctype != 'html5' ? 'text/css' : '', 261 'media' => $media, 262 'title' => $title, 263 'href' => $url, 264 )); 265 } 266 267 return txpspecialchars($url); 268 } 269 270 // ------------------------------------------------------------- 271 272 function image($atts) 273 { 274 global $thisimage; 275 static $cache = array(); 276 277 extract(lAtts(array( 278 'class' => '', 279 'escape' => 'html', 280 'html_id' => '', 281 'id' => '', 282 'name' => '', 283 'width' => '', 284 'height' => '', 285 'style' => '', 286 'wraptag' => '', 287 ), $atts)); 288 289 if ($name) { 290 if (isset($cache['n'][$name])) { 291 $rs = $cache['n'][$name]; 292 } else { 293 $name = doSlash($name); 294 295 $rs = safe_row("*", 'txp_image', "name = '$name' LIMIT 1"); 296 297 $cache['n'][$name] = $rs; 298 } 299 } elseif ($id) { 300 if (isset($cache['i'][$id])) { 301 $rs = $cache['i'][$id]; 302 } else { 303 $id = (int) $id; 304 305 $rs = safe_row("*", 'txp_image', "id = $id LIMIT 1"); 306 307 $cache['i'][$id] = $rs; 308 } 309 } elseif ($thisimage) { 310 $id = (int) $thisimage['id']; 311 $rs = $thisimage; 312 $cache['i'][$id] = $rs; 313 } else { 314 trigger_error(gTxt('unknown_image')); 315 316 return; 317 } 318 319 if ($rs) { 320 extract($rs); 321 322 if ($escape == 'html') { 323 $alt = txpspecialchars($alt); 324 $caption = txpspecialchars($caption); 325 } 326 327 if ($width == '' && $w) { 328 $width = $w; 329 } 330 331 if ($height == '' && $h) { 332 $height = $h; 333 } 334 335 $out = '<img src="'.imagesrcurl($id, $ext).'" alt="'.$alt.'"'; 336 337 if ($html_id and !$wraptag) { 338 $out .= ' id="'.txpspecialchars($html_id).'"'; 339 } 340 341 if ($class and !$wraptag) { 342 $out .= ' class="'.txpspecialchars($class).'"'; 343 } 344 345 if ($style) { 346 $out .= ' style="'.txpspecialchars($style).'"'; 347 } 348 349 if ($width) { 350 $out .= ' width="'.(int) $width.'"'; 351 } 352 353 if ($height) { 354 $out .= ' height="'.(int) $height.'"'; 355 } 356 357 $out .= ' />'; 358 359 if ($wraptag) { 360 return doTag($out, $wraptag, $class, '', $html_id); 361 } 362 363 return $out; 364 } 365 366 trigger_error(gTxt('unknown_image')); 367 } 368 369 // ------------------------------------------------------------- 370 371 function thumbnail($atts) 372 { 373 global $thisimage; 374 375 extract(lAtts(array( 376 'class' => '', 377 'escape' => 'html', 378 'html_id' => '', 379 'height' => '', 380 'id' => '', 381 'link' => 0, 382 'link_rel' => '', 383 'name' => '', 384 'poplink' => 0, // Is this used? 385 'style' => '', 386 'wraptag' => '', 387 'width' => '', 388 ), $atts)); 389 390 if ($name) { 391 $name = doSlash($name); 392 393 $rs = safe_row("*", 'txp_image', "name = '$name' LIMIT 1"); 394 } elseif ($id) { 395 $id = (int) $id; 396 397 $rs = safe_row("*", 'txp_image', "id = $id LIMIT 1"); 398 } elseif ($thisimage) { 399 $id = (int) $thisimage['id']; 400 $rs = $thisimage; 401 } else { 402 trigger_error(gTxt('unknown_image')); 403 404 return; 405 } 406 407 if ($rs) { 408 extract($rs); 409 410 if ($thumbnail) { 411 if ($escape == 'html') { 412 $alt = txpspecialchars($alt); 413 $caption = txpspecialchars($caption); 414 } 415 416 if ($width == '' && $thumb_w) { 417 $width = $thumb_w; 418 } 419 420 if ($height == '' && $thumb_h) { 421 $height = $thumb_h; 422 } 423 424 $out = '<img src="'.imagesrcurl($id, $ext, true).'" alt="'.$alt.'"'; 425 426 if ($html_id and !$wraptag) { 427 $out .= ' id="'.txpspecialchars($html_id).'"'; 428 } 429 430 if ($class and !$wraptag) { 431 $out .= ' class="'.txpspecialchars($class).'"'; 432 } 433 434 if ($style) { 435 $out .= ' style="'.txpspecialchars($style).'"'; 436 } 437 438 if ($width) { 439 $out .= ' width="'.(int) $width.'"'; 440 } 441 442 if ($height) { 443 $out .= ' height="'.(int) $height.'"'; 444 } 445 446 $out .= ' />'; 447 448 if ($link) { 449 $attribs = ''; 450 451 if (!empty($link_rel)) { 452 $attribs .= " rel='".txpspecialchars($link_rel)."'"; 453 } 454 455 $out = href($out, imagesrcurl($id, $ext), $attribs); 456 } elseif ($poplink) { 457 $out = '<a href="'.imagesrcurl($id, $ext).'"'. 458 ' onclick="window.open(this.href, \'popupwindow\', '. 459 '\'width='.$w.', height='.$h.', scrollbars, resizable\'); return false;">'.$out.'</a>'; 460 } 461 462 if ($wraptag) { 463 return doTag($out, $wraptag, $class, '', $html_id); 464 } 465 466 return $out; 467 } 468 } 469 470 trigger_error(gTxt('unknown_image')); 471 } 472 473 // ------------------------------------------------------------- 474 475 function output_form($atts, $thing = null) 476 { 477 global $yield; 478 479 extract(lAtts(array( 480 'form' => '', 481 ), $atts)); 482 483 if (!$form) { 484 trigger_error(gTxt('form_not_specified')); 485 } else { 486 $yield[] = $thing !== null ? parse($thing) : null; 487 $out = parse_form($form); 488 array_pop($yield); 489 490 return $out; 491 } 492 } 493 494 // ------------------------------------------------------------- 495 496 function feed_link($atts, $thing = null) 497 { 498 global $s, $c; 499 500 extract(lAtts(array( 501 'category' => $c, 502 'flavor' => 'rss', 503 'format' => 'a', 504 'label' => '', 505 'limit' => '', 506 'section' => ($s == 'default' ? '' : $s), 507 'title' => gTxt('rss_feed_title'), 508 'wraptag' => '', 509 'class' => '', 510 ), $atts)); 511 512 $url = pagelinkurl(array( 513 $flavor => '1', 514 'section' => $section, 515 'category' => $category, 516 'limit' => $limit, 517 )); 518 519 if ($flavor == 'atom') { 520 $title = ($title == gTxt('rss_feed_title')) ? gTxt('atom_feed_title') : $title; 521 } 522 523 $title = txpspecialchars($title); 524 525 if ($format == 'link') { 526 $type = ($flavor == 'atom') ? 'application/atom+xml' : 'application/rss+xml'; 527 528 return '<link rel="alternate" type="'.$type.'" title="'.$title.'" href="'.$url.'" />'; 529 } 530 531 $txt = ($thing === null ? $label : parse($thing)); 532 533 $out = href($txt, $url, ' title="'.$title.'"'); 534 535 return ($wraptag) ? doTag($out, $wraptag, $class) : $out; 536 } 537 538 // ------------------------------------------------------------- 539 540 function link_feed_link($atts) 541 { 542 global $c; 543 544 extract(lAtts(array( 545 'category' => $c, 546 'flavor' => 'rss', 547 'format' => 'a', 548 'label' => '', 549 'title' => gTxt('rss_feed_title'), 550 'wraptag' => '', 551 'class' => __FUNCTION__, 552 ), $atts)); 553 554 $url = pagelinkurl(array( 555 $flavor => '1', 556 'area' => 'link', 557 'category' => $category, 558 )); 559 560 if ($flavor == 'atom') { 561 $title = ($title == gTxt('rss_feed_title')) ? gTxt('atom_feed_title') : $title; 562 } 563 564 $title = txpspecialchars($title); 565 566 if ($format == 'link') { 567 $type = ($flavor == 'atom') ? 'application/atom+xml' : 'application/rss+xml'; 568 569 return '<link rel="alternate" type="'.$type.'" title="'.$title.'" href="'.$url.'" />'; 570 } 571 572 $out = href($label, $url, ' title="'.$title.'"'); 573 574 return ($wraptag) ? doTag($out, $wraptag, $class) : $out; 575 } 576 577 // ------------------------------------------------------------- 578 579 function linklist($atts, $thing = null) 580 { 581 global $s, $c, $context, $thislink, $thispage, $pretext; 582 583 extract(lAtts(array( 584 'break' => '', 585 'category' => '', 586 'author' => '', 587 'realname' => '', 588 'auto_detect' => 'category, author', 589 'class' => __FUNCTION__, 590 'form' => 'plainlinks', 591 'id' => '', 592 'label' => '', 593 'labeltag' => '', 594 'pageby' => '', 595 'limit' => 0, 596 'offset' => 0, 597 'sort' => 'linksort asc', 598 'wraptag' => '', 599 ), $atts)); 600 601 $where = array(); 602 $filters = isset($atts['category']) || isset($atts['author']) || isset($atts['realname']); 603 $context_list = (empty($auto_detect) || $filters) ? array() : do_list_unique($auto_detect); 604 $pageby = ($pageby == 'limit') ? $limit : $pageby; 605 606 if ($category) { 607 $where[] = "category IN ('".join("','", doSlash(do_list_unique($category)))."')"; 608 } 609 610 if ($id) { 611 $where[] = "id IN ('".join("','", doSlash(do_list_unique($id)))."')"; 612 } 613 614 if ($author) { 615 $where[] = "author IN ('".join("','", doSlash(do_list_unique($author)))."')"; 616 } 617 618 if ($realname) { 619 $authorlist = safe_column("name", 'txp_users', "RealName IN ('".join("','", doArray(doSlash(do_list_unique($realname)), 'urldecode'))."')"); 620 if ($authorlist) { 621 $where[] = "author IN ('".join("','", doSlash($authorlist))."')"; 622 } 623 } 624 625 // If no links are selected, try... 626 if (!$where && !$filters) { 627 foreach ($context_list as $ctxt) { 628 switch ($ctxt) { 629 case 'category': 630 // ...the global category in the URL. 631 if ($context == 'link' && !empty($c)) { 632 $where[] = "category = '".doSlash($c)."'"; 633 } 634 break; 635 case 'author': 636 // ...the global author in the URL. 637 if ($context == 'link' && !empty($pretext['author'])) { 638 $where[] = "author = '".doSlash($pretext['author'])."'"; 639 } 640 break; 641 } 642 643 // Only one context can be processed. 644 if ($where) { 645 break; 646 } 647 } 648 } 649 650 if (!$where && $filters) { 651 // If nothing matches, output nothing. 652 return ''; 653 } 654 655 if (!$where) { 656 // If nothing matches, start with all links. 657 $where[] = "1 = 1"; 658 } 659 660 $where = join(" AND ", $where); 661 662 // Set up paging if required. 663 if ($limit && $pageby) { 664 $grand_total = safe_count('txp_link', $where); 665 $total = $grand_total - $offset; 666 $numPages = ($pageby > 0) ? ceil($total/$pageby) : 1; 667 $pg = (!$pretext['pg']) ? 1 : $pretext['pg']; 668 $pgoffset = $offset + (($pg - 1) * $pageby); 669 670 // Send paging info to txp:newer and txp:older. 671 $pageout['pg'] = $pg; 672 $pageout['numPages'] = $numPages; 673 $pageout['s'] = $s; 674 $pageout['c'] = $c; 675 $pageout['context'] = 'link'; 676 $pageout['grand_total'] = $grand_total; 677 $pageout['total'] = $total; 678 679 if (empty($thispage)) { 680 $thispage = $pageout; 681 } 682 } else { 683 $pgoffset = $offset; 684 } 685 686 $qparts = array( 687 $where, 688 'ORDER BY '.doSlash($sort), 689 ($limit) ? 'LIMIT '.intval($pgoffset).', '.intval($limit) : '', 690 ); 691 692 $rs = safe_rows_start("*, UNIX_TIMESTAMP(date) AS uDate", 'txp_link', join(' ', $qparts)); 693 694 if ($rs) { 695 $count = 0; 696 $last = numRows($rs); 697 $out = array(); 698 699 while ($a = nextRow($rs)) { 700 ++$count; 701 $thislink = $a; 702 $thislink['date'] = $thislink['uDate']; 703 $thislink['is_first'] = ($count == 1); 704 $thislink['is_last'] = ($count == $last); 705 unset($thislink['uDate']); 706 707 $out[] = ($thing) ? parse($thing) : parse_form($form); 708 709 $thislink = ''; 710 } 711 712 if ($out) { 713 return doLabel($label, $labeltag).doWrap($out, $wraptag, $break, $class); 714 } 715 } 716 717 return ''; 718 } 719 720 // ------------------------------------------------------------- 721 722 // NOTE: tpt_ prefix used because link() is a PHP function. See publish.php. 723 function tpt_link($atts) 724 { 725 global $thislink; 726 727 extract(lAtts(array( 728 'rel' => '', 729 'id' => '', 730 'name' => '', 731 ), $atts)); 732 733 $rs = $thislink; 734 $sql = array(); 735 736 if ($id) { 737 $sql[] = "id = ".intval($id); 738 } elseif ($name) { 739 $sql[] = "linkname = '".doSlash($name)."'"; 740 } 741 742 if ($sql) { 743 $rs = safe_row("linkname, url", 'txp_link', implode(" AND ", $sql)." LIMIT 1"); 744 } 745 746 if (!$rs) { 747 trigger_error(gTxt('unknown_link')); 748 749 return; 750 } 751 752 return tag( 753 txpspecialchars($rs['linkname']), 'a', 754 ($rel ? ' rel="'.txpspecialchars($rel).'"' : ''). 755 ' href="'.txpspecialchars($rs['url']).'"' 756 ); 757 } 758 759 // ------------------------------------------------------------- 760 761 function linkdesctitle($atts) 762 { 763 global $thislink; 764 765 assert_link(); 766 767 extract(lAtts(array( 768 'rel' => '', 769 ), $atts)); 770 771 $description = ($thislink['description']) 772 ? ' title="'.txpspecialchars($thislink['description']).'"' 773 : ''; 774 775 return tag( 776 txpspecialchars($thislink['linkname']), 'a', 777 ($rel ? ' rel="'.txpspecialchars($rel).'"' : ''). 778 ' href="'.doSpecial($thislink['url']).'"'.$description 779 ); 780 } 781 782 // ------------------------------------------------------------- 783 784 function link_name($atts) 785 { 786 global $thislink; 787 788 assert_link(); 789 790 extract(lAtts(array( 791 'escape' => 'html', 792 ), $atts)); 793 794 return ($escape == 'html') 795 ? txpspecialchars($thislink['linkname']) 796 : $thislink['linkname']; 797 } 798 799 // ------------------------------------------------------------- 800 801 function link_url() 802 { 803 global $thislink; 804 805 assert_link(); 806 807 return doSpecial($thislink['url']); 808 } 809 810 // ------------------------------------------------------------- 811 812 function link_author($atts) 813 { 814 global $thislink, $s; 815 816 assert_link(); 817 818 extract(lAtts(array( 819 'class' => '', 820 'link' => 0, 821 'title' => 1, 822 'section' => '', 823 'this_section' => '', 824 'wraptag' => '', 825 ), $atts)); 826 827 if ($thislink['author']) { 828 $author_name = get_author_name($thislink['author']); 829 $display_name = txpspecialchars(($title) ? $author_name : $thislink['author']); 830 831 $section = ($this_section) ? ($s == 'default' ? '' : $s) : $section; 832 833 $author = ($link) 834 ? href($display_name, pagelinkurl(array('s' => $section, 'author' => $author_name, 'context' => 'link'))) 835 : $display_name; 836 837 return ($wraptag) ? doTag($author, $wraptag, $class) : $author; 838 } 839 } 840 841 // ------------------------------------------------------------- 842 843 function link_description($atts) 844 { 845 global $thislink; 846 847 assert_link(); 848 849 extract(lAtts(array( 850 'class' => '', 851 'escape' => 'html', 852 'label' => '', 853 'labeltag' => '', 854 'wraptag' => '', 855 ), $atts)); 856 857 if ($thislink['description']) { 858 $description = ($escape == 'html') ? 859 txpspecialchars($thislink['description']) : 860 $thislink['description']; 861 862 return doLabel($label, $labeltag).doTag($description, $wraptag, $class); 863 } 864 } 865 866 // ------------------------------------------------------------- 867 868 function link_date($atts) 869 { 870 global $thislink, $dateformat; 871 872 assert_link(); 873 874 extract(lAtts(array( 875 'format' => $dateformat, 876 'gmt' => '', 877 'lang' => '', 878 ), $atts)); 879 880 return safe_strftime($format, $thislink['date'], $gmt, $lang); 881 } 882 883 // ------------------------------------------------------------- 884 885 function link_category($atts) 886 { 887 global $thislink; 888 889 assert_link(); 890 891 extract(lAtts(array( 892 'class' => '', 893 'label' => '', 894 'labeltag' => '', 895 'title' => 0, 896 'wraptag' => '', 897 ), $atts)); 898 899 if ($thislink['category']) { 900 $category = ($title) 901 ? fetch_category_title($thislink['category'], 'link') 902 : $thislink['category']; 903 904 return doLabel($label, $labeltag).doTag($category, $wraptag, $class); 905 } 906 } 907 908 // ------------------------------------------------------------- 909 910 function link_id() 911 { 912 global $thislink; 913 914 assert_link(); 915 916 return $thislink['id']; 917 } 918 919 // ------------------------------------------------------------- 920 921 function email($atts, $thing = null) 922 { 923 extract(lAtts(array( 924 'email' => '', 925 'linktext' => gTxt('contact'), 926 'title' => '', 927 ), $atts)); 928 929 if ($email) { 930 if ($thing !== null) { 931 $linktext = parse($thing); 932 } 933 934 // Obfuscate link text? 935 if (is_valid_email($linktext)) { 936 $linktext = eE($linktext); 937 } 938 939 return href( 940 $linktext, 941 eE('mailto:'.$email), 942 ($title ? ' title="'.txpspecialchars($title).'"' : '') 943 ); 944 } 945 946 return ''; 947 } 948 949 // ------------------------------------------------------------- 950 951 function password_protect($atts, $thing = null) 952 { 953 ob_start(); 954 955 extract(lAtts(array( 956 'login' => null, 957 'pass' => null, 958 'privs' => null, 959 ), $atts)); 960 961 if ($pass === null) { 962 $access = ($user = is_logged_in($login)) !== false && ($privs === null || in_list($user['privs'], $privs)); 963 } else { 964 $au = serverSet('PHP_AUTH_USER'); 965 $ap = serverSet('PHP_AUTH_PW'); 966 967 // For PHP as (f)cgi, two rules in htaccess often allow this workaround. 968 $ru = serverSet('REDIRECT_REMOTE_USER'); 969 970 if (!$au && !$ap && strpos($ru, 'Basic') === 0) { 971 list($au, $ap) = explode(':', base64_decode(substr($ru, 6))); 972 } 973 974 $access = $au === $login && $ap === $pass; 975 } 976 977 if ($access === false && $pass !== null) { 978 header('WWW-Authenticate: Basic realm="Private"'); 979 } 980 981 if ($thing === null) { 982 if ($access === false) { 983 txp_die(gTxt('auth_required'), '401'); 984 } 985 986 return ''; 987 } 988 989 return parse($thing, $access); 990 } 991 992 // ------------------------------------------------------------- 993 994 function recent_articles($atts) 995 { 996 global $prefs; 997 998 $atts = lAtts(array( 999 'break' => 'br', 1000 'category' => '', 1001 'class' => __FUNCTION__, 1002 'label' => gTxt('recent_articles'), 1003 'labeltag' => '', 1004 'limit' => 10, 1005 'offset' => 0, 1006 'section' => '', 1007 'sort' => 'Posted DESC', 1008 'sortby' => '', // Deprecated. 1009 'sortdir' => '', // Deprecated. 1010 'wraptag' => '', 1011 'no_widow' => @$prefs['title_no_widow'], 1012 ), $atts); 1013 1014 $thing = '<txp:permlink><txp:title no_widow="'.($atts['no_widow'] ? '1' : '').'" /></txp:permlink>'; 1015 unset($atts['no_widow']); 1016 1017 return article_custom($atts, $thing); 1018 } 1019 1020 // ------------------------------------------------------------- 1021 1022 function recent_comments($atts, $thing = null) 1023 { 1024 global $prefs; 1025 global $thisarticle, $thiscomment; 1026 1027 extract(lAtts(array( 1028 'break' => br, 1029 'class' => __FUNCTION__, 1030 'form' => '', 1031 'label' => '', 1032 'labeltag' => '', 1033 'limit' => 10, 1034 'offset' => 0, 1035 'sort' => 'posted DESC', 1036 'wraptag' => '', 1037 ), $atts)); 1038 1039 $sort = preg_replace('/\bposted\b/', 'd.posted', $sort); 1040 $expired = ($prefs['publish_expired_articles']) ? '' : " AND (".now('expires')." <= t.Expires OR t.Expires IS NULL) "; 1041 1042 $rs = startRows("SELECT d.name, d.email, d.web, d.message, d.discussid, UNIX_TIMESTAMP(d.Posted) AS time, 1043 t.ID AS thisid, UNIX_TIMESTAMP(t.Posted) AS posted, t.Title AS title, t.Section AS section, t.url_title 1044 FROM ".safe_pfx('txp_discuss')." AS d INNER JOIN ".safe_pfx('textpattern')." AS t ON d.parentid = t.ID 1045 WHERE t.Status >= ".STATUS_LIVE.$expired." AND d.visible = ".VISIBLE." 1046 ORDER BY ".doSlash($sort)." 1047 LIMIT ".intval($offset).", ".intval($limit)); 1048 1049 if ($rs) { 1050 $out = array(); 1051 $old_article = $thisarticle; 1052 1053 while ($c = nextRow($rs)) { 1054 if ($form === '' && $thing === null) { 1055 $out[] = href( 1056 txpspecialchars($c['name']).' ('.escape_title($c['title']).')', 1057 permlinkurl($c).'#c'.$c['discussid'] 1058 ); 1059 } else { 1060 $thiscomment['name'] = $c['name']; 1061 $thiscomment['email'] = $c['email']; 1062 $thiscomment['web'] = $c['web']; 1063 $thiscomment['message'] = $c['message']; 1064 $thiscomment['discussid'] = $c['discussid']; 1065 $thiscomment['time'] = $c['time']; 1066 1067 // Allow permlink guesstimation in permlinkurl(), elsewhere. 1068 $thisarticle['thisid'] = $c['thisid']; 1069 $thisarticle['posted'] = $c['posted']; 1070 $thisarticle['title'] = $c['title']; 1071 $thisarticle['section'] = $c['section']; 1072 $thisarticle['url_title'] = $c['url_title']; 1073 1074 if ($thing === null && $form !== '') { 1075 $out[] = parse_form($form); 1076 } else { 1077 $out[] = parse($thing); 1078 } 1079 } 1080 } 1081 1082 if ($out) { 1083 unset($GLOBALS['thiscomment']); 1084 $thisarticle = $old_article; 1085 1086 return doLabel($label, $labeltag).doWrap($out, $wraptag, $break, $class); 1087 } 1088 } 1089 1090 return ''; 1091 } 1092 1093 // ------------------------------------------------------------- 1094 1095 function related_articles($atts, $thing = null) 1096 { 1097 global $thisarticle, $prefs; 1098 1099 assert_article(); 1100 1101 $atts = lAtts(array( 1102 'break' => br, 1103 'class' => __FUNCTION__, 1104 'form' => '', 1105 'label' => '', 1106 'labeltag' => '', 1107 'limit' => 10, 1108 'offset' => 0, 1109 'match' => 'Category1,Category2', 1110 'no_widow' => @$prefs['title_no_widow'], 1111 'section' => '', 1112 'sort' => 'Posted DESC', 1113 'wraptag' => '', 1114 ), $atts); 1115 1116 $match = array_intersect(do_list_unique(strtolower($atts['match'])), array_merge(array('category1', 'category2', 'author', 'keywords'), getCustomFields())); 1117 $categories = $cats = array(); 1118 1119 foreach ($match as $cf) { 1120 switch ($cf) { 1121 case 'category1': 1122 case 'category2': 1123 if (!empty($thisarticle[$cf])) { 1124 $cats[] = $thisarticle[$cf]; 1125 } 1126 1127 $categories[] = ucwords($cf); 1128 break; 1129 case 'author': 1130 $atts['author'] = $thisarticle['authorid']; 1131 break; 1132 default: 1133 if (empty($thisarticle[$cf])) { 1134 return; 1135 } 1136 1137 $atts[$cf] = $thisarticle[$cf]; 1138 break; 1139 } 1140 } 1141 1142 if (!empty($cats)) { 1143 $atts['category'] = implode(',', $cats); 1144 } elseif ($categories) { 1145 return; 1146 } 1147 1148 $atts['match'] = implode(',', $categories); 1149 $atts['exclude'] = $thisarticle['thisid']; 1150 1151 if ($atts['form'] === '' && $thing === null) { 1152 $thing = '<txp:permlink><txp:title no_widow="'.($atts['no_widow'] ? '1' : '').'" /></txp:permlink>'; 1153 } 1154 1155 unset($atts['no_widow']); 1156 1157 return article_custom($atts, $thing); 1158 } 1159 1160 // ------------------------------------------------------------- 1161 1162 function popup($atts) 1163 { 1164 global $s, $c, $permlink_mode; 1165 1166 extract(lAtts(array( 1167 'label' => gTxt('browse'), 1168 'wraptag' => '', 1169 'class' => '', 1170 'section' => '', 1171 'this_section' => 0, 1172 'type' => 'category', 1173 ), $atts)); 1174 1175 $type = substr($type, 0, 1); 1176 1177 if ($type == 's') { 1178 $rs = safe_rows_start("name, title", 'txp_section', "name != 'default' ORDER BY name"); 1179 } else { 1180 $rs = safe_rows_start("name, title", 'txp_category', "type = 'article' AND name != 'root' ORDER BY name"); 1181 } 1182 1183 if ($rs) { 1184 $out = array(); 1185 1186 $current = ($type == 's') ? $s : $c; 1187 1188 $sel = ''; 1189 $selected = false; 1190 1191 while ($a = nextRow($rs)) { 1192 extract($a); 1193 1194 if ($name == $current) { 1195 $sel = ' selected="selected"'; 1196 $selected = true; 1197 } 1198 1199 $out[] = '<option value="'.$name.'"'.$sel.'>'.txpspecialchars($title).'</option>'; 1200 1201 $sel = ''; 1202 } 1203 1204 if ($out) { 1205 $section = ($this_section) ? ($s == 'default' ? '' : $s) : $section; 1206 1207 $out = n.'<select name="'.txpspecialchars($type).'" onchange="submit(this.form);">'. 1208 n.t.'<option value=""'.($selected ? '' : ' selected="selected"').'> </option>'. 1209 n.t.join(n.t, $out). 1210 n.'</select>'; 1211 1212 if ($label) { 1213 $out = $label.br.$out; 1214 } 1215 1216 if ($wraptag) { 1217 $out = doTag($out, $wraptag, $class); 1218 } 1219 1220 if (($type == 's' || $permlink_mode == 'messy')) { 1221 $action = hu; 1222 $his = ($section !== '') ? n.hInput('s', $section) : ''; 1223 } else { 1224 // Clean URLs for category popup. 1225 $action = pagelinkurl(array('s' => $section)); 1226 $his = ''; 1227 } 1228 1229 return '<form method="get" action="'.$action.'">'. 1230 '<div>'. 1231 $his. 1232 n.$out. 1233 n.'<noscript><div><input type="submit" value="'.gTxt('go').'" /></div></noscript>'. 1234 n.'</div>'. 1235 n.'</form>'; 1236 } 1237 } 1238 } 1239 1240 // ------------------------------------------------------------- 1241 1242 // Output href list of site categories. 1243 function category_list($atts, $thing = null) 1244 { 1245 global $s, $c, $thiscategory; 1246 1247 extract(lAtts(array( 1248 'active_class' => '', 1249 'break' => br, 1250 'categories' => '', 1251 'class' => __FUNCTION__, 1252 'exclude' => '', 1253 'form' => '', 1254 'html_id' => '', 1255 'label' => '', 1256 'labeltag' => '', 1257 'parent' => '', 1258 'section' => '', 1259 'children' => '1', 1260 'sort' => '', 1261 'this_section' => 0, 1262 'type' => 'article', 1263 'wraptag' => '', 1264 'limit' => '', 1265 'offset' => '', 1266 ), $atts)); 1267 1268 $sort = doSlash($sort); 1269 $sql_limit = ''; 1270 1271 if ($limit !== '' || $offset) { 1272 $sql_limit = " LIMIT ".intval($offset).", ".($limit === '' ? PHP_INT_MAX : intval($limit)); 1273 } 1274 1275 if ($categories) { 1276 $categories = do_list_unique($categories); 1277 $categories = join("','", doSlash($categories)); 1278 1279 $rs = safe_rows_start("name, title, description", 'txp_category', 1280 "type = '".doSlash($type)."' AND name IN ('$categories') ORDER BY ".($sort ? $sort : "FIELD(name, '$categories')").$sql_limit); 1281 } else { 1282 if ($parent) { 1283 $parents = join(',', quote_list(do_list_unique($parent))); 1284 } 1285 1286 if ($children) { 1287 $shallow = ''; 1288 } else { 1289 // Descend only one level from either 'parent' or 'root', plus 1290 // parent category. 1291 $shallow = ($parent) ? "AND (parent IN ($parents) OR name IN ($parents))" : "AND parent = 'root'"; 1292 } 1293 1294 if ($exclude) { 1295 $exclude = do_list_unique($exclude); 1296 $exclude = join("','", doSlash($exclude)); 1297 $exclude = "AND name NOT IN ('$exclude')"; 1298 } 1299 1300 if ($parent) { 1301 $qs = safe_rows("lft, rgt", 'txp_category', "type = '".doSlash($type)."' AND name IN ($parents)"); 1302 1303 if ($qs) { 1304 $between = array(); 1305 1306 foreach ($qs as $a) { 1307 extract($a); 1308 $between[] = "(lft BETWEEN $lft AND $rgt)"; 1309 } 1310 1311 $rs = safe_rows_start("name, title, description", 'txp_category', 1312 "(".join(" OR ", $between).") AND type = '".doSlash($type)."' AND name != 'default' $exclude $shallow ORDER BY ".($sort ? $sort : "lft ASC").$sql_limit); 1313 } else { 1314 $rs = array(); 1315 } 1316 } else { 1317 $rs = safe_rows_start("name, title, description", 'txp_category', 1318 "type = '".doSlash($type)."' AND name NOT IN ('default','root') $exclude $shallow ORDER BY ".($sort ? $sort : "name ASC").$sql_limit); 1319 } 1320 } 1321 1322 if ($rs) { 1323 $out = array(); 1324 $count = 0; 1325 $last = numRows($rs); 1326 1327 if (isset($thiscategory)) { 1328 $old_category = $thiscategory; 1329 } 1330 1331 while ($a = nextRow($rs)) { 1332 ++$count; 1333 extract($a); 1334 1335 if ($name) { 1336 $section = ($this_section) ? ($s == 'default' ? '' : $s) : $section; 1337 1338 if ($form === '' && $thing === null) { 1339 $out[] = tag(txpspecialchars($title), 'a', 1340 (($active_class and (0 == strcasecmp($c, $name))) ? ' class="'.txpspecialchars($active_class).'"' : ''). 1341 ' href="'.pagelinkurl(array('s' => $section, 'c' => $name, 'context' => $type)).'"' 1342 ); 1343 } else { 1344 $thiscategory = array('name' => $name, 'title' => $title, 'type' => $type, 'description' => $description); 1345 $thiscategory['is_first'] = ($count == 1); 1346 $thiscategory['is_last'] = ($count == $last); 1347 1348 if (isset($atts['section'])) { 1349 $thiscategory['section'] = $section; 1350 } 1351 1352 if ($thing === null && $form !== '') { 1353 $out[] = parse_form($form); 1354 } else { 1355 $out[] = parse($thing); 1356 } 1357 } 1358 } 1359 } 1360 1361 $thiscategory = (isset($old_category) ? $old_category : null); 1362 1363 if ($out) { 1364 return doLabel($label, $labeltag).doWrap($out, $wraptag, $break, $class, '', '', '', $html_id); 1365 } 1366 } 1367 1368 return ''; 1369 } 1370 1371 // ------------------------------------------------------------- 1372 1373 // Output href list of site sections. 1374 function section_list($atts, $thing = null) 1375 { 1376 global $sitename, $s, $thissection; 1377 1378 extract(lAtts(array( 1379 'active_class' => '', 1380 'break' => br, 1381 'class' => __FUNCTION__, 1382 'default_title' => $sitename, 1383 'exclude' => '', 1384 'form' => '', 1385 'html_id' => '', 1386 'include_default' => '', 1387 'label' => '', 1388 'labeltag' => '', 1389 'sections' => '', 1390 'sort' => '', 1391 'wraptag' => '', 1392 'offset' => '', 1393 'limit' => '', 1394 ), $atts)); 1395 1396 $sql_limit = ''; 1397 $sql_sort = doSlash($sort); 1398 $sql = array(); 1399 $sql[] = 1; 1400 1401 if ($limit !== '' || $offset) { 1402 $sql_limit = " LIMIT ".intval($offset).", ".($limit === '' ? PHP_INT_MAX : intval($limit)); 1403 } 1404 1405 if ($sections) { 1406 if ($include_default) { 1407 $sections .= ', default'; 1408 } 1409 1410 $sections = join(',', quote_list(do_list_unique($sections))); 1411 $sql[] = "name IN ($sections)"; 1412 1413 if (!$sql_sort) { 1414 $sql_sort = "FIELD(name, $sections)"; 1415 } 1416 } else { 1417 if ($exclude) { 1418 $exclude = join(',', quote_list(do_list_unique($exclude))); 1419 $sql[] = "name NOT IN ($exclude)"; 1420 } 1421 1422 if (!$include_default) { 1423 $sql[] = "name != 'default'"; 1424 } 1425 1426 if (!$sql_sort) { 1427 $sql_sort = "name ASC"; 1428 } 1429 } 1430 1431 if ($include_default) { 1432 $sql_sort = "name != 'default', ".$sql_sort; 1433 } 1434 1435 $rs = safe_rows_start( 1436 "name, title, description", 1437 'txp_section', 1438 join(" AND ", $sql)." ORDER BY ".$sql_sort.$sql_limit 1439 ); 1440 1441 if ($rs && $last = numRows($rs)) { 1442 $out = array(); 1443 $count = 0; 1444 1445 if (isset($thissection)) { 1446 $old_section = $thissection; 1447 } 1448 1449 while ($a = nextRow($rs)) { 1450 ++$count; 1451 extract($a); 1452 1453 if ($name == 'default') { 1454 $title = $default_title; 1455 } 1456 1457 if ($form === '' && $thing === null) { 1458 $url = pagelinkurl(array('s' => $name)); 1459 1460 $out[] = tag(txpspecialchars($title), 'a', 1461 (($active_class and (0 == strcasecmp($s, $name))) ? ' class="'.txpspecialchars($active_class).'"' : ''). 1462 ' href="'.$url.'"' 1463 ); 1464 } else { 1465 $thissection = array( 1466 'name' => $name, 1467 'title' => $title, 1468 'description' => $description, 1469 'is_first' => ($count == 1), 1470 'is_last' => ($count == $last), 1471 ); 1472 1473 if ($thing === null && $form !== '') { 1474 $out[] = parse_form($form); 1475 } else { 1476 $out[] = parse($thing); 1477 } 1478 } 1479 } 1480 1481 $thissection = isset($old_section) ? $old_section : null; 1482 1483 if ($out) { 1484 return doLabel($label, $labeltag).doWrap($out, $wraptag, $break, $class, '', '', '', $html_id); 1485 } 1486 } 1487 1488 return ''; 1489 } 1490 1491 // ------------------------------------------------------------- 1492 1493 // Input form for search queries. 1494 function search_input($atts) 1495 { 1496 global $q, $permlink_mode, $doctype; 1497 1498 extract(lAtts(array( 1499 'form' => 'search_input', 1500 'wraptag' => 'p', 1501 'class' => __FUNCTION__, 1502 'size' => '15', 1503 'html_id' => '', 1504 'label' => gTxt('search'), 1505 'button' => '', 1506 'section' => '', 1507 'match' => 'exact', 1508 ), $atts)); 1509 1510 if ($form and !array_diff_key($atts, array('form' => true))) { 1511 $rs = fetch_form($form); 1512 1513 if ($rs) { 1514 return parse($rs); 1515 } 1516 } 1517 1518 $h5 = ($doctype == 'html5'); 1519 $sub = (!empty($button)) ? '<input type="submit" value="'.txpspecialchars($button).'" />' : ''; 1520 $id = (!empty($html_id)) ? ' id="'.txpspecialchars($html_id).'"' : ''; 1521 $out = fInput($h5 ? 'search' : 'text', 'q', $q, '', '', '', $size, '', '', false, $h5); 1522 $out = (!empty($label)) ? txpspecialchars($label).br.$out.$sub : $out.$sub; 1523 $out = ($match === 'exact') ? $out : fInput('hidden', 'm', txpspecialchars($match)).$out; 1524 $out = ($wraptag) ? doTag($out, $wraptag, $class) : $out; 1525 1526 if (!$section) { 1527 return '<form method="get" action="'.hu.'"'.$id.'>'. 1528 n.$out. 1529 n.'</form>'; 1530 } 1531 1532 if ($permlink_mode != 'messy') { 1533 return '<form method="get" action="'.pagelinkurl(array('s' => $section)).'"'.$id.'>'. 1534 n.$out. 1535 n.'</form>'; 1536 } 1537 1538 return '<form method="get" action="'.hu.'"'.$id.'>'. 1539 n.hInput('s', $section). 1540 n.$out. 1541 n.'</form>'; 1542 } 1543 1544 // ------------------------------------------------------------- 1545 1546 function search_term($atts) 1547 { 1548 global $q; 1549 1550 if (empty($q)) { 1551 return ''; 1552 } 1553 1554 extract(lAtts(array( 1555 'escape' => 'html', // Deprecated in 4.5.0. 1556 ), $atts)); 1557 1558 if (isset($atts['escape'])) { 1559 trigger_error(gTxt('deprecated_attribute', array('{name}' => 'escape')), E_USER_NOTICE); 1560 } 1561 1562 // TODO: Remove deprecated attribute 'escape'. 1563 return ($escape == 'html' ? txpspecialchars($q) : $q); 1564 } 1565 1566 // ------------------------------------------------------------- 1567 1568 // Link to next article, if it exists. 1569 function link_to_next($atts, $thing = null) 1570 { 1571 global $thisarticle; 1572 1573 assert_article(); 1574 1575 extract(lAtts(array( 1576 'showalways' => 0, 1577 ), $atts)); 1578 1579 if (is_array($thisarticle)) { 1580 if (!isset($thisarticle['next'])) { 1581 $thisarticle = $thisarticle + getNextPrev(); 1582 } 1583 1584 if ($thisarticle['next'] !== false) { 1585 $url = permlinkurl($thisarticle['next']); 1586 1587 if ($thing) { 1588 $thing = parse($thing); 1589 $next_title = escape_title($thisarticle['next']['title']); 1590 1591 return href( 1592 $thing, 1593 $url, 1594 ($next_title != $thing ? ' title="'.$next_title.'"' : ''). 1595 ' rel="next"' 1596 ); 1597 } 1598 1599 return $url; 1600 } 1601 } 1602 1603 return ($showalways) ? parse($thing) : ''; 1604 } 1605 1606 // ------------------------------------------------------------- 1607 1608 // Link to previous article, if it exists. 1609 function link_to_prev($atts, $thing = null) 1610 { 1611 global $thisarticle; 1612 1613 assert_article(); 1614 1615 extract(lAtts(array( 1616 'showalways' => 0, 1617 ), $atts)); 1618 1619 if (is_array($thisarticle)) { 1620 if (!isset($thisarticle['prev'])) { 1621 $thisarticle = $thisarticle + getNextPrev(); 1622 } 1623 1624 if ($thisarticle['prev'] !== false) { 1625 $url = permlinkurl($thisarticle['prev']); 1626 1627 if ($thing) { 1628 $thing = parse($thing); 1629 $prev_title = escape_title($thisarticle['prev']['title']); 1630 1631 return href( 1632 $thing, 1633 $url, 1634 ($prev_title != $thing ? ' title="'.$prev_title.'"' : ''). 1635 ' rel="prev"' 1636 ); 1637 } 1638 1639 return $url; 1640 } 1641 } 1642 1643 return ($showalways) ? parse($thing) : ''; 1644 } 1645 1646 // ------------------------------------------------------------- 1647 1648 function next_title() 1649 { 1650 global $thisarticle; 1651 1652 assert_article(); 1653 1654 if (!is_array($thisarticle)) { 1655 return ''; 1656 } 1657 1658 if (!isset($thisarticle['next'])) { 1659 $thisarticle = $thisarticle + getNextPrev(); 1660 } 1661 1662 if ($thisarticle['next'] !== false) { 1663 return escape_title($thisarticle['next']['title']); 1664 } else { 1665 return ''; 1666 } 1667 } 1668 1669 // ------------------------------------------------------------- 1670 1671 function prev_title() 1672 { 1673 global $thisarticle; 1674 1675 assert_article(); 1676 1677 if (!is_array($thisarticle)) { 1678 return ''; 1679 } 1680 1681 if (!isset($thisarticle['prev'])) { 1682 $thisarticle = $thisarticle + getNextPrev(); 1683 } 1684 1685 if ($thisarticle['prev'] !== false) { 1686 return escape_title($thisarticle['prev']['title']); 1687 } else { 1688 return ''; 1689 } 1690 } 1691 1692 // ------------------------------------------------------------- 1693 1694 function site_name() 1695 { 1696 global $sitename; 1697 1698 return txpspecialchars($sitename); 1699 } 1700 1701 // ------------------------------------------------------------- 1702 1703 function site_slogan() 1704 { 1705 global $site_slogan; 1706 1707 return txpspecialchars($site_slogan); 1708 } 1709 1710 // ------------------------------------------------------------- 1711 1712 function link_to_home($atts, $thing = null) 1713 { 1714 extract(lAtts(array( 1715 'class' => false, 1716 ), $atts)); 1717 1718 if ($thing) { 1719 $class = ($class) ? ' class="'.txpspecialchars($class).'"' : ''; 1720 1721 return href( 1722 parse($thing), 1723 hu, 1724 $class. 1725 ' rel="home"' 1726 ); 1727 } 1728 1729 return hu; 1730 } 1731 1732 // ------------------------------------------------------------- 1733 1734 function newer($atts, $thing = null) 1735 { 1736 global $thispage, $pretext, $m; 1737 1738 extract(lAtts(array( 1739 'showalways' => 0, 1740 'title' => '', 1741 'escape' => 'html', 1742 ), $atts)); 1743 1744 $numPages = $thispage['numPages']; 1745 $pg = $thispage['pg']; 1746 1747 if ($numPages > 1 and $pg > 1 and $pg <= $numPages) { 1748 $nextpg = ($pg - 1 == 1) ? '' : ($pg - 1); 1749 1750 // Author URLs should use RealName, rather than username. 1751 if (!empty($pretext['author'])) { 1752 $author = get_author_name($pretext['author']); 1753 } else { 1754 $author = ''; 1755 } 1756 1757 $url = pagelinkurl(array( 1758 'month' => @$pretext['month'], 1759 'pg' => $nextpg, 1760 's' => @$pretext['s'], 1761 'c' => @$pretext['c'], 1762 'context' => @$pretext['context'], 1763 'q' => @$pretext['q'], 1764 'm' => @$m, 1765 'author' => $author, 1766 )); 1767 1768 if ($thing) { 1769 if ($escape == 'html') { 1770 $title = escape_title($title); 1771 } 1772 1773 return href( 1774 parse($thing), 1775 $url, 1776 (empty($title) ? '' : ' title="'.$title.'"') 1777 ); 1778 } 1779 1780 return $url; 1781 } 1782 1783 return ($showalways) ? parse($thing) : ''; 1784 } 1785 1786 // ------------------------------------------------------------- 1787 1788 function older($atts, $thing = null) 1789 { 1790 global $thispage, $pretext, $m; 1791 1792 extract(lAtts(array( 1793 'showalways' => 0, 1794 'title' => '', 1795 'escape' => 'html', 1796 ), $atts)); 1797 1798 $numPages = $thispage['numPages']; 1799 $pg = $thispage['pg']; 1800 1801 if ($numPages > 1 and $pg > 0 and $pg < $numPages) { 1802 $nextpg = $pg + 1; 1803 1804 // Author URLs should use RealName, rather than username. 1805 if (!empty($pretext['author'])) { 1806 $author = get_author_name($pretext['author']); 1807 } else { 1808 $author = ''; 1809 } 1810 1811 $url = pagelinkurl(array( 1812 'month' => @$pretext['month'], 1813 'pg' => $nextpg, 1814 's' => @$pretext['s'], 1815 'c' => @$pretext['c'], 1816 'context' => @$pretext['context'], 1817 'q' => @$pretext['q'], 1818 'm' => @$m, 1819 'author' => $author, 1820 )); 1821 1822 if ($thing) { 1823 if ($escape == 'html') { 1824 $title = escape_title($title); 1825 } 1826 1827 return href( 1828 parse($thing), 1829 $url, 1830 (empty($title) ? '' : ' title="'.$title.'"') 1831 ); 1832 } 1833 1834 return $url; 1835 } 1836 1837 return ($showalways) ? parse($thing) : ''; 1838 } 1839 1840 // ------------------------------------------------------------- 1841 1842 function text($atts) 1843 { 1844 extract(lAtts(array( 1845 'item' => '', 1846 'escape' => 'html', 1847 ), $atts, false)); 1848 1849 if (!$item) { 1850 return; 1851 } 1852 1853 unset( 1854 $atts['item'], 1855 $atts['escape'] 1856 ); 1857 1858 $tags = array(); 1859 1860 foreach ($atts as $name => $value) { 1861 $tags['{'.$name.'}'] = $value; 1862 } 1863 1864 return gTxt($item, $tags, $escape); 1865 } 1866 1867 // ------------------------------------------------------------- 1868 1869 function article_id() 1870 { 1871 global $thisarticle; 1872 1873 assert_article(); 1874 1875 return $thisarticle['thisid']; 1876 } 1877 1878 // ------------------------------------------------------------- 1879 1880 function article_url_title() 1881 { 1882 global $thisarticle; 1883 1884 assert_article(); 1885 1886 return $thisarticle['url_title']; 1887 } 1888 1889 // ------------------------------------------------------------- 1890 1891 function if_article_id($atts, $thing) 1892 { 1893 global $thisarticle, $pretext; 1894 1895 assert_article(); 1896 1897 extract(lAtts(array( 1898 'id' => $pretext['id'], 1899 ), $atts)); 1900 1901 if ($id) { 1902 return parse($thing, in_list($thisarticle['thisid'], $id)); 1903 } 1904 } 1905 1906 // ------------------------------------------------------------- 1907 1908 function posted($atts) 1909 { 1910 global $thisarticle, $id, $c, $pg, $dateformat, $archive_dateformat; 1911 1912 assert_article(); 1913 1914 extract(lAtts(array( 1915 'class' => '', 1916 'format' => '', 1917 'gmt' => '', 1918 'lang' => '', 1919 'wraptag' => '', 1920 ), $atts)); 1921 1922 if ($format) { 1923 $out = safe_strftime($format, $thisarticle['posted'], $gmt, $lang); 1924 } else { 1925 if ($id or $c or $pg) { 1926 $out = safe_strftime($archive_dateformat, $thisarticle['posted'], $gmt, $lang); 1927 } else { 1928 $out = safe_strftime($dateformat, $thisarticle['posted'], $gmt, $lang); 1929 } 1930 } 1931 1932 return ($wraptag) ? doTag($out, $wraptag, $class) : $out; 1933 } 1934 1935 // ------------------------------------------------------------- 1936 1937 function expires($atts) 1938 { 1939 global $thisarticle, $id, $c, $pg, $dateformat, $archive_dateformat; 1940 1941 assert_article(); 1942 1943 if ($thisarticle['expires'] == 0) { 1944 return; 1945 } 1946 1947 extract(lAtts(array( 1948 'class' => '', 1949 'format' => '', 1950 'gmt' => '', 1951 'lang' => '', 1952 'wraptag' => '', 1953 ), $atts)); 1954 1955 if ($format) { 1956 $out = safe_strftime($format, $thisarticle['expires'], $gmt, $lang); 1957 } else { 1958 if ($id or $c or $pg) { 1959 $out = safe_strftime($archive_dateformat, $thisarticle['expires'], $gmt, $lang); 1960 } else { 1961 $out = safe_strftime($dateformat, $thisarticle['expires'], $gmt, $lang); 1962 } 1963 } 1964 1965 return ($wraptag) ? doTag($out, $wraptag, $class) : $out; 1966 } 1967 1968 // ------------------------------------------------------------- 1969 1970 function if_expires($atts, $thing) 1971 { 1972 global $thisarticle; 1973 1974 assert_article(); 1975 1976 return parse($thing, !empty($thisarticle['expires'])); 1977 } 1978 1979 // ------------------------------------------------------------- 1980 1981 function if_expired($atts, $thing) 1982 { 1983 global $thisarticle; 1984 1985 assert_article(); 1986 1987 return parse($thing, 1988 !empty($thisarticle['expires']) && ($thisarticle['expires'] <= time())); 1989 } 1990 1991 // ------------------------------------------------------------- 1992 1993 function modified($atts) 1994 { 1995 global $thisarticle, $id, $c, $pg, $dateformat, $archive_dateformat; 1996 1997 assert_article(); 1998 1999 extract(lAtts(array( 2000 'class' => '', 2001 'format' => '', 2002 'gmt' => '', 2003 'lang' => '', 2004 'wraptag' => '', 2005 ), $atts)); 2006 2007 if ($format) { 2008 $out = safe_strftime($format, $thisarticle['modified'], $gmt, $lang); 2009 } else { 2010 if ($id or $c or $pg) { 2011 $out = safe_strftime($archive_dateformat, $thisarticle['modified'], $gmt, $lang); 2012 } else { 2013 $out = safe_strftime($dateformat, $thisarticle['modified'], $gmt, $lang); 2014 } 2015 } 2016 2017 return ($wraptag) ? doTag($out, $wraptag, $class) : $out; 2018 } 2019 2020 // ------------------------------------------------------------- 2021 2022 function comments_count() 2023 { 2024 global $thisarticle; 2025 2026 assert_article(); 2027 2028 return $thisarticle['comments_count']; 2029 } 2030 2031 // ------------------------------------------------------------- 2032 2033 function comments_invite($atts) 2034 { 2035 global $thisarticle, $is_article_list; 2036 2037 assert_article(); 2038 2039 extract($thisarticle); 2040 global $comments_mode; 2041 2042 if (!$comments_invite) { 2043 $comments_invite = get_pref('comments_default_invite'); 2044 } 2045 2046 extract(lAtts(array( 2047 'class' => __FUNCTION__, 2048 'showcount' => true, 2049 'textonly' => false, 2050 'showalways' => false, // FIXME in crockery. This is only for BC. 2051 'wraptag' => '', 2052 ), $atts)); 2053 2054 $invite_return = ''; 2055 2056 if (($annotate or $comments_count) && ($showalways or $is_article_list)) { 2057 $comments_invite = txpspecialchars($comments_invite); 2058 $ccount = ($comments_count && $showcount) ? ' ['.$comments_count.']' : ''; 2059 2060 if ($textonly) { 2061 $invite_return = $comments_invite.$ccount; 2062 } else { 2063 if (!$comments_mode) { 2064 $invite_return = doTag($comments_invite, 'a', $class, ' href="'.permlinkurl($thisarticle).'#'.gTxt('comment').'" ').$ccount; 2065 } else { 2066 $invite_return = "<a href=\"".hu."?parentid=$thisid\" onclick=\"window.open(this.href, 'popupwindow', 'width=500,height=500,scrollbars,resizable,status'); return false;\"".(($class) ? ' class="'.txpspecialchars($class).'"' : '').'>'.$comments_invite.'</a> '.$ccount; 2067 } 2068 } 2069 2070 if ($wraptag) { 2071 $invite_return = doTag($invite_return, $wraptag, $class); 2072 } 2073 } 2074 2075 return $invite_return; 2076 } 2077 2078 // ------------------------------------------------------------- 2079 2080 function popup_comments($atts, $thing = null) 2081 { 2082 extract(lAtts(array( 2083 'form' => 'comments_display' 2084 ), $atts)); 2085 2086 $rs = safe_row( 2087 "*, UNIX_TIMESTAMP(Posted) AS uPosted, UNIX_TIMESTAMP(LastMod) AS uLastMod, UNIX_TIMESTAMP(Expires) AS uExpires", 2088 'textpattern', 2089 "ID=".intval(gps('parentid'))." AND Status >= 4" 2090 ); 2091 2092 if ($rs) { 2093 populateArticleData($rs); 2094 return ($thing === null ? parse_form($form) : parse($thing)); 2095 } 2096 2097 return ''; 2098 } 2099 2100 // ------------------------------------------------------------- 2101 2102 function comments_form($atts, $thing = null) 2103 { 2104 global $thisarticle, $has_comments_preview; 2105 global $thiscommentsform; // TODO: Remove any uses of $thiscommentsform when removing deprecated attributes from below. 2106 2107 // deprecated attributes since TXP 4.6. Most of these (except msgstyle) 2108 // were moved to the tags that occur within a comments_form, although 2109 // some of the names changed. 2110 $deprecated = array('isize', 'msgrows', 'msgcols', 'msgstyle', 2111 'previewlabel', 'submitlabel', 'rememberlabel', 'forgetlabel'); 2112 2113 foreach ($deprecated as $att) { 2114 if (isset($atts[$att])) { 2115 trigger_error(gTxt('deprecated_attribute', array('{name}' => $att)), E_USER_NOTICE); 2116 } 2117 } 2118 2119 $atts = lAtts(array( 2120 'class' => __FUNCTION__, 2121 'form' => 'comment_form', 2122 'isize' => '25', 2123 'msgcols' => '25', 2124 'msgrows' => '5', 2125 'msgstyle' => '', 2126 'show_preview' => empty($has_comments_preview), 2127 'wraptag' => '', 2128 'previewlabel' => gTxt('preview'), 2129 'submitlabel' => gTxt('submit'), 2130 'rememberlabel' => gTxt('remember'), 2131 'forgetlabel' => gTxt('forget'), 2132 ), $atts); 2133 2134 extract($atts); 2135 2136 $thiscommentsform = array_intersect_key($atts, array_flip($deprecated)); 2137 2138 assert_article(); 2139 2140 extract($thisarticle); 2141 2142 $out = ''; 2143 $ip = serverset('REMOTE_ADDR'); 2144 $blacklisted = is_blacklisted($ip); 2145 2146 if (!checkCommentsAllowed($thisid)) { 2147 $out = graf(gTxt("comments_closed"), ' id="comments_closed"'); 2148 } elseif ($blacklisted) { 2149 $out = graf(gTxt('your_ip_is_blacklisted_by'.' '.$blacklisted), ' id="comments_blacklisted"'); 2150 } elseif (gps('commented') !== '') { 2151 $out = gTxt("comment_posted"); 2152 2153 if (gps('commented') === '0') { 2154 $out .= " ".gTxt("comment_moderated"); 2155 } 2156 2157 $out = graf($out, ' id="txpCommentInputForm"'); 2158 } else { 2159 // Display a comment preview if required. 2160 if (ps('preview') and $show_preview) { 2161 $out = comments_preview(array()); 2162 } 2163 2164 extract(doDeEnt(psa(array( 2165 'parentid', 2166 'backpage', 2167 )))); 2168 2169 // If the form fields are filled (anything other than blank), pages really 2170 // should not be saved by a public cache (rfc2616/14.9.1). 2171 if (pcs('name') || pcs('email') || pcs('web')) { 2172 header('Cache-Control: private'); 2173 } 2174 2175 $url = $GLOBALS['pretext']['request_uri']; 2176 2177 // Experimental clean URLs with only 404-error-document on Apache possibly 2178 // requires messy URLs for POST requests. 2179 if (defined('PARTLY_MESSY') and (PARTLY_MESSY)) { 2180 $url = hu.'?id='.intval($parentid); 2181 } 2182 2183 $out .= '<form id="txpCommentInputForm" method="post" action="'.txpspecialchars($url).'#cpreview">'. 2184 n.'<div class="comments-wrapper">'.n. // Prevent XHTML Strict validation gotchas. 2185 ($thing === null ? parse_form($form) : parse($thing)). 2186 n.hInput('parentid', ($parentid ? $parentid : $thisid)). 2187 n.hInput('backpage', (ps('preview') ? $backpage : $url)). 2188 n.'</div>'. 2189 n.'</form>'; 2190 } 2191 2192 return (!$wraptag ? $out : doTag($out, $wraptag, $class)); 2193 } 2194 2195 // ------------------------------------------------------------- 2196 2197 function comment_name_input($atts) 2198 { 2199 global $prefs, $thiscommentsform; 2200 2201 extract(lAtts(array( 2202 'size' => $thiscommentsform['isize'] 2203 ), $atts)); 2204 2205 $namewarn = false; 2206 $name = pcs('name'); 2207 $h5 = ($prefs['doctype'] == 'html5'); 2208 2209 if (ps('preview')) { 2210 $comment = getComment(); 2211 $name = $comment['name']; 2212 $namewarn = ($prefs['comments_require_name'] && !$name); 2213 } 2214 2215 return fInput('text', 'name', $name, 'comment_name_input'.($namewarn ? ' comments_error' : ''), '', '', $size, '', 'name', false, $h5 && $prefs['comments_require_name']); 2216 } 2217 2218 // ------------------------------------------------------------- 2219 2220 function comment_email_input($atts) 2221 { 2222 global $prefs, $thiscommentsform; 2223 2224 extract(lAtts(array( 2225 'size' => $thiscommentsform['isize'] 2226 ), $atts)); 2227 2228 $emailwarn = false; 2229 $email = clean_url(pcs('email')); 2230 $h5 = ($prefs['doctype'] == 'html5'); 2231 2232 if (ps('preview')) { 2233 $comment = getComment(); 2234 $email = $comment['email']; 2235 $emailwarn = ($prefs['comments_require_email'] && !$email); 2236 } 2237 2238 return fInput($h5 ? 'email' : 'text', 'email', $email, 'comment_email_input'.($emailwarn ? ' comments_error' : ''), '', '', $size, '', 'email', false, $h5 && $prefs['comments_require_email']); 2239 } 2240 2241 // ------------------------------------------------------------- 2242 2243 function comment_web_input($atts) 2244 { 2245 global $prefs, $thiscommentsform; 2246 2247 extract(lAtts(array( 2248 'size' => $thiscommentsform['isize'] 2249 ), $atts)); 2250 2251 $web = clean_url(pcs('web')); 2252 $h5 = ($prefs['doctype'] == 'html5'); 2253 2254 if (ps('preview')) { 2255 $comment = getComment(); 2256 $web = $comment['web']; 2257 } 2258 2259 return fInput($h5 ? 'text' : 'text', 'web', $web, 'comment_web_input', '', '', $size, '', 'web', false, false); /* TODO: maybe use type = 'url' once browsers are less strict */ 2260 } 2261 2262 // ------------------------------------------------------------- 2263 2264 function comment_message_input($atts) 2265 { 2266 global $prefs, $thiscommentsform; 2267 2268 extract(lAtts(array( 2269 'rows' => $thiscommentsform['msgrows'], 2270 'cols' => $thiscommentsform['msgcols'] 2271 ), $atts)); 2272 2273 $style = $thiscommentsform['msgstyle']; 2274 $commentwarn = false; 2275 $n_message = 'message'; 2276 $formnonce = ''; 2277 $message = ''; 2278 2279 if (ps('preview')) { 2280 $comment = getComment(); 2281 $message = $comment['message']; 2282 $split = rand(1, 31); 2283 $nonce = getNextNonce(); 2284 $secret = getNextSecret(); 2285 safe_insert('txp_discuss_nonce', "issue_time = NOW(), nonce = '".doSlash($nonce)."', secret = '".doSlash($secret)."'"); 2286 $n_message = md5('message'.$secret); 2287 $formnonce = n.hInput(substr($nonce, 0, $split), substr($nonce, $split)); 2288 $commentwarn = (!trim($message)); 2289 } 2290 2291 $required = ($prefs['doctype'] == 'html5') ? ' required' : ''; 2292 $cols = ($cols and is_numeric($cols)) ? ' cols="'.intval($cols).'"' : ''; 2293 $rows = ($rows and is_numeric($rows)) ? ' rows="'.intval($rows).'"' : ''; 2294 $style = ($style ? ' style="'.$style.'"' : ''); 2295 2296 return '<textarea class="txpCommentInputMessage'.(($commentwarn) ? ' comments_error"' : '"'). 2297 ' id="message" name="'.$n_message.'"'.$cols.$rows.$style.$required. 2298 '>'.txpspecialchars(substr(trim($message), 0, 65535)).'</textarea>'. 2299 callback_event('comment.form'). 2300 $formnonce; 2301 } 2302 2303 // ------------------------------------------------------------- 2304 2305 function comment_remember($atts) 2306 { 2307 global $thiscommentsform; 2308 2309 extract(lAtts(array( 2310 'rememberlabel' => $thiscommentsform['rememberlabel'], 2311 'forgetlabel' => $thiscommentsform['forgetlabel'] 2312 ), $atts)); 2313 2314 extract(doDeEnt(psa(array( 2315 'checkbox_type', 2316 'remember', 2317 'forget' 2318 )))); 2319 2320 if (!ps('preview')) { 2321 $rememberCookie = cs('txp_remember'); 2322 2323 if ($rememberCookie === '') { 2324 $checkbox_type = 'remember'; 2325 $remember = 1; 2326 } elseif ($rememberCookie == 1) { 2327 $checkbox_type = 'forget'; 2328 } else { 2329 $checkbox_type = 'remember'; 2330 } 2331 } 2332 2333 if ($checkbox_type == 'forget') { 2334 // Inhibit default remember. 2335 if ($forget == 1) { 2336 destroyCookies(); 2337 } 2338 2339 $checkbox = checkbox('forget', 1, $forget, '', 'forget').' '.tag(txpspecialchars($forgetlabel), 'label', ' for="forget"'); 2340 } else { 2341 // Inhibit default remember. 2342 if ($remember != 1) { 2343 destroyCookies(); 2344 } 2345 2346 $checkbox = checkbox('remember', 1, $remember, '', 'remember').' '.tag(txpspecialchars($rememberlabel), 'label', ' for="remember"'); 2347 } 2348 2349 $checkbox .= ' '.hInput('checkbox_type', $checkbox_type); 2350 2351 return $checkbox; 2352 } 2353 2354 // ------------------------------------------------------------- 2355 2356 function comment_preview($atts) 2357 { 2358 global $thiscommentsform; 2359 2360 extract(lAtts(array( 2361 'label' => $thiscommentsform['previewlabel'] 2362 ), $atts)); 2363 2364 return fInput('submit', 'preview', $label, 'button', '', '', '', '', 'txpCommentPreview', false); 2365 } 2366 2367 // ------------------------------------------------------------- 2368 2369 function comment_submit($atts) 2370 { 2371 global $thiscommentsform; 2372 2373 extract(lAtts(array( 2374 'label' => $thiscommentsform['submitlabel'] 2375 ), $atts)); 2376 2377 // If all fields check out, the submit button is active/clickable. 2378 if (ps('preview')) { 2379 return fInput('submit', 'submit', $label, 'button', '', '', '', '', 'txpCommentSubmit', false); 2380 } else { 2381 return fInput('submit', 'submit', $label, 'button disabled', '', '', '', '', 'txpCommentSubmit', true); 2382 } 2383 } 2384 2385 // ------------------------------------------------------------- 2386 2387 function comments_error($atts) 2388 { 2389 extract(lAtts(array( 2390 'break' => 'br', 2391 'class' => __FUNCTION__, 2392 'wraptag' => 'div', 2393 ), $atts)); 2394 2395 $evaluator = & get_comment_evaluator(); 2396 2397 $errors = $evaluator->get_result_message(); 2398 2399 if ($errors) { 2400 return doWrap($errors, $wraptag, $break, $class); 2401 } 2402 } 2403 2404 // ------------------------------------------------------------- 2405 2406 function if_comments_error($atts, $thing) 2407 { 2408 $evaluator = & get_comment_evaluator(); 2409 2410 return parse($thing, (count($evaluator->get_result_message()) > 0)); 2411 } 2412 2413 /** 2414 * Renders a heading for comments. 2415 * 2416 * @param array $atts 2417 * @param string $thing 2418 * @return string 2419 * @deprecated in 4.0.0 2420 */ 2421 2422 function comments_annotateinvite($atts, $thing) 2423 { 2424 trigger_error(gTxt('deprecated_tag'), E_USER_NOTICE); 2425 2426 global $thisarticle, $pretext; 2427 2428 extract(lAtts(array( 2429 'class' => __FUNCTION__, 2430 'wraptag' => 'h3', 2431 ), $atts)); 2432 2433 assert_article(); 2434 2435 extract($thisarticle); 2436 2437 extract(safe_row( 2438 "Annotate, AnnotateInvite, UNIX_TIMESTAMP(Posted) AS uPosted", 2439 'textpattern', 2440 "ID = ".intval($thisid) 2441 )); 2442 2443 if (!$thing) { 2444 $thing = $AnnotateInvite; 2445 } 2446 2447 return (!$Annotate) ? '' : doTag($thing, $wraptag, $class, ' id="'.gTxt('comment').'"'); 2448 } 2449 2450 // ------------------------------------------------------------- 2451 2452 function comments($atts, $thing = null) 2453 { 2454 global $thisarticle, $prefs; 2455 extract($prefs); 2456 2457 extract(lAtts(array( 2458 'form' => 'comments', 2459 'wraptag' => ($comments_are_ol ? 'ol' : ''), 2460 'break' => ($comments_are_ol ? 'li' : 'div'), 2461 'class' => __FUNCTION__, 2462 'breakclass' => '', // Deprecated in 4.6.0 2463 'limit' => 0, 2464 'offset' => 0, 2465 'sort' => 'posted ASC', 2466 ), $atts)); 2467 2468 assert_article(); 2469 2470 if (isset($atts['breakclass'])) { 2471 trigger_error(gTxt('deprecated_attribute', array('{name}' => 'breakclass')), E_USER_NOTICE); 2472 } 2473 2474 extract($thisarticle); 2475 2476 if (!$comments_count) { 2477 return ''; 2478 } 2479 2480 $qparts = array( 2481 "parentid = ".intval($thisid)." AND visible = ".VISIBLE, 2482 "ORDER BY ".doSlash($sort), 2483 ($limit) ? "LIMIT ".intval($offset).", ".intval($limit) : '', 2484 ); 2485 2486 $rs = safe_rows_start("*, UNIX_TIMESTAMP(posted) AS time", 'txp_discuss', join(' ', $qparts)); 2487 2488 $out = ''; 2489 2490 if ($rs) { 2491 $comments = array(); 2492 2493 while ($vars = nextRow($rs)) { 2494 $GLOBALS['thiscomment'] = $vars; 2495 $comments[] = ($thing === null ? parse_form($form) : parse($thing)).n; 2496 unset($GLOBALS['thiscomment']); 2497 } 2498 2499 $out .= doWrap($comments, $wraptag, $break, $class, $breakclass); 2500 } 2501 2502 return $out; 2503 } 2504 2505 // ------------------------------------------------------------- 2506 2507 function comments_preview($atts, $thing = null) 2508 { 2509 global $has_comments_preview; 2510 2511 if (!ps('preview')) { 2512 return; 2513 } 2514 2515 extract(lAtts(array( 2516 'form' => 'comments', 2517 'wraptag' => '', 2518 'class' => __FUNCTION__, 2519 ), $atts)); 2520 2521 assert_article(); 2522 2523 $preview = psa(array('name', 'email', 'web', 'message', 'parentid', 'remember')); 2524 $preview['time'] = time(); 2525 $preview['discussid'] = 0; 2526 $preview['name'] = strip_tags($preview['name']); 2527 $preview['email'] = clean_url($preview['email']); 2528 2529 if ($preview['message'] == '') { 2530 $in = getComment(); 2531 $preview['message'] = $in['message']; 2532 } 2533 2534 // It is called 'message', not 'novel'! 2535 $preview['message'] = markup_comment(substr(trim($preview['message']), 0, 65535)); 2536 2537 $preview['web'] = clean_url($preview['web']); 2538 2539 $GLOBALS['thiscomment'] = $preview; 2540 $comments = ($thing === null ? parse_form($form) : parse($thing)).n; 2541 unset($GLOBALS['thiscomment']); 2542 $out = doTag($comments, $wraptag, $class); 2543 2544 // Set a flag to tell the comments_form tag that it doesn't have to show 2545 // a preview. 2546 $has_comments_preview = true; 2547 2548 return $out; 2549 } 2550 2551 // ------------------------------------------------------------- 2552 2553 function if_comments_preview($atts, $thing) 2554 { 2555 return parse($thing, ps('preview') && checkCommentsAllowed(gps('parentid'))); 2556 } 2557 2558 // ------------------------------------------------------------- 2559 2560 function comment_permlink($atts, $thing) 2561 { 2562 global $thisarticle, $thiscomment; 2563 2564 assert_article(); 2565 assert_comment(); 2566 2567 extract($thiscomment); 2568 extract(lAtts(array( 2569 'anchor' => empty($thiscomment['has_anchor_tag']), 2570 ), $atts)); 2571 2572 $dlink = permlinkurl($thisarticle).'#c'.$discussid; 2573 2574 $thing = parse($thing); 2575 2576 $name = ($anchor ? ' id="c'.$discussid.'"' : ''); 2577 2578 return tag($thing, 'a', ' href="'.$dlink.'"'.$name); 2579 } 2580 2581 // ------------------------------------------------------------- 2582 2583 function comment_id() 2584 { 2585 global $thiscomment; 2586 2587 assert_comment(); 2588 2589 return $thiscomment['discussid']; 2590 } 2591 2592 // ------------------------------------------------------------- 2593 2594 function comment_name($atts) 2595 { 2596 global $thiscomment, $prefs; 2597 2598 assert_comment(); 2599 2600 extract($prefs); 2601 extract($thiscomment); 2602 2603 extract(lAtts(array( 2604 'link' => 1, 2605 ), $atts)); 2606 2607 $name = txpspecialchars($name); 2608 2609 if ($link) { 2610 $web = comment_web(); 2611 $nofollow = (@$comment_nofollow ? ' rel="nofollow"' : ''); 2612 2613 if (!empty($web)) { 2614 return href($name, $web, $nofollow); 2615 } 2616 2617 if ($email && !$never_display_email) { 2618 return href($name, eE('mailto:'.$email), $nofollow); 2619 } 2620 } 2621 2622 return $name; 2623 } 2624 2625 // ------------------------------------------------------------- 2626 2627 function comment_email() 2628 { 2629 global $thiscomment; 2630 2631 assert_comment(); 2632 2633 return txpspecialchars($thiscomment['email']); 2634 } 2635 2636 // ------------------------------------------------------------- 2637 2638 function comment_web() 2639 { 2640 global $thiscomment; 2641 2642 assert_comment(); 2643 2644 if (preg_match('/^\S/', $thiscomment['web'])) { 2645 // Prepend default protocol 'http' for all non-local URLs. 2646 if (!preg_match('!^https?://|^#|^/[^/]!', $thiscomment['web'])) { 2647 $thiscomment['web'] = 'http://'.$thiscomment['web']; 2648 } 2649 2650 return txpspecialchars($thiscomment['web']); 2651 } 2652 2653 return ''; 2654 } 2655 2656 // ------------------------------------------------------------- 2657 2658 function comment_time($atts) 2659 { 2660 global $thiscomment, $comments_dateformat; 2661 2662 assert_comment(); 2663 2664 extract(lAtts(array( 2665 'format' => $comments_dateformat, 2666 'gmt' => '', 2667 'lang' => '', 2668 ), $atts)); 2669 2670 return safe_strftime($format, $thiscomment['time'], $gmt, $lang); 2671 } 2672 2673 // ------------------------------------------------------------- 2674 2675 function comment_message() 2676 { 2677 global $thiscomment; 2678 2679 assert_comment(); 2680 2681 return $thiscomment['message']; 2682 } 2683 2684 // ------------------------------------------------------------- 2685 2686 function comment_anchor() 2687 { 2688 global $thiscomment; 2689 2690 assert_comment(); 2691 2692 $thiscomment['has_anchor_tag'] = 1; 2693 2694 return '<a id="c'.$thiscomment['discussid'].'"></a>'; 2695 } 2696 2697 // ------------------------------------------------------------- 2698 2699 function author($atts) 2700 { 2701 global $thisarticle, $thisauthor, $s, $author; 2702 2703 extract(lAtts(array( 2704 'escape' => 'html', 2705 'link' => 0, 2706 'title' => 1, 2707 'section' => '', 2708 'this_section' => 0, 2709 'format' => '', // empty, link, or url 2710 ), $atts)); 2711 2712 // Synonym. 2713 if ($format === 'link') { 2714 $link = 1; 2715 } 2716 2717 if ($thisauthor) { 2718 $realname = $thisauthor['realname']; 2719 $name = $thisauthor['name']; 2720 } elseif ($author) { 2721 $realname = get_author_name($author); 2722 $name = $author; 2723 } else { 2724 assert_article(); 2725 $realname = get_author_name($thisarticle['authorid']); 2726 $name = $thisarticle['authorid']; 2727 } 2728 2729 if ($title) { 2730 $display_name = $realname; 2731 } else { 2732 $display_name = $name; 2733 } 2734 2735 $display_name = ($escape === 'html') ? txpspecialchars($display_name) : $display_name; 2736 2737 if ($this_section && $s != 'default') { 2738 $section = $s; 2739 } 2740 2741 $href = pagelinkurl(array( 2742 's' => $section, 2743 'author' => $realname, 2744 )); 2745 2746 if ($format === 'url') { 2747 return $href; 2748 } 2749 2750 if ($link) { 2751 return href($display_name, $href, ' rel="author"'); 2752 } 2753 2754 return $display_name; 2755 } 2756 2757 // ------------------------------------------------------------- 2758 2759 function author_email($atts) 2760 { 2761 global $thisarticle, $thisauthor; 2762 2763 extract(lAtts(array( 2764 'escape' => 'html', 2765 'link' => '', 2766 ), $atts)); 2767 2768 if ($thisauthor) { 2769 $email = get_author_email($thisauthor['name']); 2770 } else { 2771 assert_article(); 2772 $email = get_author_email($thisarticle['authorid']); 2773 } 2774 2775 if ($escape == 'html') { 2776 $display_email = txpspecialchars($email); 2777 } else { 2778 $display_email = $email; 2779 } 2780 2781 if ($link) { 2782 return email(array( 2783 'email' => $email, 2784 'linktext' => $display_email, 2785 )); 2786 } 2787 2788 return $display_email; 2789 } 2790 2791 // ------------------------------------------------------------- 2792 2793 function if_author($atts, $thing) 2794 { 2795 global $author, $context, $thisauthor; 2796 2797 extract(lAtts(array( 2798 'type' => 'article', 2799 'name' => '', 2800 ), $atts)); 2801 2802 if ($thisauthor) { 2803 return parse($thing, $name === '' || in_list($thisauthor['name'], $name)); 2804 } 2805 2806 $theType = ($type) ? $type == $context : true; 2807 2808 if ($name) { 2809 return parse($thing, ($theType && in_list($author, $name))); 2810 } 2811 2812 return parse($thing, ($theType && (string) $author !== '')); 2813 } 2814 2815 // ------------------------------------------------------------- 2816 2817 function if_article_author($atts, $thing) 2818 { 2819 global $thisarticle; 2820 2821 assert_article(); 2822 2823 extract(lAtts(array( 2824 'name' => '', 2825 ), $atts)); 2826 2827 $author = $thisarticle['authorid']; 2828 2829 if ($name) { 2830 return parse($thing, in_list($author, $name)); 2831 } 2832 2833 return parse($thing, (string) $author !== ''); 2834 } 2835 2836 // ------------------------------------------------------------- 2837 2838 function body() 2839 { 2840 global $thisarticle, $is_article_body; 2841 2842 assert_article(); 2843 2844 $was_article_body = $is_article_body; 2845 $is_article_body = 1; 2846 $out = parse($thisarticle['body']); 2847 $is_article_body = $was_article_body; 2848 2849 return $out; 2850 } 2851 2852 // ------------------------------------------------------------- 2853 2854 function title($atts) 2855 { 2856 global $thisarticle, $prefs; 2857 2858 assert_article(); 2859 2860 extract(lAtts(array( 2861 'no_widow' => @$prefs['title_no_widow'], 2862 ), $atts)); 2863 2864 $t = escape_title($thisarticle['title']); 2865 2866 if ($no_widow) { 2867 $t = noWidow($t); 2868 } 2869 2870 return $t; 2871 } 2872 2873 // ------------------------------------------------------------- 2874 2875 function excerpt() 2876 { 2877 global $thisarticle, $is_article_body; 2878 2879 assert_article(); 2880 2881 $was_article_body = $is_article_body; 2882 $is_article_body = 1; 2883 $out = parse($thisarticle['excerpt']); 2884 $is_article_body = $was_article_body; 2885 2886 return $out; 2887 } 2888 2889 // ------------------------------------------------------------- 2890 2891 function category1($atts, $thing = null) 2892 { 2893 global $thisarticle, $s, $permlink_mode; 2894 2895 assert_article(); 2896 2897 extract(lAtts(array( 2898 'class' => '', 2899 'link' => 0, 2900 'title' => 0, 2901 'section' => '', 2902 'this_section' => 0, 2903 'wraptag' => '', 2904 ), $atts)); 2905 2906 if ($thisarticle['category1']) { 2907 $section = ($this_section) ? ($s == 'default' ? '' : $s) : $section; 2908 $category = $thisarticle['category1']; 2909 2910 $label = txpspecialchars(($title) ? fetch_category_title($category) : $category); 2911 2912 if ($thing) { 2913 $out = href( 2914 parse($thing), 2915 pagelinkurl(array('s' => $section, 'c' => $category)), 2916 (($class and !$wraptag) ? ' class="'.txpspecialchars($class).'"' : ''). 2917 ($title ? ' title="'.$label.'"' : ''). 2918 ($permlink_mode != 'messy' ? ' rel="category tag"' : '') 2919 ); 2920 } elseif ($link) { 2921 $out = href( 2922 $label, 2923 pagelinkurl(array('s' => $section, 'c' => $category)), 2924 ($permlink_mode != 'messy' ? ' rel="category tag"' : '') 2925 ); 2926 } else { 2927 $out = $label; 2928 } 2929 2930 return doTag($out, $wraptag, $class); 2931 } 2932 } 2933 2934 // ------------------------------------------------------------- 2935 2936 function category2($atts, $thing = null) 2937 { 2938 global $thisarticle, $s, $permlink_mode; 2939 2940 assert_article(); 2941 2942 extract(lAtts(array( 2943 'class' => '', 2944 'link' => 0, 2945 'title' => 0, 2946 'section' => '', 2947 'this_section' => 0, 2948 'wraptag' => '', 2949 ), $atts)); 2950 2951 if ($thisarticle['category2']) { 2952 $section = ($this_section) ? ($s == 'default' ? '' : $s) : $section; 2953 $category = $thisarticle['category2']; 2954 2955 $label = txpspecialchars(($title) ? fetch_category_title($category) : $category); 2956 2957 if ($thing) { 2958 $out = href( 2959 parse($thing), 2960 pagelinkurl(array('s' => $section, 'c' => $category)), 2961 (($class and !$wraptag) ? ' class="'.txpspecialchars($class).'"' : ''). 2962 ($title ? ' title="'.$label.'"' : ''). 2963 ($permlink_mode != 'messy' ? ' rel="category tag"' : '') 2964 ); 2965 } elseif ($link) { 2966 $out = href( 2967 $label, 2968 pagelinkurl(array('s' => $section, 'c' => $category)), 2969 ($permlink_mode != 'messy' ? ' rel="category tag"' : '') 2970 ); 2971 } else { 2972 $out = $label; 2973 } 2974 2975 return doTag($out, $wraptag, $class); 2976 } 2977 } 2978 2979 // ------------------------------------------------------------- 2980 2981 function category($atts, $thing = null) 2982 { 2983 global $s, $c, $thiscategory, $context; 2984 2985 extract(lAtts(array( 2986 'class' => '', 2987 'link' => 0, 2988 'name' => '', 2989 'section' => $s, 2990 'this_section' => 0, 2991 'title' => 0, 2992 'type' => 'article', 2993 'url' => 0, 2994 'wraptag' => '', 2995 ), $atts)); 2996 2997 if ($name) { 2998 $category = $name; 2999 } elseif (!empty($thiscategory['name'])) { 3000 $category = $thiscategory['name']; 3001 $type = $thiscategory['type']; 3002 } else { 3003 $category = $c; 3004 3005 if (!isset($atts['type'])) { 3006 $type = $context; 3007 } 3008 } 3009 3010 if ($category) { 3011 if ($this_section) { 3012 $section = ($s == 'default' ? '' : $s); 3013 } elseif (isset($thiscategory['section'])) { 3014 $section = $thiscategory['section']; 3015 } 3016 3017 $label = txpspecialchars(($title) ? fetch_category_title($category, $type) : $category); 3018 3019 $href = pagelinkurl(array('s' => $section, 'c' => $category, 'context' => $type)); 3020 3021 if ($thing) { 3022 $out = href( 3023 parse($thing), 3024 $href, 3025 (($class and !$wraptag) ? ' class="'.txpspecialchars($class).'"' : ''). 3026 ($title ? ' title="'.$label.'"' : '') 3027 ); 3028 } elseif ($link) { 3029 $out = href( 3030 $label, 3031 $href, 3032 ($class and !$wraptag) ? ' class="'.txpspecialchars($class).'"' : '' 3033 ); 3034 } elseif ($url) { 3035 $out = $href; 3036 } else { 3037 $out = $label; 3038 } 3039 3040 return doTag($out, $wraptag, $class); 3041 } 3042 } 3043 3044 // ------------------------------------------------------------- 3045 3046 function section($atts, $thing = null) 3047 { 3048 global $thisarticle, $s, $thissection; 3049 3050 extract(lAtts(array( 3051 'class' => '', 3052 'link' => 0, 3053 'name' => '', 3054 'title' => 0, 3055 'url' => 0, 3056 'wraptag' => '', 3057 ), $atts)); 3058 3059 if ($name) { 3060 $sec = $name; 3061 } elseif (!empty($thissection['name'])) { 3062 $sec = $thissection['name']; 3063 } elseif (!empty($thisarticle['section'])) { 3064 $sec = $thisarticle['section']; 3065 } else { 3066 $sec = $s; 3067 } 3068 3069 if ($sec) { 3070 $label = txpspecialchars(($title) ? fetch_section_title($sec) : $sec); 3071 3072 $href = pagelinkurl(array('s' => $sec)); 3073 3074 if ($thing) { 3075 $out = href( 3076 parse($thing), 3077 $href, 3078 (($class and !$wraptag) ? ' class="'.txpspecialchars($class).'"' : ''). 3079 ($title ? ' title="'.$label.'"' : '') 3080 ); 3081 } elseif ($link) { 3082 $out = href( 3083 $label, 3084 $href, 3085 ($class and !$wraptag) ? ' class="'.txpspecialchars($class).'"' : '' 3086 ); 3087 } elseif ($url) { 3088 $out = $href; 3089 } else { 3090 $out = $label; 3091 } 3092 3093 return doTag($out, $wraptag, $class); 3094 } 3095 } 3096 3097 // ------------------------------------------------------------- 3098 3099 function keywords() 3100 { 3101 global $thisarticle; 3102 3103 assert_article(); 3104 3105 trigger_error(gTxt('deprecated_tag'), E_USER_NOTICE); 3106 3107 return txpspecialchars($thisarticle['keywords']); 3108 } 3109 3110 // ------------------------------------------------------------- 3111 3112 function if_keywords($atts, $thing = null) 3113 { 3114 global $thisarticle; 3115 3116 assert_article(); 3117 3118 extract(lAtts(array( 3119 'keywords' => '', 3120 ), $atts)); 3121 3122 $condition = empty($keywords) 3123 ? $thisarticle['keywords'] 3124 : array_intersect(do_list($keywords), do_list($thisarticle['keywords'])); 3125 3126 return parse($thing, !empty($condition)); 3127 } 3128 3129 // ------------------------------------------------------------- 3130 3131 function if_article_image($atts, $thing = '') 3132 { 3133 global $thisarticle; 3134 3135 assert_article(); 3136 3137 return parse($thing, !empty($thisarticle['article_image'])); 3138 } 3139 3140 // ------------------------------------------------------------- 3141 3142 function article_image($atts) 3143 { 3144 global $thisarticle; 3145 3146 assert_article(); 3147 3148 extract(lAtts(array( 3149 'class' => '', 3150 'escape' => 'html', 3151 'html_id' => '', 3152 'style' => '', 3153 'width' => '', 3154 'height' => '', 3155 'thumbnail' => 0, 3156 'wraptag' => '', 3157 ), $atts)); 3158 3159 if ($thisarticle['article_image']) { 3160 $image = $thisarticle['article_image']; 3161 } else { 3162 return; 3163 } 3164 3165 if (intval($image)) { 3166 $rs = safe_row("*", 'txp_image', "id = ".intval($image)); 3167 3168 if ($rs) { 3169 $width = ($width == '') ? (($thumbnail) ? $rs['thumb_w'] : $rs['w']) : $width; 3170 $height = ($height == '') ? (($thumbnail) ? $rs['thumb_h'] : $rs['h']) : $height; 3171 3172 if ($thumbnail) { 3173 if ($rs['thumbnail']) { 3174 extract($rs); 3175 3176 if ($escape == 'html') { 3177 $alt = txpspecialchars($alt); 3178 $caption = txpspecialchars($caption); 3179 } 3180 3181 $out = '<img src="'.imagesrcurl($id, $ext, true).'" alt="'.$alt.'"'. 3182 (($html_id and !$wraptag) ? ' id="'.txpspecialchars($html_id).'"' : ''). 3183 (($class and !$wraptag) ? ' class="'.txpspecialchars($class).'"' : ''). 3184 ($style ? ' style="'.txpspecialchars($style).'"' : ''). 3185 ($width ? ' width="'.(int) $width.'"' : ''). 3186 ($height ? ' height="'.(int) $height.'"' : ''). 3187 ' />'; 3188 } else { 3189 return ''; 3190 } 3191 } else { 3192 extract($rs); 3193 3194 if ($escape == 'html') { 3195 $alt = txpspecialchars($alt); 3196 $caption = txpspecialchars($caption); 3197 } 3198 3199 $out = '<img src="'.imagesrcurl($id, $ext).'" alt="'.$alt.'"'. 3200 (($html_id and !$wraptag) ? ' id="'.txpspecialchars($html_id).'"' : ''). 3201 (($class and !$wraptag) ? ' class="'.txpspecialchars($class).'"' : ''). 3202 ($style ? ' style="'.txpspecialchars($style).'"' : ''). 3203 ($width ? ' width="'.(int) $width.'"' : ''). 3204 ($height ? ' height="'.(int) $height.'"' : ''). 3205 ' />'; 3206 } 3207 } else { 3208 trigger_error(gTxt('unknown_image')); 3209 3210 return; 3211 } 3212 } else { 3213 $out = '<img src="'.txpspecialchars($image).'" alt=""'. 3214 (($html_id and !$wraptag) ? ' id="'.txpspecialchars($html_id).'"' : ''). 3215 (($class and !$wraptag) ? ' class="'.txpspecialchars($class).'"' : ''). 3216 ($style ? ' style="'.txpspecialchars($style).'"' : ''). 3217 ($width ? ' width="'.(int) $width.'"' : ''). 3218 ($height ? ' height="'.(int) $height.'"' : ''). 3219 ' />'; 3220 } 3221 3222 return ($wraptag) ? doTag($out, $wraptag, $class, '', $html_id) : $out; 3223 } 3224 3225 // ------------------------------------------------------------- 3226 3227 function search_result_title($atts) 3228 { 3229 return permlink($atts, '<txp:title />'); 3230 } 3231 3232 // ------------------------------------------------------------- 3233 3234 function search_result_excerpt($atts) 3235 { 3236 global $thisarticle, $pretext; 3237 3238 assert_article(); 3239 3240 extract(lAtts(array( 3241 'break' => ' …', 3242 'hilight' => 'strong', 3243 'limit' => 5, 3244 ), $atts)); 3245 3246 $m = $pretext['m']; 3247 $q = $pretext['q']; 3248 3249 $quoted = ($q[0] === '"') && ($q[strlen($q) - 1] === '"'); 3250 $q = $quoted ? trim(trim($q, '"')) : trim($q); 3251 3252 $result = preg_replace('/\s+/', ' ', strip_tags(str_replace('><', '> <', $thisarticle['body']))); 3253 3254 if ($quoted || empty($m) || $m === 'exact') { 3255 $regex_search = '/(?:\G|\s).{0,50}'.preg_quote($q, '/').'.{0,50}(?:\s|$)/iu'; 3256 $regex_hilite = '/('.preg_quote($q, '/').')/i'; 3257 } else { 3258 $regex_search = '/(?:\G|\s).{0,50}('.preg_replace('/\s+/', '|', preg_quote($q, '/')).').{0,50}(?:\s|$)/iu'; 3259 $regex_hilite = '/('.preg_replace('/\s+/', '|', preg_quote($q, '/')).')/i'; 3260 } 3261 3262 preg_match_all($regex_search, $result, $concat); 3263 $concat = $concat[0]; 3264 3265 for ($i = 0, $r = array(); $i < min($limit, count($concat)); $i++) { 3266 $r[] = trim($concat[$i]); 3267 } 3268 3269 $concat = join($break.n, $r); 3270 $concat = preg_replace('/^[^>]+>/U', '', $concat); 3271 // TODO: 3272 3273 $concat = preg_replace($regex_hilite, "<$hilight>$1</$hilight>", $concat); 3274 3275 return ($concat) ? trim($break.$concat.$break) : ''; 3276 } 3277 3278 // ------------------------------------------------------------- 3279 3280 function search_result_url($atts) 3281 { 3282 global $thisarticle; 3283 3284 assert_article(); 3285 3286 $l = permlinkurl($thisarticle); 3287 3288 return permlink($atts, $l); 3289 } 3290 3291 // ------------------------------------------------------------- 3292 3293 function search_result_date($atts) 3294 { 3295 assert_article(); 3296 3297 return posted($atts); 3298 } 3299 3300 // ------------------------------------------------------------- 3301 3302 function search_result_count($atts) 3303 { 3304 global $thispage; 3305 $t = @$thispage['grand_total']; 3306 3307 extract(lAtts(array( 3308 'text' => ($t == 1 ? gTxt('article_found') : gTxt('articles_found')), 3309 ), $atts)); 3310 3311 return $t.($text ? ' '.$text : ''); 3312 } 3313 3314 // ------------------------------------------------------------- 3315 3316 function image_index($atts) 3317 { 3318 global $s, $c, $p, $path_to_site; 3319 3320 extract(lAtts(array( 3321 'label' => '', 3322 'break' => br, 3323 'wraptag' => '', 3324 'class' => __FUNCTION__, 3325 'labeltag' => '', 3326 'c' => $c, // Keep the option to override categories due to backward compatibility. 3327 'category' => $c, 3328 'limit' => 0, 3329 'offset' => 0, 3330 'sort' => 'name ASC', 3331 ), $atts)); 3332 3333 if (isset($atts['c'])) { 3334 trigger_error(gTxt('deprecated_attribute', array('{name}' => 'c')), E_USER_NOTICE); 3335 } 3336 3337 if (isset($atts['category'])) { 3338 // Override the global. 3339 $c = $category; 3340 } 3341 3342 $qparts = array( 3343 "category = '".doSlash($c)."' AND thumbnail = 1", 3344 "ORDER BY ".doSlash($sort), 3345 ($limit) ? "LIMIT ".intval($offset).", ".intval($limit) : '', 3346 ); 3347 3348 $rs = safe_rows_start("*", 'txp_image', join(' ', $qparts)); 3349 3350 if ($rs) { 3351 $out = array(); 3352 3353 while ($a = nextRow($rs)) { 3354 extract($a); 3355 $dims = ($thumb_h ? " height=\"$thumb_h\"" : '').($thumb_w ? " width=\"$thumb_w\"" : ''); 3356 $url = pagelinkurl(array( 3357 'c' => $c, 3358 'context' => 'image', 3359 's' => $s, 3360 'p' => $id, 3361 )); 3362 $out[] = href( 3363 '<img src="'.imagesrcurl($id, $ext, true).'"'.$dims.' alt="'.txpspecialchars($alt).'" />', 3364 $url 3365 ); 3366 } 3367 3368 if (count($out)) { 3369 return doLabel($label, $labeltag).doWrap($out, $wraptag, $break, $class); 3370 } 3371 } 3372 3373 return ''; 3374 } 3375 3376 // ------------------------------------------------------------- 3377 3378 function image_display($atts) 3379 { 3380 if (is_array($atts)) { 3381 extract($atts); 3382 } 3383 3384 global $s, $c, $p; 3385 3386 if ($p) { 3387 $rs = safe_row("*", 'txp_image', "id=".intval($p)." LIMIT 1"); 3388 3389 if ($rs) { 3390 extract($rs); 3391 3392 return '<img src="'.imagesrcurl($id, $ext). 3393 '" style="height:'.$h.'px;width:'.$w.'px" alt="'.txpspecialchars($alt).'" />'; 3394 } 3395 } 3396 } 3397 3398 // ------------------------------------------------------------- 3399 3400 function images($atts, $thing = null) 3401 { 3402 global $s, $c, $context, $p, $path_to_site, $thisimage, $thisarticle, $thispage, $pretext; 3403 3404 extract(lAtts(array( 3405 'name' => '', 3406 'id' => '', 3407 'category' => '', 3408 'author' => '', 3409 'realname' => '', 3410 'extension' => '', 3411 'thumbnail' => '', 3412 'auto_detect' => 'article, category, author', 3413 'label' => '', 3414 'break' => br, 3415 'wraptag' => '', 3416 'class' => __FUNCTION__, 3417 'html_id' => '', 3418 'labeltag' => '', 3419 'form' => '', 3420 'pageby' => '', 3421 'limit' => 0, 3422 'offset' => 0, 3423 'sort' => 'name ASC', 3424 ), $atts)); 3425 3426 $safe_sort = doSlash($sort); 3427 $where = array(); 3428 $has_content = $thing || $form; 3429 $filters = isset($atts['id']) || isset($atts['name']) || isset($atts['category']) || isset($atts['author']) || isset($atts['realname']) || isset($atts['extension']) || $thumbnail === '1' || $thumbnail === '0'; 3430 $context_list = (empty($auto_detect) || $filters) ? array() : do_list_unique($auto_detect); 3431 $pageby = ($pageby == 'limit') ? $limit : $pageby; 3432 3433 if ($name) { 3434 $where[] = "name IN ('".join("','", doSlash(do_list_unique($name)))."')"; 3435 } 3436 3437 if ($category) { 3438 $where[] = "category IN ('".join("','", doSlash(do_list_unique($category)))."')"; 3439 } 3440 3441 if ($id) { 3442 $where[] = "id IN ('".join("','", doSlash(do_list_unique($id)))."')"; 3443 } 3444 3445 if ($author) { 3446 $where[] = "author IN ('".join("','", doSlash(do_list_unique($author)))."')"; 3447 } 3448 3449 if ($realname) { 3450 $authorlist = safe_column("name", 'txp_users', "RealName IN ('".join("','", doArray(doSlash(do_list_unique($realname)), 'urldecode'))."')"); 3451 if ($authorlist) { 3452 $where[] = "author IN ('".join("','", doSlash($authorlist))."')"; 3453 } 3454 } 3455 3456 if ($extension) { 3457 $where[] = "ext IN ('".join("','", doSlash(do_list_unique($extension)))."')"; 3458 } 3459 3460 if ($thumbnail === '0' || $thumbnail === '1') { 3461 $where[] = "thumbnail = $thumbnail"; 3462 } 3463 3464 // If no images are selected, try... 3465 if (!$where && !$filters) { 3466 foreach ($context_list as $ctxt) { 3467 switch ($ctxt) { 3468 case 'article': 3469 // ...the article image field. 3470 if ($thisarticle && !empty($thisarticle['article_image'])) { 3471 $items = do_list_unique($thisarticle['article_image']); 3472 foreach ($items as &$item) { 3473 if (is_numeric($item)) { 3474 $item = intval($item); 3475 } else { 3476 return article_image(compact('class', 'html_id', 'wraptag')); 3477 } 3478 } 3479 $items = join(",", $items); 3480 3481 // Note: This clause will squash duplicate ids. 3482 $where[] = "id IN ($items)"; 3483 3484 // Order of ids in article image field overrides default 'sort' attribute. 3485 if (empty($atts['sort'])) { 3486 $safe_sort = "FIELD(id, $items)"; 3487 } 3488 } 3489 break; 3490 case 'category': 3491 // ...the global category in the URL. 3492 if ($context == 'image' && !empty($c)) { 3493 $where[] = "category = '".doSlash($c)."'"; 3494 } 3495 break; 3496 case 'author': 3497 // ...the global author in the URL. 3498 if ($context == 'image' && !empty($pretext['author'])) { 3499 $where[] = "author = '".doSlash($pretext['author'])."'"; 3500 } 3501 break; 3502 } 3503 // Only one context can be processed. 3504 if ($where) { 3505 break; 3506 } 3507 } 3508 } 3509 3510 // Order of ids in 'id' attribute overrides default 'sort' attribute. 3511 if (empty($atts['sort']) && $id !== '') { 3512 $safe_sort = "FIELD(id, ".join(',', doSlash(do_list_unique($id))).")"; 3513 } 3514 3515 // If nothing matches, output nothing. 3516 if (!$where && $filters) { 3517 return ''; 3518 } 3519 3520 // If nothing matches, start with all images. 3521 if (!$where) { 3522 $where[] = "1 = 1"; 3523 } 3524 3525 $where = join(" AND ", $where); 3526 3527 // Set up paging if required. 3528 if ($limit && $pageby) { 3529 $grand_total = safe_count('txp_image', $where); 3530 $total = $grand_total - $offset; 3531 $numPages = ($pageby > 0) ? ceil($total / $pageby) : 1; 3532 $pg = (!$pretext['pg']) ? 1 : $pretext['pg']; 3533 $pgoffset = $offset + (($pg - 1) * $pageby); 3534 3535 // Send paging info to txp:newer and txp:older. 3536 $pageout['pg'] = $pg; 3537 $pageout['numPages'] = $numPages; 3538 $pageout['s'] = $s; 3539 $pageout['c'] = $c; 3540 $pageout['context'] = 'image'; 3541 $pageout['grand_total'] = $grand_total; 3542 $pageout['total'] = $total; 3543 3544 if (empty($thispage)) { 3545 $thispage = $pageout; 3546 } 3547 } else { 3548 $pgoffset = $offset; 3549 } 3550 3551 $qparts = array( 3552 $where, 3553 "ORDER BY ".$safe_sort, 3554 ($limit) ? "LIMIT ".intval($pgoffset).", ".intval($limit) : '', 3555 ); 3556 3557 $rs = safe_rows_start("*", 'txp_image', join(' ', $qparts)); 3558 3559 if ($rs) { 3560 $out = array(); 3561 $count = 0; 3562 $last = numRows($rs); 3563 3564 if (isset($thisimage)) { 3565 $old_image = $thisimage; 3566 } 3567 3568 while ($a = nextRow($rs)) { 3569 ++$count; 3570 $thisimage = image_format_info($a); 3571 $thisimage['is_first'] = ($count == 1); 3572 $thisimage['is_last'] = ($count == $last); 3573 3574 if (!$has_content) { 3575 $url = pagelinkurl(array( 3576 'c' => $thisimage['category'], 3577 'context' => 'image', 3578 's' => $s, 3579 'p' => $thisimage['id'], 3580 )); 3581 $src = image_url(array('thumbnail' => '1')); 3582 $thing = href( 3583 '<img src="'.$src.'" alt="'.txpspecialchars($thisimage['alt']).'" />', 3584 $url 3585 ); 3586 } 3587 3588 $out[] = ($thing) ? parse($thing) : parse_form($form); 3589 } 3590 3591 $thisimage = (isset($old_image) ? $old_image : null); 3592 3593 if ($out) { 3594 return doLabel($label, $labeltag).doWrap($out, $wraptag, $break, $class, '', '', '', $html_id); 3595 } 3596 } 3597 3598 return ''; 3599 } 3600 3601 // ------------------------------------------------------------- 3602 3603 function image_info($atts) 3604 { 3605 global $thisimage; 3606 3607 extract(lAtts(array( 3608 'name' => '', 3609 'id' => '', 3610 'type' => 'caption', 3611 'escape' => 'html', 3612 'wraptag' => '', 3613 'class' => '', 3614 'break' => '', 3615 'breakclass' => '', // Deprecated in 4.6.0. 3616 ), $atts)); 3617 3618 if (isset($atts['breakclass'])) { 3619 trigger_error(gTxt('deprecated_attribute', array('{name}' => 'breakclass')), E_USER_NOTICE); 3620 } 3621 3622 $validItems = array('id', 'name', 'category', 'category_title', 'alt', 'caption', 'ext', 'author', 'w', 'h', 'thumb_w', 'thumb_h', 'date'); 3623 $type = do_list($type); 3624 3625 $from_form = false; 3626 3627 if ($id) { 3628 $thisimage = imageFetchInfo('id = '.intval($id)); 3629 } elseif ($name) { 3630 $thisimage = imageFetchInfo("name = '".doSlash($name)."'"); 3631 } else { 3632 assert_image(); 3633 $from_form = true; 3634 } 3635 3636 $out = array(); 3637 if ($thisimage) { 3638 $thisimage['category_title'] = fetch_category_title($thisimage['category'], 'image'); 3639 3640 foreach ($type as $item) { 3641 if (in_array($item, $validItems)) { 3642 if (isset($thisimage[$item])) { 3643 $out[] = ($escape == 'html') ? 3644 txpspecialchars($thisimage[$item]) : $thisimage[$item]; 3645 } 3646 } 3647 } 3648 3649 if (!$from_form) { 3650 $thisimage = ''; 3651 } 3652 } 3653 3654 return doWrap($out, $wraptag, $break, $class, $breakclass); 3655 } 3656 3657 // ------------------------------------------------------------- 3658 3659 function image_url($atts, $thing = null) 3660 { 3661 global $thisimage; 3662 3663 extract(lAtts(array( 3664 'name' => '', 3665 'id' => '', 3666 'thumbnail' => 0, 3667 'link' => 'auto', 3668 ), $atts)); 3669 3670 $from_form = false; 3671 3672 if ($id) { 3673 $thisimage = imageFetchInfo('id = '.intval($id)); 3674 } elseif ($name) { 3675 $thisimage = imageFetchInfo("name = '".doSlash($name)."'"); 3676 } else { 3677 assert_image(); 3678 $from_form = true; 3679 } 3680 3681 if ($thisimage) { 3682 $url = imagesrcurl($thisimage['id'], $thisimage['ext'], $thumbnail); 3683 $link = ($link == 'auto') ? (($thing) ? 1 : 0) : $link; 3684 $out = ($thing) ? parse($thing) : $url; 3685 $out = ($link) ? href($out, $url) : $out; 3686 3687 if (!$from_form) { 3688 $thisimage = ''; 3689 } 3690 3691 return $out; 3692 } 3693 3694 return ''; 3695 } 3696 3697 // ------------------------------------------------------------- 3698 3699 function image_author($atts) 3700 { 3701 global $thisimage, $s; 3702 assert_image(); 3703 3704 extract(lAtts(array( 3705 'class' => '', 3706 'link' => 0, 3707 'title' => 1, 3708 'section' => '', 3709 'this_section' => '', 3710 'wraptag' => '', 3711 ), $atts)); 3712 3713 if ($thisimage['author']) { 3714 $author_name = get_author_name($thisimage['author']); 3715 $display_name = txpspecialchars(($title) ? $author_name : $thisimage['author']); 3716 3717 $section = ($this_section) ? ($s == 'default' ? '' : $s) : $section; 3718 3719 $author = ($link) 3720 ? href($display_name, pagelinkurl(array('s' => $section, 'author' => $author_name, 'context' => 'image'))) 3721 : $display_name; 3722 3723 return ($wraptag) ? doTag($author, $wraptag, $class) : $author; 3724 } 3725 } 3726 3727 // ------------------------------------------------------------- 3728 3729 function image_date($atts) 3730 { 3731 global $thisimage; 3732 3733 extract(lAtts(array( 3734 'name' => '', 3735 'id' => '', 3736 'format' => '', 3737 ), $atts)); 3738 3739 $from_form = false; 3740 3741 if ($id) { 3742 $thisimage = imageFetchInfo('id = '.intval($id)); 3743 } elseif ($name) { 3744 $thisimage = imageFetchInfo("name = '".doSlash($name)."'"); 3745 } else { 3746 assert_image(); 3747 $from_form = true; 3748 } 3749 3750 if (isset($thisimage['date'])) { 3751 // Not a typo: use fileDownloadFormatTime() since it's fit for purpose. 3752 $out = fileDownloadFormatTime(array( 3753 'ftime' => $thisimage['date'], 3754 'format' => $format, 3755 )); 3756 3757 if (!$from_form) { 3758 $thisimage = ''; 3759 } 3760 3761 return $out; 3762 } 3763 } 3764 3765 // ------------------------------------------------------------- 3766 3767 function if_thumbnail($atts, $thing) 3768 { 3769 global $thisimage; 3770 3771 assert_image(); 3772 3773 return parse($thing, ($thisimage['thumbnail'] == 1)); 3774 } 3775 3776 // ------------------------------------------------------------- 3777 3778 function if_comments($atts, $thing) 3779 { 3780 global $thisarticle; 3781 3782 assert_article(); 3783 3784 return parse($thing, ($thisarticle['comments_count'] > 0)); 3785 } 3786 3787 // ------------------------------------------------------------- 3788 3789 function if_comments_allowed($atts, $thing) 3790 { 3791 global $thisarticle; 3792 3793 assert_article(); 3794 3795 return parse($thing, checkCommentsAllowed($thisarticle['thisid'])); 3796 } 3797 3798 // ------------------------------------------------------------- 3799 3800 function if_comments_disallowed($atts, $thing) 3801 { 3802 global $thisarticle; 3803 3804 assert_article(); 3805 3806 return parse($thing, !checkCommentsAllowed($thisarticle['thisid'])); 3807 } 3808 3809 // ------------------------------------------------------------- 3810 3811 function if_individual_article($atts, $thing) 3812 { 3813 global $is_article_list; 3814 3815 return parse($thing, ($is_article_list == false)); 3816 } 3817 3818 // ------------------------------------------------------------- 3819 3820 function if_article_list($atts, $thing) 3821 { 3822 global $is_article_list; 3823 3824 return parse($thing, ($is_article_list == true)); 3825 } 3826 3827 /** 3828 * Returns article keywords. 3829 * 3830 * @param array $atts Tag attributes 3831 * @return string 3832 */ 3833 3834 function meta_keywords($atts) 3835 { 3836 global $id_keywords; 3837 3838 extract(lAtts(array( 3839 'escape' => 'html', 3840 'format' => 'meta', // or empty for raw value 3841 'separator' => '', 3842 ), $atts)); 3843 3844 $out = ''; 3845 3846 if ($id_keywords) { 3847 $content = ($escape === 'html') ? txpspecialchars($id_keywords) : $id_keywords; 3848 3849 if ($separator !== '') { 3850 $content = implode($separator, do_list($content)); 3851 } 3852 3853 if ($format === 'meta') { 3854 // Can't use tag_void() since it escapes its content. 3855 $out = '<meta name="keywords" content="'.$content.'" />'; 3856 } else { 3857 $out = $content; 3858 } 3859 } 3860 3861 return $out; 3862 } 3863 3864 /** 3865 * Returns article, section or category meta description info. 3866 * 3867 * @param array $atts Tag attributes 3868 * @return string 3869 */ 3870 3871 function meta_description($atts) 3872 { 3873 global $thisarticle, $thiscategory, $thissection, $s, $c, $context; 3874 3875 extract(lAtts(array( 3876 'escape' => 'html', 3877 'format' => 'meta', // or empty for raw value 3878 'type' => null, 3879 ), $atts)); 3880 3881 $out = ''; 3882 $content = getMetaDescription($type); 3883 3884 if ($content) { 3885 $content = ($escape === 'html' ? txpspecialchars($content) : $content); 3886 3887 if ($format === 'meta') { 3888 $out = '<meta name="description" content="'.$content.'" />'; 3889 } else { 3890 $out = $content; 3891 } 3892 } 3893 3894 return $out; 3895 } 3896 3897 /** 3898 * Determines if there is meta description content in the given context. 3899 * 3900 * @param array $atts Tag attributes 3901 * @param string $thing Tag container content 3902 * @return string 3903 */ 3904 3905 function if_description($atts, $thing = null) 3906 { 3907 global $thisarticle, $thiscategory, $thissection, $s, $c, $context; 3908 3909 extract(lAtts(array( 3910 'type' => null, 3911 ), $atts)); 3912 3913 $content = getMetaDescription($type); 3914 3915 return parse($thing, !empty($content)); 3916 } 3917 3918 3919 // ------------------------------------------------------------- 3920 3921 function meta_author($atts) 3922 { 3923 global $id_author; 3924 3925 extract(lAtts(array( 3926 'escape' => 'html', 3927 'format' => 'meta', // or empty for raw value 3928 'title' => 0, 3929 ), $atts)); 3930 3931 $out = ''; 3932 3933 if ($id_author) { 3934 $display_name = ($title) ? get_author_name($id_author) : $id_author; 3935 $display_name = ($escape === 'html') ? txpspecialchars($display_name) : $display_name; 3936 3937 if ($format === 'meta') { 3938 // Can't use tag_void() since it escapes its content. 3939 $out = '<meta name="author" content="'.$display_name.'" />'; 3940 } else { 3941 $out = $display_name; 3942 } 3943 } 3944 3945 return $out; 3946 } 3947 3948 // ------------------------------------------------------------- 3949 3950 function permlink($atts, $thing = null) 3951 { 3952 global $thisarticle; 3953 3954 extract(lAtts(array( 3955 'class' => '', 3956 'id' => '', 3957 'style' => '', 3958 'title' => '', 3959 ), $atts)); 3960 3961 if (!$id) { 3962 assert_article(); 3963 } 3964 3965 $url = ($id) ? permlinkurl_id($id) : permlinkurl($thisarticle); 3966 3967 if ($url) { 3968 if ($thing === null) { 3969 return $url; 3970 } 3971 3972 return tag(parse($thing), 'a', ' rel="bookmark" href="'.$url.'"'. 3973 ($title ? ' title="'.txpspecialchars($title).'"' : ''). 3974 ($style ? ' style="'.txpspecialchars($style).'"' : ''). 3975 ($class ? ' class="'.txpspecialchars($class).'"' : '') 3976 ); 3977 } 3978 } 3979 3980 // ------------------------------------------------------------- 3981 3982 function lang() 3983 { 3984 return txpspecialchars(LANG); 3985 } 3986 3987 /** 3988 * Formats article permanent links. 3989 * 3990 * @param int $ID 3991 * @param string $Section 3992 * @return string 3993 * @deprecated in 4.0.0 3994 */ 3995 3996 function formatPermLink($ID, $Section) 3997 { 3998 trigger_error(gTxt('deprecated_tag'), E_USER_NOTICE); 3999 4000 return permlinkurl_id($ID); 4001 } 4002 4003 /** 4004 * Formats comments invite link. 4005 * 4006 * @param string $AnnotateInvite 4007 * @param string $Section 4008 * @param int $ID 4009 * @return string 4010 * @deprecated in 4.0.0 4011 */ 4012 4013 function formatCommentsInvite($AnnotateInvite, $Section, $ID) 4014 { 4015 trigger_error(gTxt('deprecated_tag'), E_USER_NOTICE); 4016 4017 global $comments_mode; 4018 4019 $dc = safe_count('txp_discuss', "parentid = ".intval($ID)." AND visible = ".VISIBLE); 4020 4021 $ccount = ($dc) ? '['.$dc.']' : ''; 4022 if (!$comments_mode) { 4023 return '<a href="'.permlinkurl_id($ID).'/#'.gTxt('comment'). 4024 '">'.$AnnotateInvite.'</a>'.$ccount; 4025 } else { 4026 return "<a href=\"".hu."?parentid=$ID\" onclick=\"window.open(this.href, 'popupwindow', 'width=500,height=500,scrollbars,resizable,status'); return false;\">".$AnnotateInvite.'</a> '.$ccount; 4027 } 4028 } 4029 4030 /** 4031 * Formats article permanent link. 4032 * 4033 * @param string $text 4034 * @param string $plink 4035 * @param string $Title 4036 * @param string $url_title 4037 * @return string 4038 * @deprecated in 4.0.0 4039 */ 4040 4041 function doPermlink($text, $plink, $Title, $url_title) 4042 { 4043 trigger_error(gTxt('deprecated_tag'), E_USER_NOTICE); 4044 4045 global $url_mode; 4046 $Title = ($url_title) ? $url_title : stripSpace($Title); 4047 $Title = ($url_mode) ? $Title : ''; 4048 4049 return preg_replace("/<(txp:permlink)>(.*)<\/\\1>/sU", 4050 "<a href=\"".$plink.$Title."\" title=\"".gTxt('permanent_link')."\">$2</a>", $text); 4051 } 4052 4053 /** 4054 * Formats article link. 4055 * 4056 * @param int $ID 4057 * @param string $Title 4058 * @param string $url_title 4059 * @param string $Section 4060 * @return string 4061 * @deprecated in 4.0.0 4062 */ 4063 4064 function doArticleHref($ID, $Title, $url_title, $Section) 4065 { 4066 trigger_error(gTxt('deprecated_tag'), E_USER_NOTICE); 4067 4068 $conTitle = ($url_title) ? $url_title : stripSpace($Title); 4069 4070 return ($GLOBALS['url_mode']) 4071 ? tag($Title, 'a', ' href="'.hu.$Section.'/'.$ID.'/'.$conTitle.'"') 4072 : tag($Title, 'a', ' href="'.hu.'index.php?id='.$ID.'"'); 4073 } 4074 4075 // ------------------------------------------------------------- 4076 4077 function breadcrumb($atts) 4078 { 4079 global $pretext, $sitename; 4080 4081 extract(lAtts(array( 4082 'wraptag' => 'p', 4083 'sep' => ' » ', // Deprecated in 4.3.0. 4084 'separator' => ' » ', 4085 'link' => 1, 4086 'label' => $sitename, 4087 'title' => '', 4088 'class' => '', 4089 'linkclass' => '', 4090 ), $atts)); 4091 4092 if (isset($atts['sep'])) { 4093 $separator = $sep; 4094 trigger_error(gTxt('deprecated_attribute', array('{name}' => 'sep')), E_USER_NOTICE); 4095 } 4096 4097 // For BC, get rid of in crockery. 4098 if ($link == 'y') { 4099 $linked = true; 4100 } elseif ($link == 'n') { 4101 $linked = false; 4102 } else { 4103 $linked = $link; 4104 } 4105 4106 $label = txpspecialchars($label); 4107 4108 if ($linked) { 4109 $label = doTag($label, 'a', $linkclass, ' href="'.hu.'"'); 4110 } 4111 4112 $content = array(); 4113 extract($pretext); 4114 4115 if (!empty($s) && $s != 'default') { 4116 $section_title = ($title) ? fetch_section_title($s) : $s; 4117 $section_title_html = escape_title($section_title); 4118 $content[] = ($linked) 4119 ? (doTag($section_title_html, 'a', $linkclass, ' href="'.pagelinkurl(array('s' => $s)).'"')) 4120 : $section_title_html; 4121 } 4122 4123 $category = empty($c) ? '' : $c; 4124 4125 foreach (getTreePath($category, 'article') as $cat) { 4126 if ($cat['name'] != 'root') { 4127 $category_title_html = $title ? escape_title($cat['title']) : $cat['name']; 4128 $content[] = ($linked) 4129 ? doTag($category_title_html, 'a', $linkclass, ' href="'.pagelinkurl(array('c' => $cat['name'])).'"') 4130 : $category_title_html; 4131 } 4132 } 4133 4134 // Add the label at the end, to prevent breadcrumb for homepage. 4135 if ($content) { 4136 $content = array_merge(array($label), $content); 4137 4138 return doTag(join($separator, $content), $wraptag, $class); 4139 } 4140 } 4141 4142 //------------------------------------------------------------------------ 4143 4144 function if_excerpt($atts, $thing) 4145 { 4146 global $thisarticle; 4147 4148 assert_article(); 4149 4150 return parse($thing, trim($thisarticle['excerpt']) !== ''); 4151 } 4152 4153 // ------------------------------------------------------------- 4154 // Searches use default page. This tag allows you to use different templates if searching 4155 // ------------------------------------------------------------- 4156 4157 function if_search($atts, $thing) 4158 { 4159 global $pretext; 4160 4161 return parse($thing, !empty($pretext['q'])); 4162 } 4163 4164 // ------------------------------------------------------------- 4165 4166 function if_search_results($atts, $thing) 4167 { 4168 global $thispage, $pretext; 4169 4170 if (empty($pretext['q'])) { 4171 return ''; 4172 } 4173 4174 extract(lAtts(array( 4175 'min' => 1, 4176 'max' => 0, 4177 ), $atts)); 4178 4179 $results = (int) $thispage['grand_total']; 4180 4181 return parse($thing, $results >= $min && (!$max || $results <= $max)); 4182 } 4183 4184 // ------------------------------------------------------------- 4185 4186 function if_category($atts, $thing) 4187 { 4188 global $c, $context; 4189 4190 extract(lAtts(array( 4191 'type' => 'article', 4192 'name' => false, 4193 ), $atts)); 4194 4195 $theType = ($type) ? $type == $context : true; 4196 4197 if ($name === false) { 4198 return parse($thing, ($theType && !empty($c))); 4199 } else { 4200 return parse($thing, ($theType && in_list($c, $name))); 4201 } 4202 } 4203 4204 // ------------------------------------------------------------- 4205 4206 function if_article_category($atts, $thing) 4207 { 4208 global $thisarticle; 4209 4210 assert_article(); 4211 4212 extract(lAtts(array( 4213 'name' => '', 4214 'number' => '', 4215 ), $atts)); 4216 4217 $cats = array(); 4218 4219 if ($number) { 4220 if (!empty($thisarticle['category'.$number])) { 4221 $cats = array($thisarticle['category'.$number]); 4222 } 4223 } else { 4224 if (!empty($thisarticle['category1'])) { 4225 $cats[] = $thisarticle['category1']; 4226 } 4227 4228 if (!empty($thisarticle['category2'])) { 4229 $cats[] = $thisarticle['category2']; 4230 } 4231 4232 $cats = array_unique($cats); 4233 } 4234 4235 if ($name) { 4236 return parse($thing, array_intersect(do_list($name), $cats)); 4237 } else { 4238 return parse($thing, ($cats)); 4239 } 4240 } 4241 4242 // ------------------------------------------------------------- 4243 4244 function if_first_category($atts, $thing) 4245 { 4246 global $thiscategory; 4247 4248 assert_category(); 4249 4250 return parse($thing, !empty($thiscategory['is_first'])); 4251 } 4252 4253 // ------------------------------------------------------------- 4254 4255 function if_last_category($atts, $thing) 4256 { 4257 global $thiscategory; 4258 4259 assert_category(); 4260 4261 return parse($thing, !empty($thiscategory['is_last'])); 4262 } 4263 4264 // ------------------------------------------------------------- 4265 4266 function if_section($atts, $thing) 4267 { 4268 global $pretext; 4269 extract($pretext); 4270 4271 extract(lAtts(array( 4272 'name' => false, 4273 ), $atts)); 4274 4275 $section = ($s == 'default' ? '' : $s); 4276 4277 if ($section) { 4278 return parse($thing, $name === false or in_list($section, $name)); 4279 } else { 4280 return parse($thing, $name !== false and (in_list('', $name) or in_list('default', $name))); 4281 } 4282 } 4283 4284 // ------------------------------------------------------------- 4285 4286 function if_article_section($atts, $thing) 4287 { 4288 global $thisarticle; 4289 4290 assert_article(); 4291 4292 extract(lAtts(array( 4293 'name' => '', 4294 ), $atts)); 4295 4296 $section = $thisarticle['section']; 4297 4298 return parse($thing, in_list($section, $name)); 4299 } 4300 4301 // ------------------------------------------------------------- 4302 4303 function if_first_section($atts, $thing) 4304 { 4305 global $thissection; 4306 4307 assert_section(); 4308 4309 return parse($thing, !empty($thissection['is_first'])); 4310 } 4311 4312 // ------------------------------------------------------------- 4313 4314 function if_last_section($atts, $thing) 4315 { 4316 global $thissection; 4317 4318 assert_section(); 4319 4320 return parse($thing, !empty($thissection['is_last'])); 4321 } 4322 4323 // ------------------------------------------------------------- 4324 4325 function php($atts, $thing) 4326 { 4327 global $is_article_body, $thisarticle, $prefs; 4328 4329 if (assert_array($prefs) === false) { 4330 return ''; 4331 } 4332 4333 ob_start(); 4334 4335 if (empty($is_article_body)) { 4336 if (!empty($prefs['allow_page_php_scripting'])) { 4337 eval($thing); 4338 } else { 4339 trigger_error(gTxt('php_code_disabled_page')); 4340 } 4341 } else { 4342 if (!empty($prefs['allow_article_php_scripting'])) { 4343 if (has_privs('article.php', $thisarticle['authorid'])) { 4344 eval($thing); 4345 } else { 4346 trigger_error(gTxt('php_code_forbidden_user')); 4347 } 4348 } else { 4349 trigger_error(gTxt('php_code_disabled_article')); 4350 } 4351 } 4352 4353 return ob_get_clean(); 4354 } 4355 4356 // ------------------------------------------------------------- 4357 4358 function custom_field($atts) 4359 { 4360 global $is_article_body, $thisarticle; 4361 4362 assert_article(); 4363 4364 extract(lAtts(array( 4365 'name' => get_pref('custom_1_set'), 4366 'escape' => 'html', 4367 'default' => '', 4368 ), $atts)); 4369 4370 $name = strtolower($name); 4371 4372 if (!isset($thisarticle[$name])) { 4373 trigger_error(gTxt('field_not_found', array('{name}' => $name)), E_USER_NOTICE); 4374 4375 return ''; 4376 } 4377 4378 if ($thisarticle[$name] !== '') { 4379 $out = $thisarticle[$name]; 4380 } else { 4381 $out = $default; 4382 } 4383 4384 $was_article_body = $is_article_body; 4385 $is_article_body = 1; 4386 $out = ($escape == 'html' ? txpspecialchars($out) : parse($out)); 4387 $is_article_body = $was_article_body; 4388 4389 return $out; 4390 } 4391 4392 // ------------------------------------------------------------- 4393 4394 function if_custom_field($atts, $thing) 4395 { 4396 global $thisarticle; 4397 4398 assert_article(); 4399 4400 extract(lAtts(array( 4401 'name' => get_pref('custom_1_set'), 4402 'value' => null, 4403 'val' => null, // Deprecated in 4.3.0. 4404 'match' => 'exact', 4405 'separator' => '', 4406 ), $atts)); 4407 4408 if (isset($atts['val'])) { 4409 $value = $val; 4410 trigger_error(gTxt('deprecated_attribute', array('{name}' => 'val')), E_USER_NOTICE); 4411 } 4412 4413 $name = strtolower($name); 4414 4415 if (!isset($thisarticle[$name])) { 4416 trigger_error(gTxt('field_not_found', array('{name}' => $name)), E_USER_NOTICE); 4417 4418 return ''; 4419 } 4420 4421 if ($value !== null) { 4422 switch ($match) { 4423 case '': 4424 case 'exact': 4425 $cond = ($thisarticle[$name] == $value); 4426 break; 4427 case 'any': 4428 $values = do_list($value); 4429 $cond = false; 4430 $cf_contents = ($separator) ? do_list($thisarticle[$name], $separator) : $thisarticle[$name]; 4431 foreach ($values as $term) { 4432 if ($term == '') { 4433 continue; 4434 } 4435 4436 $cond = is_array($cf_contents) ? in_array($term, $cf_contents) : ((strpos($cf_contents, $term) !== false) ? true : false); 4437 4438 // Short circuit if a match is found. 4439 if ($cond) { 4440 break; 4441 } 4442 } 4443 break; 4444 case 'all': 4445 $values = do_list($value); 4446 $num_values = count($values); 4447 $term_count = 0; 4448 $cf_contents = ($separator) ? do_list($thisarticle[$name], $separator) : $thisarticle[$name]; 4449 foreach ($values as $term) { 4450 if ($term == '') { 4451 continue; 4452 } 4453 4454 $term_count += is_array($cf_contents) ? in_array($term, $cf_contents) : ((strpos($cf_contents, $term) !== false) ? true : false); 4455 } 4456 $cond = ($term_count == $num_values) ? true : false; 4457 break; 4458 case 'pattern': 4459 // Cannot guarantee that a fixed delimiter won't break preg_match 4460 // (and preg_quote doesn't help) so dynamically assign the delimiter 4461 // based on the first entry in $dlmPool that is NOT in the value 4462 // attribute. This minimises (does not eliminate) the possibility 4463 // of a TXP-initiated preg_match error, while still preserving 4464 // errors outside TXP's control (e.g. mangled user-submitted 4465 // PCRE pattern). 4466 $dlmPool = array('/', '@', '#', '~', '`', '|', '!', '%'); 4467 $dlm = array_merge(array_diff($dlmPool, preg_split('//', $value, -1))); 4468 $dlm = (count($dlm) > 0) ? $dlm[0].$value.$dlm[0] : $value; 4469 $cond = preg_match($dlm, $thisarticle[$name]); 4470 break; 4471 default: 4472 trigger_error(gTxt('invalid_attribute_value', array('{name}' => 'value')), E_USER_NOTICE); 4473 $cond = false; 4474 } 4475 } else { 4476 $cond = ($thisarticle[$name] !== ''); 4477 } 4478 4479 return parse($thing, !empty($cond)); 4480 } 4481 4482 // ------------------------------------------------------------- 4483 4484 function site_url() 4485 { 4486 return hu; 4487 } 4488 4489 // ------------------------------------------------------------- 4490 4491 function error_message() 4492 { 4493 global $txp_error_message; 4494 4495 return $txp_error_message; 4496 } 4497 4498 // ------------------------------------------------------------- 4499 4500 function error_status() 4501 { 4502 global $txp_error_status; 4503 4504 return $txp_error_status; 4505 } 4506 4507 // ------------------------------------------------------------- 4508 4509 function if_status($atts, $thing) 4510 { 4511 global $pretext, $txp_error_code; 4512 4513 extract(lAtts(array( 4514 'status' => '200', 4515 ), $atts)); 4516 4517 $page_status = $txp_error_code 4518 ? $txp_error_code 4519 : $pretext['status']; 4520 4521 return parse($thing, $status == $page_status); 4522 } 4523 4524 // ------------------------------------------------------------- 4525 4526 function page_url($atts) 4527 { 4528 global $pretext; 4529 4530 extract(lAtts(array( 4531 'type' => 'request_uri', 4532 ), $atts)); 4533 4534 if ($type == 'pg' and $pretext['pg'] == '') { 4535 return '1'; 4536 } 4537 4538 return @txpspecialchars($pretext[$type]); 4539 } 4540 4541 // ------------------------------------------------------------- 4542 4543 function if_different($atts, $thing) 4544 { 4545 static $last; 4546 4547 $key = md5($thing); 4548 $out = parse($thing, 1); 4549 4550 if (empty($last[$key]) or $out != $last[$key]) { 4551 return $last[$key] = $out; 4552 } else { 4553 return parse($thing, 0); 4554 } 4555 } 4556 4557 // ------------------------------------------------------------- 4558 4559 function if_first_article($atts, $thing) 4560 { 4561 global $thisarticle; 4562 4563 assert_article(); 4564 4565 return parse($thing, !empty($thisarticle['is_first'])); 4566 } 4567 4568 // ------------------------------------------------------------- 4569 4570 function if_last_article($atts, $thing) 4571 { 4572 global $thisarticle; 4573 4574 assert_article(); 4575 4576 return parse($thing, !empty($thisarticle['is_last'])); 4577 } 4578 4579 // ------------------------------------------------------------- 4580 4581 function if_plugin($atts, $thing) 4582 { 4583 global $plugins, $plugins_ver; 4584 4585 extract(lAtts(array( 4586 'name' => '', 4587 'ver' => '', // Deprecated in 4.3.0. 4588 'version' => '', 4589 ), $atts)); 4590 4591 if (isset($atts['ver'])) { 4592 $version = $ver; 4593 trigger_error(gTxt('deprecated_attribute', array('{name}' => 'ver')), E_USER_NOTICE); 4594 } 4595 4596 return parse($thing, @in_array($name, $plugins) and (!$version or version_compare($plugins_ver[$name], $version) >= 0)); 4597 } 4598 4599 // ------------------------------------------------------------- 4600 4601 function file_download_list($atts, $thing = null) 4602 { 4603 global $s, $c, $context, $thisfile, $thispage, $pretext; 4604 4605 extract(lAtts(array( 4606 'break' => br, 4607 'category' => '', 4608 'author' => '', 4609 'realname' => '', 4610 'auto_detect' => 'category, author', 4611 'class' => __FUNCTION__, 4612 'form' => 'files', 4613 'id' => '', 4614 'label' => '', 4615 'labeltag' => '', 4616 'pageby' => '', 4617 'limit' => 10, 4618 'offset' => 0, 4619 'sort' => 'filename asc', 4620 'wraptag' => '', 4621 'status' => STATUS_LIVE, 4622 ), $atts)); 4623 4624 if (!is_numeric($status)) { 4625 $status = getStatusNum($status); 4626 } 4627 4628 // Note: status treated slightly differently. 4629 $where = $statwhere = array(); 4630 $filters = isset($atts['id']) || isset($atts['category']) || isset($atts['author']) || isset($atts['realname']) || isset($atts['status']); 4631 $context_list = (empty($auto_detect) || $filters) ? array() : do_list_unique($auto_detect); 4632 $pageby = ($pageby == 'limit') ? $limit : $pageby; 4633 4634 if ($category) { 4635 $where[] = "category IN ('".join("','", doSlash(do_list_unique($category)))."')"; 4636 } 4637 4638 $ids = array_map('intval', do_list_unique($id)); 4639 4640 if ($id) { 4641 $where[] = "id IN ('".join("','", $ids)."')"; 4642 } 4643 4644 if ($status) { 4645 $statwhere[] = "status = '".doSlash($status)."'"; 4646 } 4647 4648 if ($author) { 4649 $where[] = "author IN ('".join("','", doSlash(do_list_unique($author)))."')"; 4650 } 4651 4652 if ($realname) { 4653 $authorlist = safe_column("name", 'txp_users', "RealName IN ('".join("','", doArray(doSlash(do_list_unique($realname)), 'urldecode'))."')"); 4654 if ($authorlist) { 4655 $where[] = "author IN ('".join("','", doSlash($authorlist))."')"; 4656 } 4657 } 4658 4659 // If no files are selected, try... 4660 if (!$where && !$filters) { 4661 foreach ($context_list as $ctxt) { 4662 switch ($ctxt) { 4663 case 'category': 4664 // ...the global category in the URL. 4665 if ($context == 'file' && !empty($c)) { 4666 $where[] = "category = '".doSlash($c)."'"; 4667 } 4668 break; 4669 case 'author': 4670 // ...the global author in the URL. 4671 if ($context == 'file' && !empty($pretext['author'])) { 4672 $where[] = "author = '".doSlash($pretext['author'])."'"; 4673 } 4674 break; 4675 } 4676 4677 // Only one context can be processed. 4678 if ($where) { 4679 break; 4680 } 4681 } 4682 } 4683 4684 if (!$where && !$statwhere && $filters) { 4685 // If nothing matches, output nothing. 4686 return ''; 4687 } 4688 4689 $where[] = "created <= ".now('created'); 4690 4691 $where = join(" AND ", array_merge($where, $statwhere)); 4692 4693 // Set up paging if required. 4694 if ($limit && $pageby) { 4695 $grand_total = safe_count('txp_file', $where); 4696 $total = $grand_total - $offset; 4697 $numPages = ($pageby > 0) ? ceil($total/$pageby) : 1; 4698 $pg = (!$pretext['pg']) ? 1 : $pretext['pg']; 4699 $pgoffset = $offset + (($pg - 1) * $pageby); 4700 4701 // Send paging info to txp:newer and txp:older. 4702 $pageout['pg'] = $pg; 4703 $pageout['numPages'] = $numPages; 4704 $pageout['s'] = $s; 4705 $pageout['c'] = $c; 4706 $pageout['context'] = 'file'; 4707 $pageout['grand_total'] = $grand_total; 4708 $pageout['total'] = $total; 4709 4710 if (empty($thispage)) { 4711 $thispage = $pageout; 4712 } 4713 } else { 4714 $pgoffset = $offset; 4715 } 4716 4717 // Preserve order of custom file ids unless 'sort' attribute is set. 4718 if (!empty($atts['id']) && empty($atts['sort'])) { 4719 $safe_sort = "FIELD(id, ".join(',', $ids).")"; 4720 } else { 4721 $safe_sort = doSlash($sort); 4722 } 4723 4724 $qparts = array( 4725 "ORDER BY ".$safe_sort, 4726 ($limit) ? "LIMIT ".intval($pgoffset).", ".intval($limit) : '', 4727 ); 4728 4729 $rs = safe_rows_start("*", 'txp_file', $where.' '.join(' ', $qparts)); 4730 4731 if ($rs) { 4732 $count = 0; 4733 $last = numRows($rs); 4734 $out = array(); 4735 4736 while ($a = nextRow($rs)) { 4737 ++$count; 4738 $thisfile = file_download_format_info($a); 4739 $thisfile['is_first'] = ($count == 1); 4740 $thisfile['is_last'] = ($count == $last); 4741 4742 $out[] = ($thing) ? parse($thing) : parse_form($form); 4743 4744 $thisfile = ''; 4745 } 4746 4747 if ($out) { 4748 return doLabel($label, $labeltag).doWrap($out, $wraptag, $break, $class); 4749 } 4750 } 4751 4752 return ''; 4753 } 4754 4755 // ------------------------------------------------------------- 4756 4757 function file_download($atts, $thing = null) 4758 { 4759 global $thisfile; 4760 4761 extract(lAtts(array( 4762 'filename' => '', 4763 'form' => 'files', 4764 'id' => '', 4765 ), $atts)); 4766 4767 $from_form = false; 4768 4769 if ($id) { 4770 $thisfile = fileDownloadFetchInfo('id = '.intval($id).' and created <= '.now('created')); 4771 } elseif ($filename) { 4772 $thisfile = fileDownloadFetchInfo("filename = '".doSlash($filename)."' and created <= ".now('created')); 4773 } else { 4774 assert_file(); 4775 4776 $from_form = true; 4777 } 4778 4779 if ($thisfile) { 4780 $out = ($thing) ? parse($thing) : parse_form($form); 4781 4782 // Cleanup: this wasn't called from a form, so we don't want this 4783 // value remaining. 4784 if (!$from_form) { 4785 $thisfile = ''; 4786 } 4787 4788 return $out; 4789 } 4790 } 4791 4792 // ------------------------------------------------------------- 4793 4794 function file_download_link($atts, $thing = null) 4795 { 4796 global $thisfile; 4797 4798 extract(lAtts(array( 4799 'filename' => '', 4800 'id' => '', 4801 ), $atts)); 4802 4803 $from_form = false; 4804 4805 if ($id) { 4806 $thisfile = fileDownloadFetchInfo('id = '.intval($id).' and created <= '.now('created')); 4807 } elseif ($filename) { 4808 $thisfile = fileDownloadFetchInfo("filename = '".doSlash($filename)."' and created <= ".now('created')); 4809 } else { 4810 assert_file(); 4811 4812 $from_form = true; 4813 } 4814 4815 if ($thisfile) { 4816 $url = filedownloadurl($thisfile['id'], $thisfile['filename']); 4817 4818 $out = ($thing) ? href(parse($thing), $url) : $url; 4819 4820 // Cleanup: this wasn't called from a form, so we don't want this 4821 // value remaining 4822 if (!$from_form) { 4823 $thisfile = ''; 4824 } 4825 4826 return $out; 4827 } 4828 } 4829 4830 // ------------------------------------------------------------- 4831 4832 function file_download_size($atts) 4833 { 4834 global $thisfile; 4835 4836 assert_file(); 4837 4838 extract(lAtts(array( 4839 'decimals' => 2, 4840 'format' => '', 4841 ), $atts)); 4842 4843 if (is_numeric($decimals) and $decimals >= 0) { 4844 $decimals = intval($decimals); 4845 } else { 4846 $decimals = 2; 4847 } 4848 4849 if (isset($thisfile['size'])) { 4850 $format_unit = strtolower(substr($format, 0, 1)); 4851 4852 return format_filesize($thisfile['size'], $decimals, $format_unit); 4853 } else { 4854 return ''; 4855 } 4856 } 4857 4858 // ------------------------------------------------------------- 4859 4860 function file_download_created($atts) 4861 { 4862 global $thisfile; 4863 4864 assert_file(); 4865 4866 extract(lAtts(array( 4867 'format' => '', 4868 ), $atts)); 4869 4870 if ($thisfile['created']) { 4871 return fileDownloadFormatTime(array( 4872 'ftime' => $thisfile['created'], 4873 'format' => $format, 4874 )); 4875 } 4876 } 4877 4878 // ------------------------------------------------------------- 4879 4880 function file_download_modified($atts) 4881 { 4882 global $thisfile; 4883 4884 assert_file(); 4885 4886 extract(lAtts(array( 4887 'format' => '', 4888 ), $atts)); 4889 4890 if ($thisfile['modified']) { 4891 return fileDownloadFormatTime(array( 4892 'ftime' => $thisfile['modified'], 4893 'format' => $format, 4894 )); 4895 } 4896 } 4897 4898 // ------------------------------------------------------------- 4899 4900 function file_download_id() 4901 { 4902 global $thisfile; 4903 4904 assert_file(); 4905 4906 return $thisfile['id']; 4907 } 4908 4909 // ------------------------------------------------------------- 4910 4911 function file_download_name($atts) 4912 { 4913 global $thisfile; 4914 4915 assert_file(); 4916 4917 extract(lAtts(array( 4918 'title' => 0, 4919 ), $atts)); 4920 4921 return ($title) ? $thisfile['title'] : $thisfile['filename']; 4922 } 4923 4924 // ------------------------------------------------------------- 4925 4926 function file_download_category($atts) 4927 { 4928 global $thisfile; 4929 4930 assert_file(); 4931 4932 extract(lAtts(array( 4933 'class' => '', 4934 'title' => 0, 4935 'wraptag' => '', 4936 ), $atts)); 4937 4938 if ($thisfile['category']) { 4939 $category = ($title) 4940 ? fetch_category_title($thisfile['category'], 'file') 4941 : $thisfile['category']; 4942 4943 return ($wraptag) ? doTag($category, $wraptag, $class) : $category; 4944 } 4945 } 4946 4947 // ------------------------------------------------------------- 4948 4949 function file_download_author($atts) 4950 { 4951 global $thisfile, $s; 4952 4953 assert_file(); 4954 4955 extract(lAtts(array( 4956 'class' => '', 4957 'link' => 0, 4958 'title' => 1, 4959 'section' => '', 4960 'this_section' => '', 4961 'wraptag' => '', 4962 ), $atts)); 4963 4964 if ($thisfile['author']) { 4965 $author_name = get_author_name($thisfile['author']); 4966 $display_name = txpspecialchars(($title) ? $author_name : $thisfile['author']); 4967 4968 $section = ($this_section) ? ($s == 'default' ? '' : $s) : $section; 4969 4970 $author = ($link) 4971 ? href($display_name, pagelinkurl(array('s' => $section, 'author' => $author_name, 'context' => 'file'))) 4972 : $display_name; 4973 4974 return ($wraptag) ? doTag($author, $wraptag, $class) : $author; 4975 } 4976 } 4977 4978 // ------------------------------------------------------------- 4979 4980 function file_download_downloads() 4981 { 4982 global $thisfile; 4983 4984 assert_file(); 4985 4986 return $thisfile['downloads']; 4987 } 4988 4989 // ------------------------------------------------------------- 4990 4991 function file_download_description($atts) 4992 { 4993 global $thisfile; 4994 4995 assert_file(); 4996 4997 extract(lAtts(array( 4998 'class' => '', 4999 'escape' => 'html', 5000 'wraptag' => '', 5001 ), $atts)); 5002 5003 if ($thisfile['description']) { 5004 $description = ($escape == 'html') 5005 ? txpspecialchars($thisfile['description']) 5006 : $thisfile['description']; 5007 5008 return ($wraptag) ? doTag($description, $wraptag, $class) : $description; 5009 } 5010 } 5011 5012 // ------------------------------------------------------------- 5013 5014 function hide() 5015 { 5016 return ''; 5017 } 5018 5019 // ------------------------------------------------------------- 5020 5021 function rsd() 5022 { 5023 global $prefs; 5024 5025 trigger_error(gTxt('deprecated_tag'), E_USER_NOTICE); 5026 5027 return ($prefs['enable_xmlrpc_server']) ? '<link rel="EditURI" type="application/rsd+xml" title="RSD" href="'.hu.'rpc/" />' : ''; 5028 } 5029 5030 // ------------------------------------------------------------- 5031 5032 function variable($atts, $thing = null) 5033 { 5034 global $variable, $trace; 5035 5036 extract(lAtts(array( 5037 'name' => '', 5038 'value' => $thing !== null ? parse($thing) : null, 5039 ), $atts)); 5040 5041 if (empty($name)) { 5042 trigger_error(gTxt('variable_name_empty')); 5043 5044 return; 5045 } 5046 5047 if (!isset($atts['value']) && is_null($thing)) { 5048 if (isset($variable[$name])) { 5049 return $variable[$name]; 5050 } else { 5051 $trace->log("[<txp:variable>: Unknown variable '$name']"); 5052 5053 return ''; 5054 } 5055 } else { 5056 $variable[$name] = $value; 5057 } 5058 } 5059 5060 // ------------------------------------------------------------- 5061 5062 function if_variable($atts, $thing = null) 5063 { 5064 global $variable; 5065 5066 extract(lAtts(array( 5067 'name' => '', 5068 'value' => '', 5069 ), $atts)); 5070 5071 if (empty($name)) { 5072 trigger_error(gTxt('variable_name_empty')); 5073 5074 return; 5075 } 5076 5077 if (isset($variable[$name])) { 5078 if (!isset($atts['value'])) { 5079 $x = true; 5080 } else { 5081 $x = $variable[$name] == $value; 5082 } 5083 } else { 5084 $x = false; 5085 } 5086 5087 return parse($thing, $x); 5088 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
title