Source for file url_parser.php

Documentation is available at url_parser.php

  1. <?php
  2.  
  3. /**
  4.  * url_parser.php
  5.  *
  6.  * This code provides various string manipulation functions that are
  7.  * used by the rest of the SquirrelMail code.
  8.  *
  9.  * @copyright &copy; 1999-2006 The SquirrelMail Project Team
  10.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  11.  * @version $Id: url_parser.php,v 1.44.2.9 2006/05/06 08:32:08 tokul Exp $
  12.  * @package squirrelmail
  13.  */
  14.  
  15. /**
  16.  * Undocumented - complain, then patch.
  17.  */
  18. function replaceBlock (&$in, $replace, $start, $end) {
  19.     $begin = substr($in,0,$start);
  20.     $end   = substr($in,$end,strlen($in)-$end);
  21.     $in    = $begin.$replace.$end;
  22. }
  23.  
  24. /* Having this defined in just one spot could help when changes need
  25.  * to be made to the pattern
  26.  * Make sure that the expression is evaluated case insensitively
  27.  *
  28.  * Here's pretty sophisticated IP matching:
  29.  * $IPMatch = '(2[0-5][0-9]|1?[0-9]{1,2})';
  30.  * $IPMatch = '\[?' . $IPMatch . '(\.' . $IPMatch . '){3}\]?';
  31.  */
  32. /* Here's enough: */
  33. global $IP_RegExp_Match, $Host_RegExp_Match, $Email_RegExp_Match;
  34. $IP_RegExp_Match = '\\[?[0-9]{1,3}(\\.[0-9]{1,3}){3}\\]?';
  35. $Host_RegExp_Match = '(' . $IP_RegExp_Match .
  36.     '|[0-9a-z]([-.]?[0-9a-z])*\\.[a-z][a-z]+)';
  37. $Email_RegExp_Match = '[0-9a-z]([-_.+]?[0-9a-z])*(%' . $Host_RegExp_Match .
  38.     ')?@' . $Host_RegExp_Match;
  39.  
  40. function parseEmail (&$body) {
  41.     global $color, $Email_RegExp_Match, $compose_new_win;
  42.     $sbody     = $body;
  43.     $addresses = array();
  44.  
  45.     /* Find all the email addresses in the body */
  46.     while(eregi($Email_RegExp_Match, $sbody, $regs)) {
  47.         $addresses[$regs[0]] = $regs[0];
  48.         $start = strpos($sbody, $regs[0]) + strlen($regs[0]);
  49.         $sbody = substr($sbody, $start);
  50.     }
  51.     /* Replace each email address with a compose URL */
  52.     foreach ($addresses as $email) {
  53.         $comp_uri = makeComposeLink('src/compose.php?send_to='.urlencode($email), $email);
  54.         $body = str_replace($email, $comp_uri, $body);
  55.     }
  56.     /* Return number of unique addresses found */
  57.     return count($addresses);
  58. }
  59.  
  60.  
  61. /* We don't want to re-initialize this stuff for every line.  Save work
  62.  * and just do it once here.
  63.  */
  64. global $url_parser_url_tokens;
  65. $url_parser_url_tokens = array(
  66.     'http://',
  67.     'https://',
  68.     'ftp://',
  69.     'telnet:',  // Special case -- doesn't need the slashes
  70.         'gopher://',
  71.     'news://');
  72.  
  73. global $url_parser_poss_ends;
  74. $url_parser_poss_ends = array(' ', "\n", "\r", '<', '>', ".\r", ".\n",
  75.     '.&nbsp;', '&nbsp;', ')', '(', '&quot;', '&lt;', '&gt;', '.<',
  76.     ']', '[', '{', '}', "\240", ', ', '. ', ",\n", ",\r");
  77.  
  78.  
  79. function parseUrl (&$body) {
  80.     global $url_parser_poss_ends, $url_parser_url_tokens;
  81.     $start      = 0;
  82.     $blength    = strlen($body);
  83.  
  84.     while ($start != $blength) {
  85.         $target_token = '';
  86.         $target_pos = $blength;
  87.  
  88.         /* Find the first token to replace */
  89.         foreach ($url_parser_url_tokens as $the_token) {
  90.             $pos = strpos(strtolower($body), $the_token, $start);
  91.             if (is_int($pos) && $pos < $target_pos) {
  92.                 $target_pos   = $pos;
  93.                 $target_token = $the_token;
  94.             }
  95.         }
  96.  
  97.         /* Look for email addresses between $start and $target_pos */
  98.         $check_str = substr($body, $start, $target_pos-$start);
  99.  
  100.         if (parseEmail($check_str)) {
  101.             replaceBlock($body, $check_str, $start, $target_pos);
  102.             $blength    = strlen($body);
  103.             $target_pos = strlen($check_str) + $start;
  104.         }
  105.  
  106.         /* If there was a token to replace, replace it */
  107.         if ($target_token != '') {
  108.             /* Find the end of the URL */
  109.             $end = $blength;
  110.             foreach ($url_parser_poss_ends as $val) {
  111.                 $enda = strpos($body, $val, $target_pos);
  112.                 if (is_int($enda) && $enda < $end) {
  113.                     $end = $enda;
  114.                 }
  115.             }
  116.  
  117.             /* make sure that there are no 8bit chars between $target_pos and suspected end of URL */
  118.             if (!is_bool($first8bit=sq_strpos_8bit($body,$target_pos,$end))) {
  119.                 $end = $first8bit;
  120.             }
  121.  
  122.             /* Extract URL */
  123.             $url = substr($body, $target_pos, $end-$target_pos);
  124.  
  125.             /* Needed since lines are not passed with \n or \r */
  126.             while ( ereg("[,\.]$", $url) ) {
  127.                 $url = substr( $url, 0, -1 );
  128.                 $end--;
  129.             }
  130.  
  131.             /* Replace URL with HyperLinked Url, requires 1 char in link */
  132.             if ($url != '' && $url != $target_token) {
  133.                 $url_str = "<a href=\"$url\" target=\"_blank\">$url</a>";
  134.                 replaceBlock($body,$url_str,$target_pos,$end);
  135.                 $target_pos += strlen($url_str);
  136.             }
  137.             else {
  138.                 // Not quite a valid link, skip ahead to next chance
  139.                 $target_pos += strlen($target_token);
  140.             }
  141.         }
  142.  
  143.         /* Move forward */
  144.         $start   = $target_pos;
  145.         $blength = strlen($body);
  146.     }
  147. }
  148.  
  149. /**
  150.  * Finds first occurrence of 8bit data in the string
  151.  *
  152.  * Function finds first 8bit symbol or html entity that represents 8bit character.
  153.  * Search start is defined by $offset argument. Search ends at $maxlength position.
  154.  * If $maxlength is not defined or bigger than provided string, search ends when
  155.  * string ends.
  156.  *
  157.  * Check returned data type in order to avoid confusion between bool(false)
  158.  * (not found) and int(0) (first char in the string).
  159.  * @param string $haystack 
  160.  * @param integer $offset 
  161.  * @param integer $maxlength 
  162.  * @return mixed integer with first 8bit character position or boolean false
  163.  * @since 1.5.2 and 1.4.7
  164.  */
  165. function sq_strpos_8bit($haystack,$offset=0,$maxlength=false) {
  166.     $ret = false;
  167.     
  168.     if ($maxlength===false || strlen($haystack) < $maxlength) {
  169.         $maxlength=strlen($haystack);
  170.     }
  171.  
  172.     for($i=$offset;$i<$maxlength;$i++) {
  173.         /* rh7-8 compatibility. don't use full 8bit range in regexp */
  174.         if (preg_match('/[\200-\237]|\240|[\241-\377]/',$haystack[$i])) {
  175.             /* we have 8bit char. stop here and return position */
  176.             $ret = $i;
  177.             break;
  178.         } elseif ($haystack[$i]=='&') {
  179.             $substring = substr($haystack,$i);
  180.             /**
  181.              * 1. look for "&#(decimal number);" where decimal_number is bigger than 127
  182.              * 2. look for "&x(hexadecimal number);", where hex number is bigger than x7f
  183.              * 3. look for any html character entity that is not 7bit html special char. Use 
  184.              * own sq_get_html_translation_table() function with 'utf-8' character set in 
  185.              * order to get all html entities.
  186.              */
  187.             if ((preg_match('/^&#(\d+);/',$substring,$match) && $match[1]>127) ||
  188.                 (preg_match('/^&x([0-9a-f]+);/i',$substring,$match) && $match[1]>"\x7f") ||
  189.                 (preg_match('/^&([a-z]+);/i',$substring,$match) && 
  190.                  !in_array($match[0],get_html_translation_table(HTML_SPECIALCHARS)) && 
  191.                  in_array($match[0],sq_get_html_translation_table(HTML_ENTITIES,ENT_COMPAT,'utf-8')))) {
  192.                 $ret = $i;
  193.                 break;
  194.             }
  195.         }
  196.     }
  197.     return $ret;
  198. }
  199. ?>

Documentation generated on Sat, 07 Oct 2006 16:33:59 +0300 by phpDocumentor 1.3.0RC6