Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
text.inc
1 <?php
45 function replace_keywords(&$text, &$replacements)
46 {
47  // type verification
48  $is_replacements_array = is_array($replacements);
49  if (is_string($text)) {
50  if (!$is_replacements_array) return '';
51  } else if (is_array($text)) {
52  if (!$is_replacements_array) return Array();
53  } else {
54  return '';
55  }
56 
57  return _replace_keywords_recursive($text, $replacements);
58 
59 }//end replace_keywords()
60 
61 
71 function _replace_keywords_recursive(&$text, &$replacements)
72 {
73  if (is_array($text)) {
74  $r = Array();
75  foreach ($text as $key => $value) {
76  $key = _replace_keywords_recursive($key, $replacements);
77  $r[$key] = _replace_keywords_recursive($value, $replacements);
78  }
79  $text = $r;
80  return $text;
81  }
82  foreach ($replacements as $keyword => $replacement) {
83  if ($keyword == '') continue;
84  $text = str_replace("%$keyword%", $replacement, $text);
85  }
86  return $text;
87 
88 }//end _replace_keywords_recursive()
89 
90 
102 function parse_keyword($keyword, &$modifiers = NULL)
103 {
104  $modifiers = Array();
105  $parts = explode('^', $keyword);
106  $keyword = array_shift($parts);
107 
108  foreach ($parts as &$p) {
109  $args = preg_split('/:{1}/', $p, -1);
110  $modifier = array_shift($args);
111  if (!empty($modifier)) {
112  array_push($modifiers, Array('modifier' => $modifier, 'args' => $args));
113  }
114  }
115 
116  return $keyword;
117 
118 }//end parse_keyword()
119 
120 
141 function apply_keyword_modifiers(&$text, $modifiers, $replace_keywords=Array())
142 {
143  foreach ($modifiers as $m) {
144  $text = apply_keyword_modifier($text, $m, $replace_keywords);
145  }
146 
147 }//end apply_keyword_modifiers()
148 
149 
172 function apply_keyword_modifier($text, $modifier, $replace_keywords=Array())
173 {
174 
175  switch ($modifier['modifier']) {
176 
177  case "replace_keywords":
178 
179  /* This modifier takes another modifier as its arguments.
180  * Will attempt to replace any keywords in this nested modifiers arguments.
181  * Info from $replace_keywords will be used to determine source for keyword replacements.
182  */
183  $nested_modifier = array_get_index($modifier['args'], 0, NULL);
184  $nested_modifier_args = Array();
185 
186  $kw_replacements = array_get_index($replace_keywords, 'replacements', Array());
187  $assetid = array_get_index($replace_keywords, 'assetid', 0);
188  $call_fns = array_get_index($replace_keywords, 'call_fns', Array('getKeywordReplacement'));
189 
190  for ($i = 1; $i < count($modifier['args']); $i++){
191  $value = $modifier['args'][$i];
192  preg_match_all('/\{([a-zA-Z_]{2,}[a-zA-Z_\-0-9\.:]+)\}/', $value, $matches, PREG_PATTERN_ORDER);
193  $keywords = array_unique($matches[1]);
194 
195  $replacements = Array();
196  foreach ($keywords as $keyword){
197  if (isset($kw_replacements[$keyword])){
198  $replacements[$keyword] = $kw_replacements[$keyword];
199  } else if (!empty($assetid)){
200  if (!isset($asset)) $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
201  if ($asset){
202  foreach ($call_fns as $fn){
203  if (method_exists($asset, $fn)){
204  $asset_replacement = $asset->$fn($keyword);
205  if (!is_null($asset_replacement) && $asset_replacement != '%'.$keyword.'%'){
206  $replacements[$keyword] = $asset_replacement;
207  break;
208  }
209  }
210  }
211 
212  }
213  }
214  }
215 
216  foreach ($replacements as $keyword => $replacement) {
217  if ($keyword == '') continue;
218  $value = str_replace("{".$keyword."}", $replacement, $value);
219  }
220  $nested_modifier_args[] = $value;
221  }
222 
223  return apply_keyword_modifier($text, Array('modifier' => $nested_modifier, 'args' => $nested_modifier_args));
224 
225  case "urlencode":
226  return urlencode($text);
227 
228  case "urldecode":
229  return urldecode($text);
230 
231  case "base64encode":
232  return base64_encode($text);
233 
234  case "base64decode":
235  return base64_decode($text);
236 
237  case "lowercase":
238  return strtolower($text);
239 
240  case "uppercase":
241  return strtoupper($text);
242 
243  case "nl2br":
244  return nl2br($text);
245 
246  case "escapequotes":
247  return addslashes($text);
248 
249  case "escapehtml":
250  return htmlspecialchars($text, ENT_QUOTES, SQ_CONF_DEFAULT_CHARACTER_SET);
251 
252  case "striphtml":
253  return strip_tags($text);
254 
255  case "maxchars":
256  // One argument; the max characters as an integer.
257  $max = array_get_index($modifier['args'], 0, -1);
258 
259  if (SQ_CONF_DEFAULT_CHARACTER_SET == 'utf-8' && extension_loaded('mbstring'))
260  return mb_substr($text, 0, $max, SQ_CONF_DEFAULT_CHARACTER_SET);
261  else
262  return substr($text, 0, $max);
263 
264  case "maxwords":
265  // One argument; the max words as an integer.
266  $max = array_get_index($modifier['args'], 0, NULL);
267 
268  if (is_numeric($max)) {
269  $text = str_replace('&nbsp;', ' ', trim($text));
270  $words = preg_split("/[\s,]+/", $text);
271 
272  if ($max >= count($words)) {
273  return $text;
274  } else {
275  $words = array_splice($words, 0, $max);
276  return implode(' ', $words);
277  }
278  } else {
279  return $text;
280  }
281 
282  case "wordcount":
283  return str_word_count($text);
284 
285  case "charcount":
286  return strlen($text);
287 
288  case "capitalize":
289  return ucfirst($text);
290 
291  case "titleize":
292  return ucwords($text);
293 
294  case "trim":
295  return trim($text);
296 
297  case "underscore":
298  return preg_replace('/\s+/', '_', $text);
299 
300  case "xpath":
301  // Args are delimeter, xpath
302  //
303  // Example (ordered list of RSS item titles, using tagif modifier to ol list):
304  //
305  // %asset_contents~xpath:</li><li>://item/title~tagif:li~tagif:ol%
306  //
307  // The path lists all titles in the feed, delimited by </li><li>, and then conditionally wrapped in <li>,
308  // which in turn is conditionally wrapped in <ol>.
309  //
310  if (empty($text)) return $text;
311 
312  $delim = array_get_index($modifier['args'], 0, '');
313  $path = array_get_index($modifier['args'], 1, NULL);
314 
315  // If there are more args, this means there were colons in the path. Fixup.
316  for ($i = 2; $i < count($modifier['args']); $i++) {
317  $path .= ':' . $modifier['args'][$i];
318  }
319 
320  if ($path) {
321  try {
322  $xml = new SimpleXMLElement($text);
323 
324  // if namespaces are used, register them before using them in the xpath query
325  $namespaces = explode('xmlns:', $path);
326  $path = array_shift($namespaces);
327  foreach ($namespaces as $namespace) {
328  $ns = explode('=', $namespace);
329  if (count($ns) == 2) {
330  $xml->registerXPathNamespace($ns[0], trim($ns[1]));
331  }
332  }
333 
334  $res = $xml->xpath($path);
335  if ($res) {
336  return implode($delim, $xml->xpath($path));
337  }
338  } catch (Exception $e) {
339  // Badly formed xml, most likely.
340  trigger_error($e->getMessage());
341  }
342 
343  }
344  return '';
345 
346  case "xpathe":
347  // Arg is a xpath query
348  //
349  // PHP state that XPath version 1.0 is supported,
350  // see: http://au.php.net/manual/en/class.domxpath.php
351  //
352  // This should mean that all the functions documented by W3C are supported,
353  // see: http://www.w3.org/TR/xpath/
354  //
355  // Example:
356  //
357  // %asset_contents~xpathe:sum(//item/value)%
358  //
359  // The path takes the mathematical sum() of item/value tags in the XML.
360  //
361  // Example:
362  //
363  // %asset_contents~xpathe:count(//h1)%
364  //
365  // Counts the number of heading ones in the supplied markup.
366  //
367  if (empty($text)) return $text;
368 
369  // There may have been a colon in the path, which would have split the argument
370  // out across elements - if so, fix it up.
371  $path = implode(':', $modifier['args']);
372 
373  $dom = new DOMDocument();
374  $dom->loadXML($text);
375  $xpath = new DOMXPath($dom);
376 
377  $result = $xpath->evaluate($path);
378 
379  // free up memory
380  unset($xpath);
381  unset($dom);
382 
383  return is_scalar($result) ? $result : '';
384 
385  case "empty":
386  // One argument; text to display if the keyword result is empty.
387  if (empty($text)) {
388  // We only want one arg, which might have : in. So implode.
389  $text = implode(':', $modifier['args']);
390  }
391  return $text;
392 
393  case "notempty":
394  // One argument; text to display if the keyword result is not empty.
395  if (!empty($text)) {
396  // We only want one arg, which might have : in. So implode.
397  $text = implode(':', $modifier['args']);
398  }
399  return $text;
400 
401  case "tag":
402  // One argument; the tag name to wrap around the text.
403  $tag = array_get_index($modifier['args'], 0, NULL);
404  if ($tag) {
405  if (empty($text)) {
406  return "<$tag />";
407  } else {
408  return "<$tag>$text</$tag>";
409  }
410  }
411  return $text;
412 
413  case "tagif":
414  // Same as above, except do nothing if the text is empty.
415  $tag = array_get_index($modifier['args'], 0, NULL);
416  if ($tag) {
417  if (empty($text)) {
418  return "";
419  } else {
420  return "<$tag>$text</$tag>";
421  }
422  }
423  return $text;
424 
425  case "cdata":
426  // Escape CDATA closing markup.
427  $text = str_replace(']]>', ']]]]><![CDATA[>', $text);
428  return "<![CDATA[$text]]>";
429 
430  case "stripdecl":
431  // Strip XML declaration.
432  $text = preg_replace('/^<\?xml\s.*\?>/', '', $text);
433  return $text;
434 
435  case "increment":
436  // Increment
437  return ++$text;
438 
439  case "decrement":
440  // Decrement
441  return --$text;
442 
443  case "negate":
444  // Negate
445  return -$text;
446 
447  case "abs":
448  // Returns the absolute number.
449  return abs($text);
450 
451  case "sign":
452  // Returns the sign of a number, +, -, or 0. Overriden in args 2, 3, and 4.
453  $plus = array_get_index($modifier['args'], 0, '+');
454  $minus = array_get_index($modifier['args'], 1, '-');
455  $zero = array_get_index($modifier['args'], 2, '0');
456 
457  if ($text > 0) {
458  return $plus;
459  } else if ($text < 0) {
460  return $minus;
461  } else {
462  return $zero;
463  }
464 
465  case "ceil":
466  // Rounds up to integer.
467  return ceil($text);
468 
469  case "floor":
470  // Rounds down to integer.
471  return floor($text);
472 
473  case "round":
474  // Round to specified precision (0 by default).
475  $precision = array_get_index($modifier['args'], 0, 0);
476  return round($text, $precision);
477 
478  case "number_format":
479  // Format a number with grouped thousands and round to decimal point (0 by default).
480  $decimals = array_get_index($modifier['args'], 0, 0);
481  return number_format($text, $decimals);
482 
483  // Arithmetic modifiers.
484  case "add":
485  case "subtract":
486  case "modulo":
487  case "divide":
488  case "multiply":
489  case "squareroot":
490  return _run_arithmetic_keyword_modifier($modifier, $text);
491 
492  // Comparison operator modifiers. By default these return '1' if true and '' if false.
493  // Return values can be overriden with the subsequent args, e.g:
494  //
495  // %asset_contents~eq:Hello:MATCH:NOMATCH%
496  case "eq":
497  case "neq":
498  case "gt":
499  case "lt":
500  case "gte":
501  case "lte":
502  return _run_comparison_keyword_modifier($modifier, $text);
503 
504  // Hash generation modifiers.
505  case "md5":
506  return md5($text);
507 
508  case "sha1":
509  return sha1($text);
510 
511  case "date_format":
512  // Format a date string and only prints the field required
513  $format = array_get_index($modifier['args'], 0, '');
514  return date($format, strtotime($text));
515 
516  case "replace":
517  $toReplace = array_get_index($modifier['args'], 0, NULL);
518  $replaceWith = array_get_index($modifier['args'], 1, NULL);
519 
520  if (!is_null($toReplace) && !is_null($replaceWith)) {
521  return preg_replace('/'.$toReplace.'/', $replaceWith, $text);
522  }
523  return $text;
524 
525  case "contains":
526  $toMatch = array_get_index($modifier['args'], 0, NULL);
527  $success = array_get_index($modifier['args'], 1, NULL);
528  $failure = array_get_index($modifier['args'], 2, NULL);
529 
530  if (!is_null($toMatch) && strpos($toMatch, '/') !== FALSE) $toMatch = str_replace('/', '\/', $toMatch);
531 
532  if (!is_null($toMatch) && preg_match_all('/'.$toMatch.'/', $text, $matches)) {
533  if (isset($matches[0]) && count($matches[0]) > 0) {
534  return $success ? $success : count($matches[0]);
535  }
536  }
537  return $failure ? $failure : 0;
538 
539  case "as_asset":
540  $asset_keyword = array_get_index($modifier['args'], 0, '');
541  if ($asset_keyword != '' && assert_valid_assetid($text, '', TRUE, FALSE)) {
542  if ($GLOBALS['SQ_SYSTEM']->am->assetExists($text)) {
543  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($text);
544  if ($asset->readAccess()) {
545  if (strpos($asset_keyword, 'asset_contents') === 0) {
546  if ($asset_keyword == 'asset_contents') {
547  // get the front end of the asset
548  $this_paint_layout = $asset->getCurrentPaintLayoutName();
549  $this_url = preg_replace('/^.+:\/\//', '', $asset->getURL());
550  $layout_id = $GLOBALS['SQ_SYSTEM']->am->getValueFromURL($this_url, $this_paint_layout);
551  ob_start();
552  if (!$layout_id) {
553  $asset->printBodyWithPaintLayout();
554  } else {
555  $asset->printBodyWithPaintLayout($layout_id);
556  }
557  $content = ob_get_contents();
558  ob_end_clean();
559 
560  } else if ($asset_keyword == 'asset_contents_raw') {
561  ob_start();
562  $asset->printBody();
563  $content = ob_get_contents();
564  ob_end_clean();
565 
566  } else if (strpos($asset_keyword, 'asset_contents_paint_layout_id') === 0) {
567  $layout_id = str_replace('asset_contents_paint_layout_id_', '', $asset_keyword);
568  ob_start();
569  if (!$layout_id) {
570  $asset->printBodyWithPaintLayout();
571  } else {
572  $asset->printBodyWithPaintLayout($layout_id);
573  }
574  $content = ob_get_contents();
575  ob_end_clean();
576 
577  } else if (0 === strpos ($asset_keyword, 'asset_contents_paint_layout_name')) {
578  $layout_name = str_replace('asset_contents_paint_layout_name_', '', $asset_keyword);
579  $this_url = preg_replace('/^.*:\/\//', '', $asset->getURL());
580 
581  // if user has not mentioned if it is a user defined or default frontend
582  // assume it is user defined
583  if (strpos($layout_name, 'paint_layout::user::') === FALSE && strpos($layout_name, 'paint_layout::system::frontend') === FALSE) {
584  $layout_name = 'paint_layout::user::'.$layout_name;
585  }
586  $layout_id = $GLOBALS['SQ_SYSTEM']->am->getValueFromURL($this_url, $layout_name);
587  ob_start();
588  if (!$layout_id) {
589  $asset->printBodyWithPaintLayout();
590  } else {
591  $asset->printBodyWithPaintLayout($layout_id);
592  }
593  $content = ob_get_contents();
594  ob_end_clean();
595  } else {
596  $content = '';
597  }
598 
599  return $content;
600 
601  } else {
602  return $asset->getKeywordReplacement($asset_keyword);
603  }
604  }
605  } else {
606  // assetid is numeric but the asset doesn't exist
607  trigger_localised_error('SYS0087', E_USER_WARNING, $text);
608  }
609  } else {
610  // the keyword is not empty but is also not a assetid let
611  // the user know about this so that they kno what happened
612  trigger_localised_error('CORE0321', E_USER_WARNING, $text);
613  }
614  return '';
615 
616  case "xslt":
617  $new_text = '';
618  try {
619  //create an XSL object from the file asset id
620  $xsl_assetid = array_get_index($modifier['args'], 0, NULL);
621  if (empty($xsl_assetid)) return $new_text;
622  $xsl_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($xsl_assetid);
623  if (empty($xsl_asset)) return $new_text;
624 
625  $xsl = new DOMDocument();
626  if ($xsl_asset instanceof File) {
627  $xsl->load($xsl_asset->data_path.'/'.$xsl_asset->name);
628  } else {
629  trigger_error("XSLT keyword modifier: The asset #$xsl_assetid is not a File asset.");
630  return $new_text;
631  }
632 
633  //create the xslt object and import the style sheet
634  $xslt = new XSLTProcessor();
635  $xslt->importStylesheet($xsl);
636 
637  //load the XML from the keyword replacement text
638  $xml = new DOMDocument();
639  $xml->loadXML($text);
640  $new_text = $xslt->transformToXml($xml);
641 
642  } catch (Exception $e) {
643  trigger_error($e->getMessage());
644  }
645 
646  return $new_text;
647 
648  case "json_encode":
649  if (!function_exists('json_encode')) {
650  require_once 'Services/JSON.php';
651  $json = new Services_JSON();
652  $output = $json->encodeUnsafe($text);
653  if (Services_JSON::isError($output)) {
654  trigger_error($output, E_USER_NOTICE);
655  }
656  } else {
657  $output = json_encode($text);
658  if (function_exists('json_last_error') && (json_last_error() != JSON_ERROR_NONE)) {
659  switch (json_last_error()) {
660  case JSON_ERROR_DEPTH:
661  $error = 'Maximum stack depth exceeded';
662  break;
663  case JSON_ERROR_STATE_MISMATCH:
664  $error = 'Underflow or the modes mismatch';
665  break;
666  case JSON_ERROR_CTRL_CHAR:
667  $error = 'Unexpected control character found';
668  break;
669  case JSON_ERROR_SYNTAX:
670  $error = 'Syntax error, malformed JSON';
671  break;
672  case JSON_ERROR_UTF8:
673  $error = 'Malformed UTF-8 characters, possibly incorrectly encoded';
674  break;
675  default:
676  $error = 'Unknown error';
677  break;
678  }
679  trigger_error($error, E_USER_NOTICE);
680  }
681  }
682 
683  // our encodeing has added extra double quotes at the start
684  // and end of our string. Remove them before returning text
685  return trim($output, '"');
686 
687  default:
688  return $text;
689 
690  }
691 
692 }//end _run_keyword_modifier()
693 
694 
703 function _run_arithmetic_keyword_modifier($modifier, $text)
704 {
705  // Divide
706  $n = array_get_index($modifier['args'], 0, 0);
707 
708  switch ($modifier['modifier']) {
709  case "add":
710  return $text + $n;
711  case "subtract":
712  return $text - $n;
713  case "multiply":
714  return $text * $n;
715  case "divide":
716  if ($n != 0) {
717  return $text / $n;
718  } else {
719  return '';
720  }
721  case "modulo":
722  if ($n != 0) {
723  return $text % $n;
724  } else {
725  return '';
726  }
727  case "squareroot":
728  if ($text > 0) {
729  return sqrt($text);
730  } else if ($text == '-1') {
731  return 'i';
732  } else {
733  return '';
734  }//end if
735  default:
736  return $text;
737  }
738 
739 }//end _run_arithmetic_keyword_modifier()
740 
741 
750 function _run_comparison_keyword_modifier($modifier, $text)
751 {
752  // Greater than. Returns '1' or ''.
753  $n = array_get_index($modifier['args'], 0, 0);
754  $t = array_get_index($modifier['args'], 1, '1');
755  $f = array_get_index($modifier['args'], 2, '');
756 
757  $ret = FALSE;
758  switch ($modifier['modifier']) {
759  case "eq":
760  $ret = $text == $n;
761  break;
762  case "neq":
763  $ret = $text != $n;
764  break;
765  case "gt":
766  $ret = $text > $n;
767  break;
768  case "gte":
769  $ret = $text >= $n;
770  break;
771  case "lt":
772  $ret = $text < $n;
773  break;
774  case "lte":
775  $ret = $text <= $n;
776  break;
777  }
778 
779  if ($ret) {
780  return $t;
781  } else {
782  return $f;
783  }
784 
785 }//end _run_comparison_keyword_modifier()
786 
787 
800 function retrieve_keywords_replacements($text, $additional='')
801 {
802  return extract_keywords($text, $additional);
803 
804 }//end retrieve_keywords_replacements()
805 
806 
816 function extract_keywords($text, $additional='')
817 {
818  $matches = Array();
819  $additional = preg_replace('|(.)|', '\\\\\1', $additional);
820 
821  // Match any keyword including the filter portion.
822  preg_match_all ('/%([a-zA-Z_]{2,}[a-zA-Z_\-0-9\.:'.$additional.']+(\^{1}[^%]+)*)%/', $text, $matches, PREG_PATTERN_ORDER);
823  return array_unique($matches[1]);
824 
825 }//end extract_keywords()
826 
827 
844 function get_word_counts($text, $split_regexp="/\s+/", $word_match_regexp="/\S+/", $min_length=1)
845 {
846  // type verification
847  if (!is_string($text) || !is_string($split_regexp) || !is_string($word_match_regexp) || !is_int($min_length)) {
848  return Array();
849  } else if (!is_int($min_length) || ($min_length < 0)) {
850  return Array();
851  }
852 
853  // Remove silent characters
854  $text = remove_silent_chars($text);
855 
856  $words = preg_split($split_regexp, $text, -1, PREG_SPLIT_NO_EMPTY);
857 
858  // Get rid of the leading and trailing white space
859  // Dont have good enough reason to save them
860  foreach ($words as $key => $word) {
861  $words[$key] = trim($word);
862  }
863 
864  $word_counts = array_count_values($words);
865  foreach ($word_counts as $word => $count) {
866  if (strlen($word) < $min_length || !preg_match($word_match_regexp, $word, $matches)) {
867  unset($word_counts[$word]);
868  }
869  }
870 
871  return $word_counts;
872 
873 }//end get_word_counts()
874 
875 
888 function remove_silent_chars($text, $not_indexing=FALSE, $oracle_keyword=FALSE)
889 {
890  // Replace period (.) and comma (,) in number, e.g. 1,234.5 => 12345
891  $number_pattern = '/(\d{1})[,.](\d{1})/'; // use that pattern instead of /(\d+)[,.](\d+)/ because this pattern can not replace both period and comma in one number. For example, 1,234.5 => 1234.5
892  $text = preg_replace($number_pattern, '$1$2', $text);
893 
894  if (!$oracle_keyword) {
895  // Remove at (@) and period (.) in email addresses, e.g. everyone@squiz.net => everyonesquiznet
896  // The following pattern matches most email addresses, but it will need to be review to match all email addresses
897  $email_pattern = '/([^@\s]+)@(([-a-z0-9]+\.)+[a-z]{2,})/e';
898  $text = preg_replace($email_pattern, 'str_replace(".", "", "$1").str_replace(".", "", "$2")', $text);
899 
900  // Remove apostrophe ('), e.g. you've => youve
901  $text = str_replace('\'', '', $text);
902  }
903 
904  $silent_chars = Array('.', ':', ';', ',', '!', '?', '`', '!', '@', '#', '$', '^', '*', '-', '=', '+', '{', '}', '[', ']', '\\', '<', '>', '/');
905  if ($not_indexing == FALSE) {
906  $oracle_search_operators = Array('(',')','"','~','&','|','%');
907  $silent_chars = array_merge($silent_chars, $oracle_search_operators);
908  //Remove the underscore ('_') that is usually used in metadata select field, e.g. select_1 => select1
909  $text = str_replace('_', '', $text); // just move underscore ('_') from the above line to this line so that it won't be removed when search in oracle
910  }
911 
912  // Replace the rest of silent characters with space (' '). This will create more indexed words but it is safer, e.g. Hello,world => Hello world
913  $text = str_replace($silent_chars, ' ', $text);
914 
915  return $text;
916 
917 }//end remove_silent_chars()
918 
919 
928 function escape_double_quotes(&$subject)
929 {
930  $subject = str_replace('"', '\"', $subject);
931 
932 }//end escape_double_quotes()
933 
934 
944 function escape_php(&$subject)
945 {
946  // not necessary to escape the php end tag when outside of a PHP block
947  $subject = str_replace('<?', "<?php echo '<'.'?'; ?>", $subject);
948  $subject = str_replace('<%', "<?php echo '<'.'%'; ?>", $subject);
949  $subject = preg_replace(
950  '/
951  <script[\s]*
952  language[\s]*=[\s]*
953  ["\']?php["\']?
954  [^>]*>
955  /xi',
956  "<?php echo '<'.'script language=\"php\">'; ?>",
957  $subject
958  );
959  return $subject;
960 
961 }//end escape_php()
962 
963 
975 function ucwords_no_space($string, $word_separator='_')
976 {
977  $tmp_word = strtr($string, $word_separator, ' ');
978  $tmp_word = preg_replace('/\s+/', '', ucwords($tmp_word));
979 
980  return $tmp_word;
981 
982 }//end ucwords_no_space()
983 
984 
997 function make_readable_list($string_array, $end_delimiter='and')
998 {
999  if (empty($string_array) || !is_array($string_array)) {
1000  return '';
1001  }
1002 
1003  $last = array_pop($string_array);
1004 
1005  if (empty($string_array)) return $last;
1006 
1007  $retval = implode(', ', $string_array);
1008  $retval .= ' '.$end_delimiter.' '.$last;
1009 
1010  return $retval;
1011 
1012 }//end make_readable_list()
1013 
1014 
1023 function escape_regex_chars($text)
1024 {
1025  return preg_replace('|([\{\}\(\)\^\$\.\*\?\+\-\[\]\\\])|', '\\\$1', $text);
1026 
1027 }//end escape_regex_chars()
1028 
1029 ?>