source: github/program/include/rcube_string_replacer.php @ 96e24fa

HEADcourier-fixdev-browser-capabilitiespdorelease-0.6release-0.7release-0.8
Last change on this file since 96e24fa was 96e24fa, checked in by alecpl <alec@…>, 2 years ago
  • Fix parsing URLs containing commas (#1487970)
  • Property mode set to 100644
File size: 5.2 KB
Line 
1<?php
2
3/*
4 +-----------------------------------------------------------------------+
5 | program/include/rcube_string_replacer.php                             |
6 |                                                                       |
7 | This file is part of the Roundcube Webmail client                     |
8 | Copyright (C) 2009, The Roundcube Dev Team                            |
9 | Licensed under the GNU GPL                                            |
10 |                                                                       |
11 | PURPOSE:                                                              |
12 |   Handle string replacements based on preg_replace_callback           |
13 |                                                                       |
14 +-----------------------------------------------------------------------+
15 | Author: Thomas Bruederli <roundcube@gmail.com>                        |
16 +-----------------------------------------------------------------------+
17
18 $Id$
19
20*/
21
22
23/**
24 * Helper class for string replacements based on preg_replace_callback
25 *
26 * @package Core
27 */
28class rcube_string_replacer
29{
30  public static $pattern = '/##str_replacement\[([0-9]+)\]##/';
31  public $mailto_pattern;
32  public $link_pattern;
33  private $values = array();
34
35
36  function __construct()
37  {
38    // Simplified domain expression for UTF8 characters handling
39    // Support unicode/punycode in top-level domain part
40    $utf_domain = '[^?&@"\'\\/()\s\r\t\n]+\\.([^\\x00-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,})';
41    $url1 = '.:;,';
42    $url2 = 'a-z0-9%=#@+?&\\/_~\\[\\]-';
43
44    $this->link_pattern = "/([\w]+:\/\/|\Wwww\.)($utf_domain([$url1]?[$url2]+)*)/i";
45    $this->mailto_pattern = "/("
46        ."[-\w!\#\$%&\'*+~\/^`|{}=]+(?:\.[-\w!\#\$%&\'*+~\/^`|{}=]+)*"  // local-part
47        ."@$utf_domain"                                                 // domain-part
48        ."(\?[$url1$url2]+)?"                                           // e.g. ?subject=test...
49        .")/i";
50  }
51
52  /**
53   * Add a string to the internal list
54   *
55   * @param string String value
56   * @return int Index of value for retrieval
57   */
58  public function add($str)
59  {
60    $i = count($this->values);
61    $this->values[$i] = $str;
62    return $i;
63  }
64
65  /**
66   * Build replacement string
67   */
68  public function get_replacement($i)
69  {
70    return '##str_replacement['.$i.']##';
71  }
72
73  /**
74   * Callback function used to build HTML links around URL strings
75   *
76   * @param array Matches result from preg_replace_callback
77   * @return int Index of saved string value
78   */
79  public function link_callback($matches)
80  {
81    $i = -1;
82    $scheme = strtolower($matches[1]);
83
84    if (preg_match('!^(http|ftp|file)s?://!', $scheme)) {
85      $url = $matches[1] . $matches[2];
86    }
87    else if (preg_match('/^(\W)www\.$/', $matches[1], $m)) {
88      $url        = 'www.' . $matches[2];
89      $url_prefix = 'http://';
90      $prefix     = $m[1];
91    }
92
93    if ($url) {
94      $suffix = $this->parse_url_brackets($url);
95      $i = $this->add($prefix . html::a(array(
96          'href' => $url_prefix . $url,
97          'target' => '_blank'
98        ), Q($url)) . $suffix);
99    }
100
101    // Return valid link for recognized schemes, otherwise, return the unmodified string for unrecognized schemes.
102    return $i >= 0 ? $this->get_replacement($i) : $matches[0];
103  }
104
105  /**
106   * Callback function used to build mailto: links around e-mail strings
107   *
108   * @param array Matches result from preg_replace_callback
109   * @return int Index of saved string value
110   */
111  public function mailto_callback($matches)
112  {
113    $href   = $matches[1];
114    $suffix = $this->parse_url_brackets($href);
115
116    $i = $this->add(html::a(array(
117        'href' => 'mailto:' . $href,
118        'onclick' => "return ".JS_OBJECT_NAME.".command('compose','".JQ($href)."',this)",
119      ), Q($href)) . $suffix);
120
121    return $i >= 0 ? $this->get_replacement($i) : '';
122  }
123
124  /**
125   * Look up the index from the preg_replace matches array
126   * and return the substitution value.
127   *
128   * @param array Matches result from preg_replace_callback
129   * @return string Value at index $matches[1]
130   */
131  public function replace_callback($matches)
132  {
133    return $this->values[$matches[1]];
134  }
135
136  /**
137   * Replace substituted strings with original values
138   */
139  public function resolve($str)
140  {
141    return preg_replace_callback(self::$pattern, array($this, 'replace_callback'), $str);
142  }
143
144  /**
145   * Fixes bracket characters in URL handling
146   */
147  public static function parse_url_brackets(&$url)
148  {
149    // #1487672: special handling of square brackets,
150    // URL regexp allows [] characters in URL, for example:
151    // "http://example.com/?a[b]=c". However we need to handle
152    // properly situation when a bracket is placed at the end
153    // of the link e.g. "[http://example.com]"
154    if (preg_match('/(\\[|\\])/', $url)) {
155      $in = false;
156      for ($i=0, $len=strlen($url); $i<$len; $i++) {
157        if ($url[$i] == '[') {
158          if ($in)
159            break;
160          $in = true;
161        }
162        else if ($url[$i] == ']') {
163          if (!$in)
164            break;
165          $in = false;
166        }
167      }
168
169      if ($i<$len) {
170        $suffix = substr($url, $i);
171        $url    = substr($url, 0, $i);
172      }
173    }
174
175    return $suffix;
176  }
177
178}
Note: See TracBrowser for help on using the repository browser.