Mercurial > hg > rc2
comparison program/lib/Roundcube/rcube_string_replacer.php @ 0:4681f974d28b
vanilla 1.3.3 distro, I hope
author | Charlie Root |
---|---|
date | Thu, 04 Jan 2018 15:52:31 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4681f974d28b |
---|---|
1 <?php | |
2 | |
3 /** | |
4 +-----------------------------------------------------------------------+ | |
5 | This file is part of the Roundcube Webmail client | | |
6 | Copyright (C) 2009-2012, The Roundcube Dev Team | | |
7 | | | |
8 | Licensed under the GNU General Public License version 3 or | | |
9 | any later version with exceptions for skins & plugins. | | |
10 | See the README file for a full license statement. | | |
11 | | | |
12 | PURPOSE: | | |
13 | Handle string replacements based on preg_replace_callback | | |
14 +-----------------------------------------------------------------------+ | |
15 | Author: Thomas Bruederli <roundcube@gmail.com> | | |
16 +-----------------------------------------------------------------------+ | |
17 */ | |
18 | |
19 /** | |
20 * Helper class for string replacements based on preg_replace_callback | |
21 * | |
22 * @package Framework | |
23 * @subpackage Utils | |
24 */ | |
25 class rcube_string_replacer | |
26 { | |
27 public static $pattern = '/##str_replacement_(\d+)##/'; | |
28 public $mailto_pattern; | |
29 public $link_pattern; | |
30 public $linkref_index; | |
31 public $linkref_pattern; | |
32 | |
33 protected $values = array(); | |
34 protected $options = array(); | |
35 protected $linkrefs = array(); | |
36 protected $urls = array(); | |
37 protected $noword = '[^\w@.#-]'; | |
38 | |
39 | |
40 function __construct($options = array()) | |
41 { | |
42 // Simplified domain expression for UTF8 characters handling | |
43 // Support unicode/punycode in top-level domain part | |
44 $utf_domain = '[^?&@"\'\\/()<>\s\r\t\n]+\\.?([^\\x00-\\x2f\\x3b-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-zA-Z0-9]{2,})'; | |
45 $url1 = '.:;,'; | |
46 $url2 = 'a-zA-Z0-9%=#$@+?|!&\\/_~\\[\\]\\(\\){}\*\x80-\xFE-'; | |
47 | |
48 // Supported link prefixes | |
49 $link_prefix = "([\w]+:\/\/|{$this->noword}[Ww][Ww][Ww]\.|^[Ww][Ww][Ww]\.)"; | |
50 | |
51 $this->options = $options; | |
52 $this->linkref_index = '/\[([^\]#]+)\](:?\s*##str_replacement_(\d+)##)/'; | |
53 $this->linkref_pattern = '/\[([^\]#]+)\]/'; | |
54 $this->link_pattern = "/$link_prefix($utf_domain([$url1]*[$url2]+)*)/"; | |
55 $this->mailto_pattern = "/(" | |
56 ."[-\w!\#\$%&\'*+~\/^`|{}=]+(?:\.[-\w!\#\$%&\'*+~\/^`|{}=]+)*" // local-part | |
57 ."@$utf_domain" // domain-part | |
58 ."(\?[$url1$url2]+)?" // e.g. ?subject=test... | |
59 .")/"; | |
60 } | |
61 | |
62 /** | |
63 * Add a string to the internal list | |
64 * | |
65 * @param string String value | |
66 * | |
67 * @return int Index of value for retrieval | |
68 */ | |
69 public function add($str) | |
70 { | |
71 $i = count($this->values); | |
72 $this->values[$i] = $str; | |
73 return $i; | |
74 } | |
75 | |
76 /** | |
77 * Build replacement string | |
78 */ | |
79 public function get_replacement($i) | |
80 { | |
81 return '##str_replacement_' . $i . '##'; | |
82 } | |
83 | |
84 /** | |
85 * Callback function used to build HTML links around URL strings | |
86 * | |
87 * @param array Matches result from preg_replace_callback | |
88 * @return int Index of saved string value | |
89 */ | |
90 public function link_callback($matches) | |
91 { | |
92 $i = -1; | |
93 $scheme = strtolower($matches[1]); | |
94 | |
95 if (preg_match('!^(http|ftp|file)s?://!i', $scheme)) { | |
96 $url = $matches[1] . $matches[2]; | |
97 } | |
98 else if (preg_match("/^({$this->noword}*)(www\.)$/i", $matches[1], $m)) { | |
99 $url = $m[2] . $matches[2]; | |
100 $url_prefix = 'http://'; | |
101 $prefix = $m[1]; | |
102 } | |
103 | |
104 if ($url) { | |
105 $suffix = $this->parse_url_brackets($url); | |
106 $attrib = (array)$this->options['link_attribs']; | |
107 $attrib['href'] = $url_prefix . $url; | |
108 | |
109 $i = $this->add(html::a($attrib, rcube::Q($url)) . $suffix); | |
110 $this->urls[$i] = $attrib['href']; | |
111 } | |
112 | |
113 // Return valid link for recognized schemes, otherwise | |
114 // return the unmodified string for unrecognized schemes. | |
115 return $i >= 0 ? $prefix . $this->get_replacement($i) : $matches[0]; | |
116 } | |
117 | |
118 /** | |
119 * Callback to add an entry to the link index | |
120 */ | |
121 public function linkref_addindex($matches) | |
122 { | |
123 $key = $matches[1]; | |
124 $this->linkrefs[$key] = $this->urls[$matches[3]]; | |
125 | |
126 return $this->get_replacement($this->add('['.$key.']')) . $matches[2]; | |
127 } | |
128 | |
129 /** | |
130 * Callback to replace link references with real links | |
131 */ | |
132 public function linkref_callback($matches) | |
133 { | |
134 $i = 0; | |
135 if ($url = $this->linkrefs[$matches[1]]) { | |
136 $attrib = (array)$this->options['link_attribs']; | |
137 $attrib['href'] = $url; | |
138 $i = $this->add(html::a($attrib, rcube::Q($matches[1]))); | |
139 } | |
140 | |
141 return $i > 0 ? '['.$this->get_replacement($i).']' : $matches[0]; | |
142 } | |
143 | |
144 /** | |
145 * Callback function used to build mailto: links around e-mail strings | |
146 * | |
147 * @param array Matches result from preg_replace_callback | |
148 * | |
149 * @return int Index of saved string value | |
150 */ | |
151 public function mailto_callback($matches) | |
152 { | |
153 $href = $matches[1]; | |
154 $suffix = $this->parse_url_brackets($href); | |
155 $i = $this->add(html::a('mailto:' . $href, rcube::Q($href)) . $suffix); | |
156 | |
157 return $i >= 0 ? $this->get_replacement($i) : ''; | |
158 } | |
159 | |
160 /** | |
161 * Look up the index from the preg_replace matches array | |
162 * and return the substitution value. | |
163 * | |
164 * @param array Matches result from preg_replace_callback | |
165 * @return string Value at index $matches[1] | |
166 */ | |
167 public function replace_callback($matches) | |
168 { | |
169 return $this->values[$matches[1]]; | |
170 } | |
171 | |
172 /** | |
173 * Replace all defined (link|mailto) patterns with replacement string | |
174 * | |
175 * @param string $str Text | |
176 * | |
177 * @return string Text | |
178 */ | |
179 public function replace($str) | |
180 { | |
181 // search for patterns like links and e-mail addresses | |
182 $str = preg_replace_callback($this->link_pattern, array($this, 'link_callback'), $str); | |
183 $str = preg_replace_callback($this->mailto_pattern, array($this, 'mailto_callback'), $str); | |
184 // resolve link references | |
185 $str = preg_replace_callback($this->linkref_index, array($this, 'linkref_addindex'), $str); | |
186 $str = preg_replace_callback($this->linkref_pattern, array($this, 'linkref_callback'), $str); | |
187 | |
188 return $str; | |
189 } | |
190 | |
191 /** | |
192 * Replace substituted strings with original values | |
193 */ | |
194 public function resolve($str) | |
195 { | |
196 return preg_replace_callback(self::$pattern, array($this, 'replace_callback'), $str); | |
197 } | |
198 | |
199 /** | |
200 * Fixes bracket characters in URL handling | |
201 */ | |
202 public static function parse_url_brackets(&$url) | |
203 { | |
204 // #1487672: special handling of square brackets, | |
205 // URL regexp allows [] characters in URL, for example: | |
206 // "http://example.com/?a[b]=c". However we need to handle | |
207 // properly situation when a bracket is placed at the end | |
208 // of the link e.g. "[http://example.com]" | |
209 // Yes, this is not perfect handles correctly only paired characters | |
210 // but it should work for common cases | |
211 | |
212 if (preg_match('/(\\[|\\])/', $url)) { | |
213 $in = false; | |
214 for ($i=0, $len=strlen($url); $i<$len; $i++) { | |
215 if ($url[$i] == '[') { | |
216 if ($in) | |
217 break; | |
218 $in = true; | |
219 } | |
220 else if ($url[$i] == ']') { | |
221 if (!$in) | |
222 break; | |
223 $in = false; | |
224 } | |
225 } | |
226 | |
227 if ($i < $len) { | |
228 $suffix = substr($url, $i); | |
229 $url = substr($url, 0, $i); | |
230 } | |
231 } | |
232 | |
233 // Do the same for parentheses | |
234 if (preg_match('/(\\(|\\))/', $url)) { | |
235 $in = false; | |
236 for ($i=0, $len=strlen($url); $i<$len; $i++) { | |
237 if ($url[$i] == '(') { | |
238 if ($in) | |
239 break; | |
240 $in = true; | |
241 } | |
242 else if ($url[$i] == ')') { | |
243 if (!$in) | |
244 break; | |
245 $in = false; | |
246 } | |
247 } | |
248 | |
249 if ($i < $len) { | |
250 $suffix = substr($url, $i); | |
251 $url = substr($url, 0, $i); | |
252 } | |
253 } | |
254 | |
255 return $suffix; | |
256 } | |
257 } |