| [ Index ] |
PHP Cross Reference of MantisBT |
[Summary view] [Print] [Text view]
1 <?php 2 # MantisBT - A PHP based bugtracking system 3 4 # MantisBT is free software: you can redistribute it and/or modify 5 # it under the terms of the GNU General Public License as published by 6 # the Free Software Foundation, either version 2 of the License, or 7 # (at your option) any later version. 8 # 9 # MantisBT is distributed in the hope that it will be useful, 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # GNU General Public License for more details. 13 # 14 # You should have received a copy of the GNU General Public License 15 # along with MantisBT. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * String Processing API 19 * 20 * @package CoreAPI 21 * @subpackage StringProcessingAPI 22 * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org 23 * @copyright Copyright (C) 2002 - 2011 MantisBT Team - mantisbt-dev@lists.sourceforge.net 24 * @link http://www.mantisbt.org 25 * 26 * @uses access_api.php 27 * @uses authentication_api.php 28 * @uses bug_api.php 29 * @uses bugnote_api.php 30 * @uses config_api.php 31 * @uses constant_inc.php 32 * @uses email_api.php 33 * @uses event_api.php 34 * @uses helper_api.php 35 * @uses lang_api.php 36 * @uses user_api.php 37 * @uses utility_api.php 38 */ 39 40 require_api( 'access_api.php' ); 41 require_api( 'authentication_api.php' ); 42 require_api( 'bug_api.php' ); 43 require_api( 'bugnote_api.php' ); 44 require_api( 'config_api.php' ); 45 require_api( 'constant_inc.php' ); 46 require_api( 'email_api.php' ); 47 require_api( 'event_api.php' ); 48 require_api( 'helper_api.php' ); 49 require_api( 'lang_api.php' ); 50 require_api( 'user_api.php' ); 51 require_api( 'utility_api.php' ); 52 53 $g_cache_html_valid_tags = ''; 54 $g_cache_html_valid_tags_single_line = ''; 55 56 /** 57 * Preserve spaces at beginning of lines. 58 * Lines must be separated by \n rather than <br /> 59 * @param string $p_string 60 * @return string 61 */ 62 function string_preserve_spaces_at_bol( $p_string ) { 63 $lines = explode( "\n", $p_string ); 64 $line_count = count( $lines ); 65 for( $i = 0;$i < $line_count;$i++ ) { 66 $count = 0; 67 $prefix = ''; 68 69 $t_char = utf8_substr( $lines[$i], $count, 1 ); 70 $spaces = 0; 71 while(( $t_char == ' ' ) || ( $t_char == "\t" ) ) { 72 if( $t_char == ' ' ) { 73 $spaces++; 74 } else { 75 $spaces += 4; 76 } 77 78 // 1 tab = 4 spaces, can be configurable. 79 80 $count++; 81 $t_char = utf8_substr( $lines[$i], $count, 1 ); 82 } 83 84 for( $j = 0;$j < $spaces;$j++ ) { 85 $prefix .= ' '; 86 } 87 88 $lines[$i] = $prefix . utf8_substr( $lines[$i], $count ); 89 } 90 return implode( "\n", $lines ); 91 } 92 93 /** 94 * Prepare a string to be printed without being broken into multiple lines 95 * @param string $p_string 96 * @return string 97 */ 98 function string_no_break( $p_string ) { 99 if( strpos( $p_string, ' ' ) !== false ) { 100 return '<span class="nowrap">' . $p_string . "</span>"; 101 } else { 102 return $p_string; 103 } 104 } 105 106 /** 107 * Similar to nl2br, but fixes up a problem where new lines are doubled between 108 * html pre tags. 109 * additionally, wrap the text an $p_wrap character intervals if the config is set 110 * @param string $p_string 111 * @param int $p_wrap 112 * @return string 113 */ 114 function string_nl2br( $p_string, $p_wrap = 100 ) { 115 $output = ''; 116 $pieces = preg_split( '/(<pre[^>]*>.*?<\/pre>)/is', $p_string, -1, PREG_SPLIT_DELIM_CAPTURE ); 117 if( isset( $pieces[1] ) ) { 118 foreach( $pieces as $piece ) { 119 if( preg_match( '/(<pre[^>]*>.*?<\/pre>)/is', $piece ) ) { 120 $piece = preg_replace( "/<br[^>]*?>/", '', $piece ); 121 122 # @@@ thraxisp - this may want to be replaced by html_entity_decode (or equivalent) 123 # if other encoded characters are a problem 124 $piece = preg_replace( '/ /', ' ', $piece ); 125 if( ON == config_get( 'wrap_in_preformatted_text' ) ) { 126 $output .= preg_replace( '/([^\n]{' . $p_wrap . ',}?[\s]+)(?!<\/pre>)/', "$1\n", $piece ); 127 } else { 128 $output .= $piece; 129 } 130 } else { 131 $output .= nl2br( $piece ); 132 } 133 } 134 return $output; 135 } else { 136 return nl2br( $p_string ); 137 } 138 } 139 140 /** 141 * Prepare a multiple line string for display to HTML 142 * @param string $p_string 143 * @return string 144 */ 145 function string_display( $p_string ) { 146 $t_data = event_signal( 'EVENT_DISPLAY_TEXT', $p_string, true ); 147 return $t_data; 148 } 149 150 /** 151 * Prepare a single line string for display to HTML 152 * @param string $p_string 153 * @return string 154 */ 155 function string_display_line( $p_string ) { 156 $t_data = event_signal( 'EVENT_DISPLAY_TEXT', $p_string, false ); 157 return $t_data; 158 } 159 160 /** 161 * Prepare a string for display to HTML and add href anchors for URLs, emails 162 * and bug references 163 * @param string $p_string 164 * @return string 165 */ 166 function string_display_links( $p_string ) { 167 $t_data = event_signal( 'EVENT_DISPLAY_FORMATTED', $p_string, true ); 168 return $t_data; 169 } 170 171 /** 172 * Prepare a single line string for display to HTML and add href anchors for 173 * URLs, emails and bug references 174 * @param string $p_string 175 * @return string 176 */ 177 function string_display_line_links( $p_string ) { 178 $t_data = event_signal( 'EVENT_DISPLAY_FORMATTED', $p_string, false ); 179 return $t_data; 180 } 181 182 /** 183 * Prepare a string for display in rss 184 * @param string 185 * @return string 186 */ 187 function string_rss_links( $p_string ) { 188 # rss can not start with   which spaces will be replaced into by string_display(). 189 $t_string = trim( $p_string ); 190 191 $t_string = event_signal( 'EVENT_DISPLAY_RSS', $t_string ); 192 193 # another escaping to escape the special characters created by the generated links 194 return string_html_specialchars( $t_string ); 195 } 196 197 /** 198 * Prepare a string for plain text display in email 199 * @param string $p_string 200 * @return string 201 */ 202 function string_email( $p_string ) { 203 return string_strip_hrefs( $p_string ); 204 } 205 206 /** 207 * Prepare a string for plain text display in email and add URLs for bug 208 * links 209 * @param string 210 * @return string 211 */ 212 function string_email_links( $p_string ) { 213 return event_signal( 'EVENT_DISPLAY_EMAIL', $p_string ); 214 } 215 216 # -------------------- 217 # Process a string for display in a textarea box 218 /** 219 * @todo function documentation 220 * @param string 221 * @return string 222 */ 223 function string_textarea( $p_string ) { 224 return string_html_specialchars( $p_string ); 225 } 226 227 /** 228 * Process a string for display in a text box 229 * @param string 230 * @return string 231 */ 232 function string_attribute( $p_string ) { 233 return string_html_specialchars( $p_string ); 234 } 235 236 /** 237 * Process a string for inclusion in a URL as a GET parameter 238 * @param string $p_string 239 * @return string 240 */ 241 function string_url( $p_string ) { 242 return rawurlencode( $p_string ); 243 } 244 245 /** 246 * validate the url as part of this site before continuing 247 * @param string $p_url 248 * @param bool $p_return_absolute 249 * @return string 250 */ 251 function string_sanitize_url( $p_url, $p_return_absolute = false ) { 252 $t_url = strip_tags( urldecode( $p_url ) ); 253 254 $t_path = rtrim( config_get( 'path' ), '/' ); 255 $t_short_path = rtrim( config_get( 'short_path' ), '/' ); 256 257 $t_pattern = '(?:/*(?P<script>[^\?#]*))(?:\?(?P<query>[^#]*))?(?:#(?P<anchor>[^#]*))?'; 258 259 # Break the given URL into pieces for path, script, query, and anchor 260 $t_type = 0; 261 if ( preg_match( '@^(?P<path>' . preg_quote( $t_path, '@' ) . ')' . $t_pattern . '$@', $t_url, $t_matches ) ) { 262 $t_type = 1; 263 } else if ( preg_match( '@^(?P<path>' . preg_quote( $t_short_path, '@' ) . ')' . $t_pattern . '$@', $t_url, $t_matches ) ) { 264 $t_type = 2; 265 } else if ( preg_match( '@^(?P<path>)' . $t_pattern . '$@', $t_url, $t_matches ) ) { 266 $t_type = 3; 267 } 268 269 # Check for URL's pointing to other domains 270 if ( 0 == $t_type || empty( $t_matches['script'] ) || 271 3 == $t_type && preg_match( '@(?:[^:]*)?://@', $t_url ) > 0 ) { 272 273 return ( $p_return_absolute ? $t_path . '/' : '' ) . 'index.php'; 274 } 275 276 # Start extracting regex matches 277 $t_script = $t_matches['script']; 278 $t_script_path = $t_matches['path']; 279 280 # Clean/encode query params 281 $t_query = ''; 282 if ( isset( $t_matches['query'] ) ) { 283 $t_pairs = array(); 284 parse_str( html_entity_decode( $t_matches['query'] ), $t_pairs ); 285 286 $t_clean_pairs = array(); 287 foreach( $t_pairs as $t_key => $t_value ) { 288 if ( is_array( $t_value ) ) { 289 foreach( $t_value as $t_value_each ) { 290 $t_clean_pairs[] .= rawurlencode( $t_key ) . '[]=' . rawurlencode( $t_value_each ); 291 } 292 } else { 293 $t_clean_pairs[] = rawurlencode( $t_key ) . '=' . rawurlencode( $t_value ); 294 } 295 } 296 297 if ( !empty( $t_clean_pairs ) ) { 298 $t_query = '?' . join( '&', $t_clean_pairs ); 299 } 300 } 301 302 # encode link anchor 303 $t_anchor = ''; 304 if ( isset( $t_matches['anchor'] ) ) { 305 $t_anchor = '#' . rawurlencode( $t_matches['anchor'] ); 306 } 307 308 # Return an appropriate re-combined URL string 309 if ( $p_return_absolute ) { 310 return $t_path . '/' . $t_script . $t_query . $t_anchor; 311 } else { 312 return ( !empty( $t_script_path ) ? $t_script_path . '/' : '' ) . $t_script . $t_query . $t_anchor; 313 } 314 } 315 316 $string_process_bug_link_callback = array(); 317 318 /** 319 * Process $p_string, looking for bug ID references and creating bug view 320 * links for them. 321 * 322 * Returns the processed string. 323 * 324 * If $p_include_anchor is true, include the href tag, otherwise just insert 325 * the URL 326 * 327 * The bug tag ('#' by default) must be at the beginning of the string or 328 * preceeded by a character that is not a letter, a number or an underscore 329 * 330 * if $p_include_anchor = false, $p_fqdn is ignored and assumed to true. 331 * @param string $p_string 332 * @param bool $p_include_anchor 333 * @param bool $p_detail_info 334 * @param bool $p_fqdn 335 * @return string 336 */ 337 function string_process_bug_link( $p_string, $p_include_anchor = true, $p_detail_info = true, $p_fqdn = false ) { 338 global $string_process_bug_link_callback; 339 340 $t_tag = config_get( 'bug_link_tag' ); 341 342 # bail if the link tag is blank 343 if( '' == $t_tag || $p_string == '' ) { 344 return $p_string; 345 } 346 347 if( !isset( $string_process_bug_link_callback[$p_include_anchor][$p_detail_info][$p_fqdn] ) ) { 348 if( $p_include_anchor ) { 349 $string_process_bug_link_callback[$p_include_anchor][$p_detail_info][$p_fqdn] = create_function( '$p_array', ' 350 if ( bug_exists( (int)$p_array[2] ) && access_has_bug_level( VIEWER, (int)$p_array[2] ) ) { 351 return $p_array[1] . string_get_bug_view_link( (int)$p_array[2], null, ' . ( $p_detail_info ? 'true' : 'false' ) . ', ' . ( $p_fqdn ? 'true' : 'false' ) . '); 352 } else { 353 return $p_array[0]; 354 } 355 ' ); 356 } else { 357 $string_process_bug_link_callback[$p_include_anchor][$p_detail_info][$p_fqdn] = create_function( '$p_array', ' 358 # We might as well create the link here even if the bug 359 # doesnt exist. In the case above we dont want to do 360 # the summary lookup on a non-existant bug. But here, we 361 # can create the link and by the time it is clicked on, the 362 # bug may exist. 363 return $p_array[1] . string_get_bug_view_url_with_fqdn( (int)$p_array[2], null ); 364 ' ); 365 } 366 } 367 368 $p_string = preg_replace_callback( '/(^|[^\w&])' . preg_quote( $t_tag, '/' ) . '(\d+)\b/', $string_process_bug_link_callback[$p_include_anchor][$p_detail_info][$p_fqdn], $p_string ); 369 return $p_string; 370 } 371 372 $string_process_bugnote_link_callback = array(); 373 374 /** 375 * Process $p_string, looking for bugnote ID references and creating bug view 376 * links for them. 377 * 378 * Returns the processed string. 379 * 380 * If $p_include_anchor is true, include the href tag, otherwise just insert 381 * the URL 382 * 383 * The bugnote tag ('~' by default) must be at the beginning of the string or 384 * preceeded by a character that is not a letter, a number or an underscore 385 * 386 * if $p_include_anchor = false, $p_fqdn is ignored and assumed to true. 387 * @param string $p_string 388 * @param bool $p_include_anchor 389 * @param bool $p_detail_info 390 * @param bool $p_fqdn 391 * @return string 392 */ 393 function string_process_bugnote_link( $p_string, $p_include_anchor = true, $p_detail_info = true, $p_fqdn = false ) { 394 global $string_process_bugnote_link_callback; 395 $t_tag = config_get( 'bugnote_link_tag' ); 396 397 # bail if the link tag is blank 398 if( '' == $t_tag || $p_string == '' ) { 399 return $p_string; 400 } 401 402 if( !isset( $string_process_bugnote_link_callback[$p_include_anchor][$p_detail_info][$p_fqdn] ) ) { 403 if( $p_include_anchor ) { 404 $string_process_bugnote_link_callback[$p_include_anchor][$p_detail_info][$p_fqdn] = create_function( '$p_array', ' 405 if ( bugnote_exists( (int)$p_array[2] ) ) { 406 $t_bug_id = bugnote_get_field( (int)$p_array[2], \'bug_id\' ); 407 $g_project_override = bug_get_field( $t_bug_id, \'project_id\' ); 408 if ( bug_exists( $t_bug_id ) && ( access_compare_level( user_get_access_level( auth_get_current_user_id(), bug_get_field( $t_bug_id, \'project_id\' ) ), config_get( \'private_bugnote_threshold\' ) ) || ( bugnote_get_field( (int)$p_array[2], \'reporter_id\' ) == auth_get_current_user_id() ) || bugnote_get_field( (int)$p_array[2], \'view_state\' ) == VS_PUBLIC ) ) { 409 $g_project_override = null; 410 return $p_array[1] . string_get_bugnote_view_link( $t_bug_id, (int)$p_array[2], null, ' . ( $p_detail_info ? 'true' : 'false' ) . ', ' . ( $p_fqdn ? 'true' : 'false' ) . ' ); 411 } else { 412 $g_project_override = null; 413 return $p_array[0]; 414 } 415 } else { 416 return $p_array[0]; 417 } 418 ' ); 419 } else { 420 $string_process_bugnote_link_callback[$p_include_anchor][$p_detail_info][$p_fqdn] = create_function( '$p_array', ' 421 # We might as well create the link here even if the bug 422 # doesnt exist. In the case above we dont want to do 423 # the summary lookup on a non-existant bug. But here, we 424 # can create the link and by the time it is clicked on, the 425 # bug may exist. 426 $t_bug_id = bugnote_get_field( (int)$p_array[2], \'bug_id\' ); 427 if ( bug_exists( $t_bug_id ) ) { 428 return $p_array[1] . string_get_bugnote_view_url_with_fqdn( $t_bug_id, (int)$p_array[2], null ); 429 } else { 430 return $p_array[0]; 431 } 432 ' ); 433 } 434 } 435 $p_string = preg_replace_callback( '/(^|[^\w])' . preg_quote( $t_tag, '/' ) . '(\d+)\b/', $string_process_bugnote_link_callback[$p_include_anchor][$p_detail_info][$p_fqdn], $p_string ); 436 return $p_string; 437 } 438 439 /** 440 * Detect URLs and email addresses in the string and replace them with href anchors 441 * @param string $p_string 442 * @return string 443 */ 444 function string_insert_hrefs( $p_string ) { 445 static $s_url_regex = null; 446 447 if( !config_get( 'html_make_links' ) ) { 448 return $p_string; 449 } 450 451 $t_change_quotes = false; 452 if( ini_get_bool( 'magic_quotes_sybase' ) && function_exists( 'ini_set' ) ) { 453 $t_change_quotes = true; 454 ini_set( 'magic_quotes_sybase', false ); 455 } 456 457 # Find any URL in a string and replace it by a clickable link 458 if ( is_null( $s_url_regex ) ) { 459 # %2A notation in url's 460 $t_url_hex = '%[[:digit:]A-Fa-f]{2}'; 461 462 # valid set of characters that may occur in url scheme. Note: - should be first (A-F != -AF). 463 $t_url_valid_chars = '-_.,!~*\';\/?%^\\\\:@&={\|}+$#[:alnum:]\pL'; 464 465 $t_url_chars = "(?:$t_url_hex}|[$t_url_valid_chars}\(\)\[\]])"; 466 $t_url_chars2 = "(?:$t_url_hex}|[$t_url_valid_chars}])"; 467 $t_url_chars_in_brackets = "(?:$t_url_hex}|[$t_url_valid_chars}\(\)])"; 468 $t_url_chars_in_parens = "(?:$t_url_hex}|[$t_url_valid_chars}\[\]])"; 469 470 $t_url_part1 = "$t_url_chars}"; 471 $t_url_part2 = "(?:\($t_url_chars_in_parens}*\)|\[$t_url_chars_in_brackets}*\]|$t_url_chars2})"; 472 473 $s_url_regex = "/(([[:alpha:]][-+.[:alnum:]]*):\/\/($t_url_part1}*?$t_url_part2}+))/sue"; 474 } 475 476 $p_string = preg_replace( $s_url_regex, "'<a href=\"'.rtrim('\\1','.').'\">\\1</a>'", $p_string ); 477 if( $t_change_quotes ) { 478 ini_set( 'magic_quotes_sybase', true ); 479 } 480 481 $p_string = preg_replace( email_regex_simple(), '<a href="mailto:\0">\0</a>', $p_string ); 482 483 return $p_string; 484 } 485 486 /** 487 * Detect href anchors in the string and replace them with URLs and email addresses 488 * @param string $p_string 489 * @return string 490 */ 491 function string_strip_hrefs( $p_string ) { 492 # First grab mailto: hrefs. We don't care whether the URL is actually 493 # correct - just that it's inside an href attribute. 494 $p_string = preg_replace( '/<a\s[^\>]*href="mailto:([^\"]+)"[^\>]*>[^\<]*<\/a>/si', '\1', $p_string ); 495 496 # Then grab any other href 497 $p_string = preg_replace( '/<a\s[^\>]*href="([^\"]+)"[^\>]*>[^\<]*<\/a>/si', '\1', $p_string ); 498 return $p_string; 499 } 500 501 /** 502 * This function looks for text with htmlentities 503 * like <b> and converts is into corresponding 504 * html < b > tag based on the configuration presets 505 * @param string $p_string 506 * @param bool $p_multiline 507 * @return string 508 */ 509 function string_restore_valid_html_tags( $p_string, $p_multiline = true ) { 510 global $g_cache_html_valid_tags_single_line, $g_cache_html_valid_tags; 511 $tags = ''; 512 if( is_blank(( $p_multiline ? $g_cache_html_valid_tags : $g_cache_html_valid_tags_single_line ) ) ) { 513 $t_html_valid_tags = config_get( $p_multiline ? 'html_valid_tags' : 'html_valid_tags_single_line' ); 514 515 if( OFF === $t_html_valid_tags || is_blank( $t_html_valid_tags ) ) { 516 return $p_string; 517 } 518 519 $tags = explode( ',', $t_html_valid_tags ); 520 foreach( $tags as $key => $value ) { 521 if( !is_blank( $value ) ) { 522 $tags[$key] = trim( $value ); 523 } 524 } 525 $tags = implode( '|', $tags ); 526 if( $p_multiline ) { 527 $g_cache_html_valid_tags = $tags; 528 } else { 529 $g_cache_html_valid_tags_single_line = $tags; 530 } 531 } else { 532 $tags = ( $p_multiline ? $g_cache_html_valid_tags : $g_cache_html_valid_tags_single_line ); 533 } 534 535 $p_string = preg_replace( '/<(' . $tags . ')\s*>/ui', '<\\1>', $p_string ); 536 $p_string = preg_replace( '/<\/(' . $tags . ')\s*>/ui', '</\\1>', $p_string ); 537 $p_string = preg_replace( '/<(' . $tags . ')\s*\/>/ui', '<\\1 />', $p_string ); 538 539 return $p_string; 540 } 541 542 /** 543 * return the name of a bug page for the user 544 * account for the user preference and site override 545 * $p_action should be something like 'view', 'update', or 'report' 546 * If $p_user_id is null or not specified, use the current user * @param string $p_action 547 * @param string $p_action 548 * @param int $p_user_id 549 * @return string 550 */ 551 function string_get_bug_page( $p_action, $p_user_id = null ) { 552 if ( $p_action == 'view' ) { 553 return 'bug_view_page.php'; 554 } 555 556 if ( $p_action == 'update' ) { 557 return 'bug_update_page.php'; 558 } 559 560 if ( $p_action == 'report' ) { 561 return 'bug_report_page.php'; 562 } 563 564 trigger_error( ERROR_GENERIC, ERROR ); 565 } 566 567 /** 568 * return an href anchor that links to a bug VIEW page for the given bug 569 * account for the user preference and site override 570 * @param int $p_bug_id 571 * @param int $p_user_id 572 * @param bool $p_detail_info 573 * @param bool $p_fqdn 574 * @return string 575 */ 576 function string_get_bug_view_link( $p_bug_id, $p_user_id = null, $p_detail_info = true, $p_fqdn = false ) { 577 if( bug_exists( $p_bug_id ) ) { 578 $t_link = '<a href="'; 579 if( $p_fqdn ) { 580 $t_link .= config_get_global( 'path' ); 581 } else { 582 $t_link .= config_get_global( 'short_path' ); 583 } 584 $t_link .= string_get_bug_view_url( $p_bug_id, $p_user_id ) . '"'; 585 if( $p_detail_info ) { 586 $t_summary = string_attribute( bug_get_field( $p_bug_id, 'summary' ) ); 587 $t_project_id = bug_get_field( $p_bug_id, 'project_id' ); 588 $t_status = string_attribute( get_enum_element( 'status', bug_get_field( $p_bug_id, 'status' ), $t_project_id ) ); 589 $t_link .= ' title="[' . $t_status . '] ' . $t_summary . '"'; 590 591 $t_resolved = bug_get_field( $p_bug_id, 'status' ) >= config_get( 'bug_resolved_status_threshold', null, null, $t_project_id ); 592 if( $t_resolved ) { 593 $t_link .= ' class="resolved"'; 594 } 595 } 596 $t_link .= '>' . bug_format_id( $p_bug_id ) . '</a>'; 597 } else { 598 $t_link = bug_format_id( $p_bug_id ); 599 } 600 601 return $t_link; 602 } 603 604 /** 605 * return an href anchor that links to a bug VIEW page for the given bug 606 * account for the user preference and site override 607 * @param int $p_bug_id 608 * @param int $p_bugnote_id 609 * @param int $p_user_id 610 * @param bool $p_detail_info 611 * @param bool $p_fqdn 612 * @return string 613 */ 614 function string_get_bugnote_view_link( $p_bug_id, $p_bugnote_id, $p_user_id = null, $p_detail_info = true, $p_fqdn = false ) { 615 $t_bug_id = (int)$p_bug_id; 616 617 if( bug_exists( $t_bug_id ) && bugnote_exists( $p_bugnote_id ) ) { 618 $t_link = '<a href="'; 619 if( $p_fqdn ) { 620 $t_link .= config_get_global( 'path' ); 621 } else { 622 $t_link .= config_get_global( 'short_path' ); 623 } 624 625 $t_link .= string_get_bugnote_view_url( $p_bug_id, $p_bugnote_id, $p_user_id ) . '"'; 626 if( $p_detail_info ) { 627 $t_reporter = string_attribute( user_get_name( bugnote_get_field( $p_bugnote_id, 'reporter_id' ) ) ); 628 $t_update_date = string_attribute( date( config_get( 'normal_date_format' ), ( bugnote_get_field( $p_bugnote_id, 'last_modified' ) ) ) ); 629 $t_link .= ' title="' . bug_format_id( $t_bug_id ) . ': [' . $t_update_date . '] ' . $t_reporter . '"'; 630 } 631 632 $t_link .= '>' . bug_format_id( $t_bug_id ) . ':' . bugnote_format_id( $p_bugnote_id ) . '</a>'; 633 } else { 634 $t_link = bugnote_format_id( $t_bug_id ) . ':' . bugnote_format_id( $p_bugnote_id ); 635 } 636 637 return $t_link; 638 } 639 640 /** 641 * return the name and GET parameters of a bug VIEW page for the given bug 642 * @param int $p_bug_id 643 * @return string 644 */ 645 function string_get_bug_view_url( $p_bug_id ) { 646 return 'view.php?id=' . $p_bug_id; 647 } 648 649 /** 650 * return the name and GET parameters of a bug VIEW page for the given bug 651 * @param int $p_bug_id 652 * @param int $p_bugnote_id 653 * @return string 654 */ 655 function string_get_bugnote_view_url( $p_bug_id, $p_bugnote_id ) { 656 return 'view.php?id=' . $p_bug_id . '#c' . $p_bugnote_id; 657 } 658 659 /** 660 * return the name and GET parameters of a bug VIEW page for the given bug 661 * account for the user preference and site override 662 * The returned url includes the fully qualified domain, hence it is suitable to be included 663 * in emails. 664 * @param int $p_bug_id 665 * @param int $p_bugnote_id 666 * @param int $p_user_id 667 * @return string 668 */ 669 function string_get_bugnote_view_url_with_fqdn( $p_bug_id, $p_bugnote_id, $p_user_id = null ) { 670 return config_get( 'path' ) . string_get_bug_view_url( $p_bug_id, $p_user_id ) . '#c' . $p_bugnote_id; 671 } 672 673 /** 674 * return the name and GET parameters of a bug VIEW page for the given bug 675 * account for the user preference and site override 676 * The returned url includes the fully qualified domain, hence it is suitable to be included in emails. 677 * @param int $p_bug_id 678 * @param int $p_user_id 679 * @return string 680 */ 681 function string_get_bug_view_url_with_fqdn( $p_bug_id, $p_user_id = null ) { 682 return config_get( 'path' ) . string_get_bug_view_url( $p_bug_id, $p_user_id ); 683 } 684 685 /** 686 * return the name of a bug VIEW page for the user 687 * account for the user preference and site override 688 * @param int $p_user_id 689 * @return string 690 */ 691 function string_get_bug_view_page( $p_user_id = null ) { 692 return string_get_bug_page( 'view', $p_user_id ); 693 } 694 695 /** 696 * return an href anchor that links to a bug UPDATE page for the given bug 697 * account for the user preference and site override 698 * @param int $p_bug_id 699 * @param int $p_user_id 700 * @return string 701 */ 702 function string_get_bug_update_link( $p_bug_id, $p_user_id = null ) { 703 $t_summary = string_attribute( bug_get_field( $p_bug_id, 'summary' ) ); 704 return '<a href="' . helper_mantis_url( string_get_bug_update_url( $p_bug_id, $p_user_id ) ) . '" title="' . $t_summary . '">' . bug_format_id( $p_bug_id ) . '</a>'; 705 } 706 707 /** 708 * return the name and GET parameters of a bug UPDATE page for the given bug 709 * account for the user preference and site override 710 * @param int $p_bug_id 711 * @param int $p_user_id 712 * @return string 713 */ 714 function string_get_bug_update_url( $p_bug_id, $p_user_id = null ) { 715 return string_get_bug_update_page( $p_user_id ) . '?bug_id=' . $p_bug_id; 716 } 717 718 /** 719 * return the name of a bug UPDATE page for the user 720 * account for the user preference and site override 721 * @param int $p_user_id 722 * @return string 723 */ 724 function string_get_bug_update_page( $p_user_id = null ) { 725 return string_get_bug_page( 'update', $p_user_id ); 726 } 727 728 /** 729 * return an href anchor that links to a bug REPORT page for the given bug 730 * account for the user preference and site override 731 * @param int $p_user_id 732 * @return string 733 */ 734 function string_get_bug_report_link( $p_user_id = null ) { 735 return '<a href="' . helper_mantis_url( string_get_bug_report_url( $p_user_id ) ) . '">' . lang_get( 'report_bug_link' ) . '</a>'; 736 } 737 738 /** 739 * return the name and GET parameters of a bug REPORT page for the given bug 740 * account for the user preference and site override 741 * @param int $p_user_id 742 * @return string 743 */ 744 function string_get_bug_report_url( $p_user_id = null ) { 745 return string_get_bug_report_page( $p_user_id ); 746 } 747 748 /** 749 * return the name of a bug REPORT page for the user 750 * account for the user preference and site override 751 * @param int $p_user_id 752 * @return string 753 */ 754 function string_get_bug_report_page( $p_user_id = null ) { 755 return string_get_bug_page( 'report', $p_user_id ); 756 } 757 758 /** 759 * return the complete url link to checkin using the confirm_hash 760 * @param int $p_user_id 761 * @param string $p_confirm_hash 762 * @return string 763 */ 764 function string_get_confirm_hash_url( $p_user_id, $p_confirm_hash ) { 765 $t_path = config_get( 'path' ); 766 return $t_path . "verify.php?id=" . string_url( $p_user_id ) . "&confirm_hash=" . string_url( $p_confirm_hash ); 767 } 768 769 /** 770 * Format date for display 771 * @param int $p_date 772 * @return string 773 */ 774 function string_format_complete_date( $p_date ) { 775 return date( config_get( 'complete_date_format' ), $p_date ); 776 } 777 778 /** 779 * Shorten a string for display on a dropdown to prevent the page rendering too wide 780 * ref issues #4630, #5072, #5131 781 * @param string $p_string 782 * @param int $p_max 783 * @return string 784 */ 785 function string_shorten( $p_string, $p_max = null ) { 786 if( $p_max === null ) { 787 $t_max = config_get( 'max_dropdown_length' ); 788 } else { 789 $t_max = (int) $p_max; 790 } 791 792 if( ( $t_max > 0 ) && ( utf8_strlen( $p_string ) > $t_max ) ) { 793 $t_pattern = '/([\s|.|,|\-|_|\/|\?]+)/'; 794 $t_bits = preg_split( $t_pattern, $p_string, -1, PREG_SPLIT_DELIM_CAPTURE ); 795 796 $t_string = ''; 797 $t_last = $t_bits[count( $t_bits ) - 1]; 798 $t_last_len = strlen( $t_last ); 799 800 if( count( $t_bits ) == 1 ) { 801 $t_string .= utf8_substr( $t_last, 0, $t_max - 3 ); 802 $t_string .= '...'; 803 } else { 804 foreach( $t_bits as $t_bit ) { 805 if(( utf8_strlen( $t_string ) + utf8_strlen( $t_bit ) + $t_last_len + 3 <= $t_max ) || ( strpos( $t_bit, '.,-/?' ) > 0 ) ) { 806 $t_string .= $t_bit; 807 } else { 808 break; 809 } 810 } 811 $t_string .= '...' . $t_last; 812 } 813 return $t_string; 814 } else { 815 return $p_string; 816 } 817 } 818 819 /** 820 * Normalize a string by removing leading, trailing and excessive internal spaces 821 * note a space is used as the pattern instead of '\s' to make it work with UTF-8 strings 822 * @param string $p_string 823 * @return string 824 */ 825 function string_normalize( $p_string ) { 826 return preg_replace( '/ +/', ' ', trim( $p_string ) ); 827 } 828 829 /** 830 * remap a field name to a string name (for sort filter) 831 * @param string $p_string 832 * @return string 833 */ 834 function string_get_field_name( $p_string ) { 835 $t_map = array( 836 'attachment_count' => 'attachments', 837 'category_id' => 'category', 838 'handler_id' => 'assigned_to', 839 'id' => 'email_bug', 840 'last_updated' => 'updated', 841 'project_id' => 'email_project', 842 'reporter_id' => 'reporter', 843 'view_state' => 'view_status', 844 ); 845 846 $t_string = $p_string; 847 if( isset( $t_map[$p_string] ) ) { 848 $t_string = $t_map[$p_string]; 849 } 850 return lang_get_defaulted( $t_string ); 851 } 852 853 /** 854 * Calls htmlentities on the specified string, passing along 855 * the current charset. 856 * @param string $p_string 857 * @return string 858 */ 859 function string_html_entities( $p_string ) { 860 return htmlentities( $p_string, ENT_COMPAT, 'utf-8' ); 861 } 862 863 /** 864 * Calls htmlspecialchars on the specified string, handling utf8 865 * @param string $p_string 866 * @return string 867 */ 868 function string_html_specialchars( $p_string ) { 869 # achumakov: @ added to avoid warning output in unsupported codepages 870 # e.g. 8859-2, windows-1257, Korean, which are treated as 8859-1. 871 # This is VERY important for Eastern European, Baltic and Korean languages 872 return preg_replace( "/&(#[0-9]+|[a-z]+);/i", "&$1;", @htmlspecialchars( $p_string, ENT_COMPAT, 'utf-8' ) ); 873 } 874 875 /** 876 * Prepares a string to be used as part of header(). 877 * @param string $p_string 878 * @return string 879 */ 880 function string_prepare_header( $p_string ) { 881 $t_string= explode( "\n", $p_string, 2 ); 882 $t_string= explode( "\r", $t_string[0], 2 ); 883 return $t_string[0]; 884 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Jul 28 15:48:31 2011 | Cross-referenced by PHPXref 0.7 |