PageRenderTime 126ms CodeModel.GetById 55ms app.highlight 28ms RepoModel.GetById 38ms app.codeStats 0ms

/lib/functions/string_api.php

https://bitbucket.org/pfernandez/testlink1.9.6
PHP | 492 lines | 257 code | 87 blank | 148 comment | 41 complexity | bc734c9d205eed7fe77d3c15fd22b8b4 MD5 | raw file
  1<?php
  2/** 
  3 * TestLink Open Source Project - http://testlink.sourceforge.net/ 
  4 * This script is distributed under the GNU General Public License 2 or later.
  5 *  
  6 * String Processing functions
  7 * 
  8 * @package 	TestLink
  9 * @copyright 	2007-2009, TestLink community
 10 * @copyright 	Copyright (C) 2002 - 2004  Mantis Team
 11 * 				The base for certain code was adapted from Mantis - a php based bugtracking system
 12 * @version    	CVS: $Id: string_api.php,v 1.12 2009/09/04 19:22:37 schlundus Exp $
 13 * @link 		http://www.teamst.org/index.php
 14 * 
 15 * @internal rev: 
 16 *  20080822 - franciscom - restored missed string_email_links() 
 17 * 	20080606 - havlatm - remove useles mantis related code
 18 * 	20071104 - franciscom - changes to string_email_links()
 19 *     
 20 **/
 21
 22
 23/** 
 24 * Preserve spaces at beginning of lines. 
 25 * Lines must be separated by \n rather than < br / > 
 26 **/
 27function string_preserve_spaces_at_bol( $p_string ) 
 28{
 29	$lines = explode( "\n", $p_string );
 30	$line_count = count( $lines );
 31	for ( $i = 0; $i < $line_count; $i++ ) {
 32		$count	= 0;
 33		$prefix	= '';
 34		
 35		$t_char = substr( $lines[$i], $count, 1 );
 36		$spaces = 0;
 37		while ( ( $t_char  == ' ' ) || ( $t_char == "\t" ) ) {
 38			if ( $t_char == ' ' )
 39				$spaces++;
 40			else
 41				$spaces += 4; // 1 tab = 4 spaces, can be configurable.
 42			
 43			$count++;
 44			$t_char = substr( $lines[$i], $count, 1 );
 45		}
 46		
 47		for ( $j = 0; $j < $spaces; $j++ ) {
 48			$prefix .= '&nbsp;';
 49		}
 50		
 51		$lines[$i] = $prefix . substr( $lines[$i], $count );
 52	}
 53	return implode( "\n", $lines );
 54}
 55
 56
 57/** 
 58 * Prepare a string to be printed without being broken into multiple lines 
 59 **/
 60function string_no_break( $p_string ) {
 61	if ( strpos( $p_string, ' ' ) !== false ) {
 62		return '<span class="nowrap">' . $p_string . "</span>";
 63	} else {
 64		return $p_string;
 65	}
 66}
 67
 68/** 
 69 * Similar to nl2br, but fixes up a problem where new lines are doubled between < pre > tags.
 70 * additionally, wrap the text an $p_wrap character intervals if the config is set
 71 * 
 72 * @author Mantis BT team
 73 */
 74function string_nl2br( $p_string, $p_wrap = 100 ) 
 75{
 76		$p_string = nl2br( $p_string );
 77
 78		// fix up eols within <pre> tags
 79		$pre2 = array();
 80		preg_match_all("/<pre[^>]*?>(.|\n)*?<\/pre>/", $p_string, $pre1);
 81		for ( $x = 0; $x < count($pre1[0]); $x++ ) 
 82		{
 83			$pre2[$x] = preg_replace("/<br[^>]*?>/", "", $pre1[0][$x]);
 84			// this may want to be replaced by html_entity_decode (or equivalent)
 85			//     if other encoded characters are a problem
 86			$pre2[$x] = preg_replace("/&nbsp;/", " ", $pre2[$x]);
 87			if ( ON == config_get( 'wrap_in_preformatted_text' ) ) 
 88			{
 89				$pre2[$x] = preg_replace("/([^\n]{".$p_wrap."})(?!<\/pre>)/", "$1\n", $pre2[$x]);
 90			}
 91			$pre1[0][$x] = "/" . preg_quote($pre1[0][$x], "/") . "/";
 92		}
 93
 94		return preg_replace( $pre1[0], $pre2, $p_string );
 95}
 96
 97
 98/** 
 99 * Prepare a multiple line string for display to HTML 
100 **/
101function string_display( $p_string ) 
102{	
103	$p_string = string_strip_hrefs( $p_string );
104	$p_string = string_html_specialchars( $p_string );
105	$p_string = string_restore_valid_html_tags( $p_string, /* multiline = */ true );
106	$p_string = string_preserve_spaces_at_bol( $p_string );
107	$p_string = string_nl2br( $p_string );
108
109	return $p_string;
110}
111
112
113/** Prepare a single line string for display to HTML */
114function string_display_line( $p_string ) 
115{
116	$p_string = string_strip_hrefs( $p_string );
117	$p_string = string_html_specialchars( $p_string );
118	$p_string = string_restore_valid_html_tags( $p_string, /* multiline = */ false );
119	
120	return $p_string;
121}
122
123
124/** 
125 * Prepare a string for display to HTML and add href anchors for URLs, emails,
126 * bug references, and cvs references
127 */
128function string_display_links( $p_string ) 
129{
130	$p_string = string_display( $p_string );
131	$p_string = string_insert_hrefs( $p_string );
132	return $p_string;
133}
134
135
136/** 
137 * Prepare a single line string for display to HTML and add href anchors for
138 * URLs, emails, bug references, and cvs references
139 */ 
140function string_display_line_links( $p_string ) 
141{
142	$p_string = string_display_line( $p_string );
143	$p_string = string_insert_hrefs( $p_string );
144
145	return $p_string;
146}
147
148
149/** Prepare a string for display in rss */
150function string_rss_links( $p_string ) 
151{
152	// rss can not start with &nbsp; which spaces will be replaced into by string_display().
153	$t_string = trim( $p_string );
154
155	// same steps as string_display_links() without the preservation of spaces since &nbsp; is undefined in XML.
156	$t_string = string_strip_hrefs( $t_string );
157	$t_string = string_html_specialchars( $t_string );
158	$t_string = string_restore_valid_html_tags( $t_string );
159	$t_string = string_nl2br( $t_string );
160	$t_string = string_insert_hrefs( $t_string );
161	$t_string = string_process_bug_link( $t_string, /* anchor */ true, /* detailInfo */ false, /* fqdn */ true );
162	$t_string = string_process_bugnote_link( $t_string, /* anchor */ true, /* detailInfo */ false, /* fqdn */ true );
163	$t_string = string_process_cvs_link( $t_string );
164	# another escaping to escape the special characters created by the generated links
165	$t_string = string_html_specialchars( $t_string );
166
167	return $t_string;
168}
169
170   
171/** 
172 * Prepare a string for plain text display in email 
173 **/
174function string_email( $p_string ) 
175{
176	$p_string = string_strip_hrefs( $p_string );
177	return $p_string;
178}
179 
180  
181/**  
182 * Prepare a string for plain text display in email and add URLs for bug
183 * links and cvs links
184 */     
185function string_email_links( $p_string ) {
186	$p_string = string_email( $p_string );
187  return $p_string;
188}
189
190
191/** 
192 * Process a string for display in a textarea box 
193 **/
194function string_textarea( $p_string ) 
195{
196	$p_string = string_html_specialchars( $p_string );
197	return $p_string;
198}
199
200
201/** 
202 * Process a string for display in a text box
203 */
204function string_attribute( $p_string ) 
205{
206	$p_string = string_html_specialchars( $p_string );
207
208	return $p_string;
209}
210
211
212/** 
213 * Process a string for inclusion in a URL as a GET parameter 
214 */
215function string_url( $p_string ) 
216{
217	$p_string = rawurlencode( $p_string );
218
219	return $p_string;
220}
221
222
223/** 
224 * validate the url as part of this site before continuing 
225 **/
226function string_sanitize_url( $p_url ) {
227
228	$t_url = strip_tags( urldecode( $p_url ) );
229	if ( preg_match( '?http(s)*://?', $t_url ) > 0 ) { 
230		// no embedded addresses
231		if ( preg_match( '?^' . config_get( 'path' ) . '?', $t_url ) == 0 ) { 
232			// url is ok if it begins with our path, if not, replace it
233			$t_url = 'index.php';
234		}
235	}
236	if ( $t_url == '' ) {
237		$t_url = 'index.php';
238	}
239	
240	// split and encode parameters
241	if ( strpos( $t_url, '?' ) !== FALSE ) {
242		list( $t_path, $t_param ) = split( '\?', $t_url, 2 );
243		if ( $t_param !== "" ) {
244			$t_vals = array();
245			parse_str( $t_param, $t_vals );
246			$t_param = '';
247			foreach($t_vals as $k => $v) {
248				if ($t_param != '') {
249					$t_param .= '&'; 
250				}
251				$t_param .= "$k=" . urlencode( strip_tags( urldecode( $v ) ) );
252			}
253			return $t_path . '?' . $t_param;
254		} else {
255			return $t_path;
256		}
257	} else {
258		return $t_url;
259	}
260}
261	
262
263// ----- Tag Processing -------------------------------------------------------
264
265/** 
266 * Detect URLs and email addresses in the string and replace them with href anchors 
267 **/
268function string_insert_hrefs( $p_string ) 
269{
270	if ( !config_get('html_make_links') ) {
271		return $p_string;
272	}
273
274	$t_change_quotes = false;
275	if( ini_get_bool( 'magic_quotes_sybase' ) ) {
276		$t_change_quotes = true;
277		ini_set( 'magic_quotes_sybase', false );
278	}
279
280	// Find any URL in a string and replace it by a clickable link
281	$p_string = preg_replace( '/(([[:alpha:]][-+.[:alnum:]]*):\/\/(%[[:digit:]A-Fa-f]{2}|[-_.!~*\';\/?%^\\\\:@&={\|}+$#\(\),\[\][:alnum:]])+)/se',
282                              "'<a href=\"'.rtrim('\\1','.').'\">\\1</a> [<a href=\"'.rtrim('\\1','.').'\" target=\"_blank\">^</a>]'", $p_string);
283                              
284	if( $t_change_quotes ) {
285		ini_set( 'magic_quotes_sybase', true );
286	}
287
288	# Set up a simple subset of RFC 822 email address parsing
289	#  We don't allow domain literals or quoted strings
290	#  We also don't allow the & character in domains even though the RFC
291	#  appears to do so.  This was to prevent &gt; etc from being included.
292	#  Note: we could use email_get_rfc822_regex() but it doesn't work well
293	#  when applied to data that has already had entities inserted.
294	#
295	# bpfennig: '@' doesn't accepted anymore
296	# achumakov: characters 0x80-0xFF aren't acceptable, too
297	$t_atom = '[^\'@\'](?:[^()<>@,;:\\\".\[\]\000-\037\177-\377 &]+)';
298
299	# In order to avoid selecting URLs containing @ characters as email
300	#  addresses we limit our selection to addresses that are preceded by:
301	#  * the beginning of the string
302	#  * a &lt; entity (allowing '<foo@bar.baz>')
303	#  * whitespace
304	#  * a : (allowing 'send email to:foo@bar.baz')
305	#  * a \n, \r, or > (because newlines have been replaced with <br />
306	#    and > isn't valid in URLs anyway
307	#
308	# At the end of the string we allow the opposite:
309	#  * the end of the string
310	#  * a &gt; entity
311	#  * whitespace
312	#  * a , character (allowing 'email foo@bar.baz, or ...')
313	#  * a \n, \r, or <
314
315	$p_string = preg_replace( '/(?<=^|&quot;|&lt;|[\s\:\>\n\r])('.$t_atom.'(?:\.'.$t_atom.')*\@'.$t_atom.'(?:\.'.$t_atom.')*)(?=$|&quot;|&gt;|[\s\,\<\n\r])/s',
316							'<a href="mailto:\1">\1</a>', $p_string);
317
318	return $p_string;
319}
320
321
322/** 
323 * Detect href anchors in the string and replace them with URLs and email addresses 
324 **/
325function string_strip_hrefs( $p_string ) 
326{
327	# First grab mailto: hrefs.  We don't care whether the URL is actually
328	# correct - just that it's inside an href attribute.
329	$p_string = preg_replace( '/<a\s[^\>]*href="mailto:([^\"]+)"[^\>]*>[^\<]*<\/a>/si',
330								'\1', $p_string);
331
332	# Then grab any other href
333	$p_string = preg_replace( '/<a\s[^\>]*href="([^\"]+)"[^\>]*>[^\<]*<\/a>/si',
334								'\1', $p_string);
335	return $p_string;
336}
337
338
339/**
340 * This function looks for text with htmlentities
341 * like &lt;b&gt; and converts is into corresponding
342 * html &lt;b&gt; based on the configuration presets
343 */
344function string_restore_valid_html_tags( $p_string, $p_multiline = true ) 
345{
346	$t_html_valid_tags = config_get( $p_multiline ? 'html_valid_tags' : 'html_valid_tags_single_line' );
347
348	if ( OFF === $t_html_valid_tags || is_blank( $t_html_valid_tags ) ) {
349		return $p_string;
350	}
351
352	$tags = explode( ',', $t_html_valid_tags );
353	foreach ($tags as $key => $value) 
354	{ 
355    	if ( !is_blank( $value ) ) {
356        	$tags[$key] = trim($value); 
357        }
358    }
359    $tags = implode( '|', $tags);
360
361	$p_string = preg_replace( '/&lt;(' . $tags . ')\s*&gt;/ui', '<\\1>', $p_string );
362	$p_string = preg_replace( '/&lt;\/(' . $tags . ')\s*&gt;/ui', '</\\1>', $p_string );
363	$p_string = preg_replace( '/&lt;(' . $tags . ')\s*\/&gt;/ui', '<\\1 />', $p_string );
364
365
366	return $p_string;
367}
368
369
370/**	
371 * Return a string with the $p_character pattern repeated N times.
372 * 
373 * @param string $p_character - pattern to repeat
374 * @param integer $p_repeats - number of times to repeat.
375 */
376function string_repeat_char( $p_character, $p_repeats ) {
377	return str_pad( '', $p_repeats, $p_character );
378}
379
380
381/**
382 * Format date for display
383 */ 
384function string_format_complete_date( $p_date ) {
385	$t_timestamp = db_unixtimestamp( $p_date );
386	return date( config_get( 'complete_date_format' ), $t_timestamp );
387}
388
389
390/** 
391 * Shorten a string for display on a dropdown to prevent the page rendering too wide
392 */
393function string_shorten( $p_string ) {
394	$t_max = config_get( 'max_dropdown_length' );
395	if ( ( tlStrLen($p_string ) > $t_max ) && ( $t_max > 0 ) ){
396		$t_pattern = '/([\s|.|,|\-|_|\/|\?]+)/';
397		$t_bits = preg_split( $t_pattern, $p_string, -1, PREG_SPLIT_DELIM_CAPTURE );
398
399		$t_string = '';
400		$t_last = $t_bits[ count( $t_bits ) - 1 ];
401		$t_last_len = tlStrLen( $t_last );
402
403		foreach ( $t_bits as $t_bit ) {
404			if ( ( tlStrLen( $t_string ) + tlStrLen( $t_bit ) + $t_last_len + 3 <= $t_max )
405				|| ( strpos( $t_bit, '.,-/?' ) > 0 ) ) {
406				$t_string .= $t_bit;
407			} else {
408				break;
409			}
410		}
411		$t_string .= '...' . $t_last;
412		return $t_string;
413	} else {
414		return $p_string;
415	}
416}
417
418
419/**
420 * remap a field name to a string name (for sort filter)
421 */
422function string_get_field_name( $p_string ) {
423
424	$t_map = array(
425			'last_updated' => 'last_update',
426			'id' => 'email_bug'
427			);
428
429	$t_string = $p_string;
430	if ( isset( $t_map[ $p_string ] ) ) {
431		$t_string = $t_map[ $p_string ];
432	}
433	return lang_get_defaulted( $t_string );
434}
435
436
437/** 
438 * Calls htmlentities on the specified string, passing along
439 * the current charset.
440 */
441function string_html_entities( $p_string ) {
442	return htmlentities( $p_string, ENT_COMPAT, config_get('charset') );
443}
444
445
446/** 
447 * Calls htmlspecialchars on the specified string, passing along
448 * the current charset, if the current PHP version supports it.
449 */
450function string_html_specialchars( $p_string ) {
451	# achumakov: @ added to avoid warning output in unsupported codepages
452	# e.g. 8859-2, windows-1257, Korean, which are treated as 8859-1.
453	# This is VERY important for Eastern European, Baltic and Korean languages
454	return preg_replace("/&amp;(#[0-9]+|[a-z]+);/i", "&$1;", @htmlspecialchars( $p_string, ENT_COMPAT, config_get('charset') ) );
455}
456
457
458/** 
459 * Prepares a string to be used as part of header().
460 */
461function string_prepare_header( $p_string ) {
462	$t_string = $p_string;
463
464	$t_truncate_pos = strpos($p_string, "\n");
465	if ($t_truncate_pos !== false ) {
466		$t_string = substr($t_string, 0, $t_truncate_pos);
467	}
468
469	$t_truncate_pos = strpos($p_string, "\r");
470	if ($t_truncate_pos !== false ) {
471		$t_string = substr($t_string, 0, $t_truncate_pos);
472	}
473
474	return $t_string;
475}
476
477
478/** 
479 * Checks the supplied string for scripting characters, if it contains any, then return true, otherwise return false.
480 * 
481 * @param string $p_string
482 * @return boolean
483 */
484function string_contains_scripting_chars( $p_string ) {
485	if ( ( strstr( $p_string, '<' ) !== false ) || ( strstr( $p_string, '>' ) !== false ) ) {
486		return true;
487	}
488
489	return false;
490}
491
492?>