PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.6.4
Jetpack – WP Security, Backup, Speed, & Growth v12.6.4
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / vendor / nojimage / twitter-text-php / lib / Twitter / Text / Regex.php
jetpack / vendor / nojimage / twitter-text-php / lib / Twitter / Text Last commit date
Autolink.php 5 years ago Configuration.php 5 years ago EmojiRegex.php 5 years ago Extractor.php 5 years ago HitHighlighter.php 5 years ago ParseResults.php 5 years ago Parser.php 5 years ago Regex.php 5 years ago StringUtils.php 5 years ago TldLists.php 5 years ago Validator.php 5 years ago
Regex.php
839 lines
1 <?php
2
3 /**
4 * @author Mike Cochrane <mikec@mikenz.geek.nz>
5 * @author Nick Pope <nick@nickpope.me.uk>
6 * @copyright Copyright © 2010, Mike Cochrane, Nick Pope
7 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
8 * @package Twitter.Text
9 */
10
11 namespace Twitter\Text;
12
13 /**
14 * Twitter Regex Abstract Class
15 *
16 * Used by subclasses that need to parse tweets.
17 *
18 * Originally written by {@link http://github.com/mikenz Mike Cochrane}, this
19 * is based on code by {@link http://github.com/mzsanford Matt Sanford} and
20 * heavily modified by {@link http://github.com/ngnpope Nick Pope}.
21 *
22 * @author Mike Cochrane <mikec@mikenz.geek.nz>
23 * @author Nick Pope <nick@nickpope.me.uk>
24 * @copyright Copyright © 2010, Mike Cochrane, Nick Pope
25 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
26 * @package Twitter
27 */
28 class Regex
29 {
30 /**
31 * Expression to match whitespace characters.
32 *
33 * 0x0009-0x000D Cc # <control-0009>..<control-000D>
34 * 0x0020 Zs # SPACE
35 * 0x0085 Cc # <control-0085>
36 * 0x00A0 Zs # NO-BREAK SPACE
37 * 0x1680 Zs # OGHAM SPACE MARK
38 * 0x180E Zs # MONGOLIAN VOWEL SEPARATOR
39 * 0x2000-0x200A Zs # EN QUAD..HAIR SPACE
40 * 0x2028 Zl # LINE SEPARATOR
41 * 0x2029 Zp # PARAGRAPH SEPARATOR
42 * 0x202F Zs # NARROW NO-BREAK SPACE
43 * 0x205F Zs # MEDIUM MATHEMATICAL SPACE
44 * 0x3000 Zs # IDEOGRAPHIC SPACE
45 *
46 * @var string
47 */
48 // @codingStandardsIgnoreStart
49 private static $spaces = '\x{0009}-\x{000D}\x{0020}\x{0085}\x{00a0}\x{1680}\x{180E}\x{2000}-\x{200a}\x{2028}\x{2029}\x{202f}\x{205f}\x{3000}'; // @codingStandardsIgnoreEnd
50
51 /**
52 * Expression to match latin accented characters.
53 *
54 * 0x00C0-0x00D6
55 * 0x00D8-0x00F6
56 * 0x00F8-0x00FF
57 * 0x0100-0x024f
58 * 0x0253-0x0254
59 * 0x0256-0x0257
60 * 0x0259
61 * 0x025b
62 * 0x0263
63 * 0x0268
64 * 0x026f
65 * 0x0272
66 * 0x0289
67 * 0x028b
68 * 0x02bb
69 * 0x0300-0x036f
70 * 0x1e00-0x1eff
71 *
72 * Excludes 0x00D7 - multiplication sign (confusable with 'x').
73 * Excludes 0x00F7 - division sign.
74 *
75 * @var string
76 */
77 // @codingStandardsIgnoreStart
78 private static $latinAccents = '\x{00c0}-\x{00d6}\x{00d8}-\x{00f6}\x{00f8}-\x{00ff}\x{0100}-\x{024f}\x{0253}-\x{0254}\x{0256}-\x{0257}\x{0259}\x{025b}\x{0263}\x{0268}\x{026f}\x{0272}\x{0289}\x{028b}\x{02bb}\x{0300}-\x{036f}\x{1e00}-\x{1eff}'; // @codingStandardsIgnoreEnd
79
80 /**
81 * Invalid Characters
82 *
83 * 0xFFFE,0xFEFF # BOM
84 * 0xFFFF # Special
85 * 0x202A-0x202E # Directional change
86 */
87 private static $invalidCharacters = '\x{202a}-\x{202e}\x{feff}\x{fffe}\x{ffff}';
88
89 /**
90 * Directional Characters
91 *
92 * 0x061C ARABIC LETTER MARK (ALM)
93 * 0x200E LEFT-TO-RIGHT MARK (LRM)
94 * 0x200F RIGHT-TO-LEFT MARK (RLM)
95 * 0x202A LEFT-TO-RIGHT EMBEDDING (LRE)
96 * 0x202B RIGHT-TO-LEFT EMBEDDING (RLE)
97 * 0x202C POP DIRECTIONAL FORMATTING (PDF)
98 * 0x202D LEFT-TO-RIGHT OVERRIDE (LRO)
99 * 0x202E RIGHT-TO-LEFT OVERRIDE (RLO)
100 * 0x2066 LEFT-TO-RIGHT ISOLATE (LRI)
101 * 0x2067 RIGHT-TO-LEFT ISOLATE (RLI)
102 * 0x2068 FIRST STRONG ISOLATE (FSI)
103 * 0x2069 POP DIRECTIONAL ISOLATE (PDI)
104 */
105 private static $directionalCharacters = '\x{061c}\x{200e}\x{200f}\x{202a}\x{202e}\x{2066}\x{2069}';
106
107 /**
108 * Expression to match RTL characters.
109 *
110 * 0x0600-0x06FF Arabic
111 * 0x0750-0x077F Arabic Supplement
112 * 0x08A0-0x08FF Arabic Extended-A
113 * 0x0590-0x05FF Hebrew
114 * 0xFB50-0xFDFF Arabic Presentation Forms-A
115 * 0xFE70-0xFEFF Arabic Presentation Forms-B
116 *
117 * @var string
118 */
119 // @codingStandardsIgnoreStart
120 private static $rtlChars = '\x{0600}-\x{06ff}\x{0750}-\x{077f}\x{08a0}-\x{08ff}\x{0590}-\x{05ff}\x{fb50}-\x{fdff}\x{fe70}-\x{feff}'; // @codingStandardsIgnoreEnd
121
122 # Expression to match at and hash sign characters:
123 private static $atSigns = '@@';
124
125 private static $hashSigns = '##';
126
127 # cash tags
128 private static $cashSigns = '\$';
129
130 private static $cashtag = '[a-z]{1,6}(?:[._][a-z]{1,2})?';
131
132 # These URL validation pattern strings are based on the ABNF from RFC 3986
133 private static $validateUrlUnreserved = '[a-z\p{Cyrillic}0-9\-._~]';
134
135 private static $validateUrlPctEncoded = '(?:%[0-9a-f]{2})';
136
137 private static $validateUrlSubDelims = '[!$&\'()*+,;=]';
138
139 private static $validUrlQueryChars = '[a-z0-9!?\*\'\(\);:&=\+\$\/%#\[\]\-_\.,~|@]';
140
141 private static $validUrlQueryEndingChars = '[a-z0-9_&=#\/\-]';
142
143 // @codingStandardsIgnoreStart
144 private static $validateUrlIpv4 = '(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(?:\.(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3})'; // @codingStandardsIgnoreEnd
145
146 private static $validateUrlIpv6 = '(?:\[[a-f0-9:\.]+\])';
147
148 private static $validateUrlPort = '[0-9]{1,5}';
149
150 # URL related hash regex collection
151 private static $validSpecialCcTLD = '(?:(?:co|tv)(?=[^0-9a-z@]|$))';
152
153 private static $validPunycode = '(?:xn--[0-9a-z]+)';
154
155 /**
156 * Get invalid characters matcher
157 *
158 * @staticvar string $regexp
159 * @return string
160 */
161 public static function getInvalidCharactersMatcher()
162 {
163 static $regexp = null;
164
165 if ($regexp === null) {
166 $regexp = '/[' . static::$invalidCharacters . ']/u';
167 }
168
169 return $regexp;
170 }
171
172 /**
173 * Get RTL characters matcher
174 *
175 * @staticvar string $regexp
176 * @return string
177 */
178 public static function getRtlCharsMatcher()
179 {
180 static $regexp = null;
181
182 if ($regexp === null) {
183 $regexp = '/[' . static::$rtlChars . ']/iu';
184 }
185
186 return $regexp;
187 }
188
189 // =================================================================================================================
190
191 /**
192 * Get valid ascii domain matcher
193 *
194 * @staticvar string $regexp
195 * @return string
196 */
197 public static function getValidAsciiDomainMatcher()
198 {
199 static $regexp = null;
200
201 if ($regexp === null) {
202 $regexp = '/' . static::getValidSubdomain() . '*(' . static::getValidDomainName()
203 . ')(?:' . TldLists::getValidGTLD() . '|' . TldLists::getValidCcTLD()
204 . '|' . static::$validPunycode . ')/iu';
205 }
206
207 return $regexp;
208 }
209
210 /**
211 * Get valid tco url matcher
212 *
213 * Used by the extractor for stricter t.co URL extraction
214 *
215 * @staticvar string $regexp
216 * @return string
217 */
218 public static function getValidTcoUrlMatcher()
219 {
220 static $regexp = null;
221
222 if ($regexp === null) {
223 $regexp = '/^https?:\/\/t\.co\/([a-z0-9]+)'
224 . '(?:\?' . static::$validUrlQueryChars . '*' . static::$validUrlQueryEndingChars . ')?/iu';
225 }
226
227 return $regexp;
228 }
229
230 /**
231 * Get invalid short domain matcher
232 *
233 * @staticvar string $regexp
234 * @return string
235 */
236 public static function getInvalidShortDomainMatcher()
237 {
238 static $regexp = null;
239
240 if ($regexp === null) {
241 $regexp = '/\A' . static::getValidDomainName() . TldLists::getValidCcTLD() . '\Z/iu';
242 }
243
244 return $regexp;
245 }
246
247 /**
248 * Get valid special short domain matcher
249 *
250 * @staticvar string $regexp
251 * @return string
252 */
253 public static function getValidSpecialShortDomainMatcher()
254 {
255 static $regexp = null;
256
257 if ($regexp === null) {
258 $regexp = '/\A' . static::getValidDomainName() . static::$validSpecialCcTLD . '\Z/iu';
259 }
260
261 return $regexp;
262 }
263
264 /**
265 * Get invalid url without protocol preceding chars matcher
266 *
267 * @staticvar string $regexp
268 * @return string
269 */
270 public static function getInvalidUrlWithoutProtocolPrecedingCharsMatcher()
271 {
272 static $regexp = null;
273
274 if ($regexp === null) {
275 $regexp = '/[\-_.\/]\z/iu';
276 }
277
278 return $regexp;
279 }
280
281 /**
282 * Get valid url
283 *
284 * @staticvar string $regexp
285 * @return string
286 */
287 public static function getValidUrlMatcher()
288 {
289 static $regexp = null;
290
291 if ($regexp === null) {
292 $validUrlPrecedingChars = '(?:[^a-z0-9_@@\$##' . static::$invalidCharacters . ']|[' . static::$directionalCharacters . ']|^)';
293 $validPortNumber = '[0-9]+';
294
295 $regexp = '/(?:' # $1 Complete match (preg_match() already matches everything.)
296 . '(' . $validUrlPrecedingChars . ')' # $2 Preceding characters
297 . '(' # $3 Complete URL
298 . '(https?:\/\/)?' # $4 Protocol (optional)
299 . '(' . static::getValidDomain() . ')' # $5 Domain(s)
300 . '(?::(' . $validPortNumber . '))?' # $6 Port number (optional)
301 . '(\/' . static::getValidUrlPath() . '*)?' # $7 URL Path
302 . '(\?' . static::$validUrlQueryChars . '*' . static::$validUrlQueryEndingChars . ')?' # $8 Query String
303 . ')'
304 . ')/iux';
305 }
306
307 return $regexp;
308 }
309
310 /**
311 * Get valid domain chars
312 *
313 * @return string
314 */
315 private static function getValidDomainChars()
316 {
317 return '0-9a-z' . static::$latinAccents;
318 }
319
320 /**
321 * Get valid subdomain
322 *
323 * @return string
324 */
325 private static function getValidSubdomain()
326 {
327 $domainValidChars = static::getValidDomainChars();
328
329 return '(?>(?:[' . $domainValidChars . '][' . $domainValidChars . '\-_]*)?[' . $domainValidChars . ']\.)';
330 }
331
332 /**
333 * Get valid domain name
334 *
335 * @return string
336 */
337 private static function getValidDomainName()
338 {
339 $domainValidChars = static::getValidDomainChars();
340
341 return '(?:(?:[' . $domainValidChars . '][' . $domainValidChars . '\-]*)?[' . $domainValidChars . ']\.)';
342 }
343
344 /**
345 * Get valid unicode domain chars
346 *
347 * @return string
348 */
349 private static function getValidUnicodeDomainChars()
350 {
351 return '[^\p{P}\p{Z}\p{C}' . static::$invalidCharacters . static::$spaces . ']';
352 }
353
354 /**
355 * Get valid unicode domain name
356 *
357 * @return string
358 */
359 private static function getValidUnicodeDomainName()
360 {
361 $domainValidChars = static::getValidUnicodeDomainChars();
362
363 return '(?:(?:' . $domainValidChars . '(?:' . $domainValidChars . '|[\-])*)?' . $domainValidChars . '\.)';
364 }
365
366 /**
367 * Get valid domain
368 *
369 * @return string
370 */
371 private static function getValidDomain()
372 {
373 $validSubdomain = static::getValidSubdomain();
374 $validDomainName = static::getValidDomainName();
375 $validUnicodeDomainName = static::getValidUnicodeDomainName();
376 $validGTLD = TldLists::getValidGTLD();
377 $validCcTLD = TldLists::getValidCcTLD();
378
379 return ''
380 // optional sub-domain + domain + TLD
381 // e.g. twitter.com, foo.co.jp, bar.co.uk
382 . '(?:' . $validSubdomain . '*' . $validDomainName
383 . '(?:' . $validGTLD . '|' . $validCcTLD . '|' . static::$validPunycode . '))'
384 // domain + gTLD | protocol + unicode domain + gTLD
385 . '|(?:'
386 . '(?:' . $validSubdomain . '+' . $validDomainName
387 . '|' . $validDomainName
388 . '|(?:(?<=http:\/\/|https:\/\/)' . $validUnicodeDomainName . ')'
389 . ')'
390 . $validGTLD
391 . ')'
392 // protocol + (domain | unicode domain) + ccTLD
393 . '|(?:(?<=http:\/\/|https:\/\/)'
394 . '(?:' . $validDomainName . '|' . $validUnicodeDomainName . ')'
395 . $validCcTLD . ')'
396 // domain + ccTLD + '/'
397 // e.g. t.co/
398 . '|(?:' . $validDomainName . $validCcTLD . '(?=\/))';
399 }
400
401 /**
402 * Get valid url path
403 *
404 * @return string
405 */
406 private static function getValidUrlPath()
407 {
408 $validGeneralUrlPathChars = '[a-z0-9' . preg_quote("!*';:=+,.$/%#[]–\x{2013}_~", '/')
409 . '|&@' . static::$latinAccents . '\p{Cyrillic}]';
410
411 # Allow URL paths to contain up to two nested levels of balanced parentheses:
412 # 1. Used in Wikipedia URLs, e.g. /Primer_(film)
413 # 2. Used in IIS sessions, e.g. /S(dfd346)/
414 # 3. Used in Rdio URLs like /track/We_Up_(Album_Version_(Edited))/
415 $validUrlBalancedParens = '(?:\('
416 . '(?:' . $validGeneralUrlPathChars . '+'
417 . '|'
418 // allow one nested level of balanced parentheses
419 . '(?:'
420 . $validGeneralUrlPathChars . '*'
421 . '\(' . $validGeneralUrlPathChars . '+' . '\)'
422 . $validGeneralUrlPathChars . '*'
423 . ')'
424 . ')'
425 . '\))';
426 # Valid end-of-path characters (so /foo. does not gobble the period).
427 # 1. Allow =&# for empty URL parameters and other URL-join artifacts.
428 $validUrlPathEndingChars = '[a-z0-9=_#\/\+\-' . static::$latinAccents . '\p{Cyrillic}]'
429 . '|(?:' . $validUrlBalancedParens . ')';
430
431 return '(?:(?:'
432 . $validGeneralUrlPathChars . '*(?:'
433 . $validUrlBalancedParens . ' '
434 . $validGeneralUrlPathChars . '*)*'
435 . $validUrlPathEndingChars . ')|(?:@'
436 . $validGeneralUrlPathChars . '+\/))';
437 }
438
439 // =================================================================================================================
440
441 # NOTE: PHP doesn't have Ruby's $' (dollar apostrophe) so we have to capture
442 # $after in the following regular expression. Note that we only use a
443 # look-ahead capture here and don't append $after when we return.
444
445 /**
446 * Get valid mentions or lists matcher
447 *
448 * @staticvar string $regexp
449 * @return string
450 */
451 public static function getValidMentionsOrListsMatcher()
452 {
453 static $regexp = null;
454
455 if ($regexp === null) {
456 $mentionPrecedingChars = '([^a-z0-9_!#\$%&*@@\/]|^|(?:^|[^a-z0-9_+~.-])RT:?)';
457 $regexp = '/' . $mentionPrecedingChars
458 . '([' . static::$atSigns . '])([a-z0-9_]{1,20})(\/[a-z][a-z0-9_\-]{0,24})?(?=(.*|$))/iu';
459 }
460
461 return $regexp;
462 }
463
464 /**
465 * Get valid hashtag matcher
466 *
467 * @staticvar string $regexp
468 * @return string
469 */
470 public static function getValidReplyMatcher()
471 {
472 static $regexp = null;
473
474 if ($regexp === null) {
475 $regexp = '/^(?:[' . static::$spaces . static::$directionalCharacters . '])*[' . static::$atSigns . ']([a-z0-9_]{1,20})(?=(.*|$))/iu';
476 }
477
478 return $regexp;
479 }
480
481 /**
482 * Get end of hashtag matcher
483 *
484 * @staticvar string $regexp
485 * @return string
486 */
487 public static function getEndMentionMatcher()
488 {
489 static $regexp = null;
490
491 if ($regexp === null) {
492 $regexp = '/\A(?:[' . static::$atSigns . ']|[' . static::$latinAccents . ']|:\/\/)/iu';
493 }
494
495 return $regexp;
496 }
497
498 // =================================================================================================================
499
500 /**
501 * Get hashtag matcher
502 *
503 * @return string matcher
504 */
505 private static function getHashtagPattern()
506 {
507 $hashtag_letters = '\p{L}\p{M}';
508 $hashtag_numerals = '\p{Nd}';
509 # Hashtag special chars
510 #
511 # _ underscore
512 # 0x200c ZERO WIDTH NON-JOINER (ZWNJ)
513 # 0x200d ZERO WIDTH JOINER (ZWJ)
514 # 0xa67e CYRILLIC KAVYKA
515 # 0x05be HEBREW PUNCTUATION MAQAF
516 # 0x05f3 HEBREW PUNCTUATION GERESH
517 # 0x05f4 HEBREW PUNCTUATION GERSHAYIM
518 # 0xff5e FULLWIDTH TILDE
519 # 0x301c WAVE DASH
520 # 0x309b KATAKANA-HIRAGANA VOICED SOUND MARK
521 # 0x309c KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
522 # 0x30a0 KATAKANA-HIRAGANA DOUBLE HYPHEN
523 # 0x30fb KATAKANA MIDDLE DOT
524 # 0x3003 DITTO MARK
525 # 0x0f0b TIBETAN MARK INTERSYLLABIC TSHEG
526 # 0x0f0c TIBETAN MARK DELIMITER TSHEG BSTAR
527 # 0x00b7 MIDDLE DOT
528 $hashtag_special_chars = '_\x{200c}\x{200d}\x{a67e}\x{05be}\x{05f3}\x{05f4}'
529 . '\x{ff5e}\x{301c}\x{309b}\x{309c}\x{30a0}\x{30fb}\x{3003}\x{0f0b}\x{0f0c}\x{00b7}';
530 $hashtag_letters_numerals_set = '[' . $hashtag_letters . $hashtag_numerals . $hashtag_special_chars . ']';
531 $hashtag_letters_set = '[' . $hashtag_letters . ']';
532 $hashtag_boundary = '(?:\A|\x{fe0e}|\x{fe0f}|[^&'
533 . $hashtag_letters . $hashtag_numerals . $hashtag_special_chars . '])';
534
535 return '(' . $hashtag_boundary . ')(#|\x{ff03})(?!\x{fe0f}|\x{20e3})('
536 . $hashtag_letters_numerals_set . '*' . $hashtag_letters_set . $hashtag_letters_numerals_set . '*)';
537 }
538
539 /**
540 * Get valid hashtag matcher
541 *
542 * @staticvar string $regexp
543 * @return string
544 */
545 public static function getValidHashtagMatcher()
546 {
547 static $regexp = null;
548
549 if ($regexp === null) {
550 $regexp = '/' . static::getHashtagPattern() . '(?=(.*|$))/iu';
551 }
552
553 return $regexp;
554 }
555
556 /**
557 * Get end of hashtag matcher
558 *
559 * @staticvar string $regexp
560 * @return string
561 */
562 public static function getEndHashtagMatcher()
563 {
564 static $regexp = null;
565
566 if ($regexp === null) {
567 $regexp = '/\A(?:[' . static::$hashSigns . ']|:\/\/)/u';
568 }
569
570 return $regexp;
571 }
572
573 // =================================================================================================================
574
575 /**
576 * Get valid cachtag matcher
577 *
578 * @staticvar string $regexp
579 * @return string
580 */
581 public static function getValidCashtagMatcher()
582 {
583 static $regexp = null;
584
585 if ($regexp === null) {
586 $regexp = '/(^|[' . static::$spaces . static::$directionalCharacters . '])([' . static::$cashSigns . '])'
587 . '(' . static::$cashtag . ')(?=($|\s|[[:punct:]]))/iu';
588 }
589
590 return $regexp;
591 }
592
593 /**
594 * Get end of cachtag matcher
595 *
596 * @staticvar string $regexp
597 * @return string
598 */
599 public static function getEndCashtagMatcher()
600 {
601 static $regexp = null;
602
603 if ($regexp === null) {
604 $regexp = '/\A(?:[' . static::$cashSigns . ']|:\/\/)/u';
605 }
606
607 return $regexp;
608 }
609
610 // =================================================================================================================
611
612 /**
613 * Get url matcher
614 *
615 * @staticvar string $regexp
616 * @return string
617 */
618 public static function getValidateUrlUnencodedMatcher()
619 {
620 static $regexp = null;
621
622 if ($regexp === null) {
623 # Modified version of RFC 3986 Appendix B
624 $regexp = '/\A' # Full URL
625 . '(?:'
626 . '([^:\/?#]+):\/\/' # $1 Scheme
627 . ')?'
628 . '([^\/?#]*)' # $2 Authority
629 . '([^?#]*)' # $3 Path
630 . '(?:'
631 . '\?([^#]*)' # $4 Query
632 . ')?'
633 . '(?:'
634 . '\#(.*)' # $5 Fragment
635 . ')?\z/iux';
636 }
637
638 return $regexp;
639 }
640
641 /**
642 * Get valid url ip
643 *
644 * @return string matcher
645 */
646 private static function getValidateUrlIp()
647 {
648 return '(?:' . static::$validateUrlIpv4 . '|' . static::$validateUrlIpv6 . ')'; #/iox
649 }
650
651 /**
652 * Get valid url domain
653 *
654 * @return string matcher
655 */
656 private static function getValidateUrlDomain()
657 {
658 $subdomain = '(?:[a-z0-9](?:[a-z0-9_\-]*[a-z0-9])?)'; #/i
659 $domain = '(?:[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?)'; #/i
660 $tld = '(?:[a-z](?:[a-z0-9\-]*[a-z0-9])?)'; #/i
661
662 return '(?:(?:' . $subdomain . '\.)*(?:' . $domain . '\.)' . $tld . ')'; #/iox
663 }
664
665 /**
666 * Get valid url host
667 *
668 * @return string matcher
669 */
670 private static function getValidateUrlHost()
671 {
672 return '(?:' . static::getValidateUrlIp() . '|' . static::getValidateUrlDomain() . ')'; #/iox
673 }
674
675 /**
676 * Get valid url unicode domain
677 *
678 * @return string matcher
679 */
680 private static function getValidateUrlUnicodeDomain()
681 {
682 $subdomain = '(?:(?:[a-z0-9]|[^\x00-\x7f])(?:(?:[a-z0-9_\-]|[^\x00-\x7f])*(?:[a-z0-9]|[^\x00-\x7f]))?)'; #/ix
683 $domain = '(?:(?:[a-z0-9]|[^\x00-\x7f])(?:(?:[a-z0-9\-]|[^\x00-\x7f])*(?:[a-z0-9]|[^\x00-\x7f]))?)'; #/ix
684 $tld = '(?:(?:[a-z]|[^\x00-\x7f])(?:(?:[a-z0-9\-]|[^\x00-\x7f])*(?:[a-z0-9]|[^\x00-\x7f]))?)'; #/ix
685
686 return '(?:(?:' . $subdomain . '\.)*(?:' . $domain . '\.)' . $tld . ')'; #/iox
687 }
688
689 /**
690 * Get valid url unicode host
691 *
692 * @return string matcher
693 */
694 private static function getValidateUrlUnicodeHost()
695 {
696 return '(?:' . static::getValidateUrlIp() . '|' . static::getValidateUrlUnicodeDomain() . ')'; #/iox
697 }
698
699 /**
700 * Get valid url userinfo
701 *
702 * @return string matcher
703 */
704 private static function getValidateUrlUserinfo()
705 {
706 return '(?:' . static::$validateUrlUnreserved
707 . '|' . static::$validateUrlPctEncoded
708 . '|' . static::$validateUrlSubDelims
709 . '|:)*'; #/iox
710 }
711
712 /**
713 * Get url unicode authority matcher
714 *
715 * Unencoded internationalized domains - this doesn't check for invalid UTF-8 sequences
716 *
717 * @staticvar string $regexp
718 * @return string
719 */
720 public static function getValidateUrlUnicodeAuthorityMatcher()
721 {
722 static $regexp = null;
723
724 if ($regexp === null) {
725 $regexp = '/'
726 . '(?:(' . static::getValidateUrlUserinfo() . ')@)?' # $1 userinfo
727 . '(' . static::getValidateUrlUnicodeHost() . ')' # $2 host
728 . '(?::(' . static::$validateUrlPort . '))?' # $3 port
729 . '/iux';
730 }
731
732 return $regexp;
733 }
734
735 /**
736 * Get url authority matcher
737 *
738 * This is more strict than the rfc specifies
739 *
740 * @staticvar string $regexp
741 * @return string
742 */
743 public static function getValidateUrlAuthorityMatcher()
744 {
745 static $regexp = null;
746
747 if ($regexp === null) {
748 $regexp = '/'
749 . '(?:(' . static::getValidateUrlUserinfo() . ')@)?' # $1 userinfo
750 . '(' . static::getValidateUrlHost() . ')' # $2 host
751 . '(?::(' . static::$validateUrlPort . '))?' # $3 port
752 . '/ix';
753 }
754
755 return $regexp;
756 }
757
758 /**
759 * Get url scheme matcher
760 *
761 * @staticvar string $regexp
762 * @return string
763 */
764 public static function getValidateUrlSchemeMatcher()
765 {
766 static $regexp = null;
767
768 if ($regexp === null) {
769 $regexp = '/(?:[a-z][a-z0-9+\-.]*)/i';
770 }
771
772 return $regexp;
773 }
774
775 /**
776 * Get valid url charactors
777 *
778 * @return string matcher
779 */
780 private static function getValidateUrlPchar()
781 {
782 return '(?:' . static::$validateUrlUnreserved
783 . '|' . static::$validateUrlPctEncoded
784 . '|' . static::$validateUrlSubDelims
785 . '|[:\|@])'; #/iox
786 }
787
788 /**
789 * Get url path matcher
790 *
791 * @staticvar string $regexp
792 * @return string
793 */
794 public static function getValidateUrlPathMatcher()
795 {
796 static $regexp = null;
797
798 if ($regexp === null) {
799 $regexp = '/(\/' . static::getValidateUrlPchar() . '*)*/iu';
800 }
801
802 return $regexp;
803 }
804
805 /**
806 * Get url query matcher
807 *
808 * @staticvar string $regexp
809 * @return string
810 */
811 public static function getValidateUrlQueryMatcher()
812 {
813 static $regexp = null;
814
815 if ($regexp === null) {
816 $regexp = '/(' . static::getValidateUrlPchar() . '|\/|\?)*/iu';
817 }
818
819 return $regexp;
820 }
821
822 /**
823 * Get url flagment matcher
824 *
825 * @staticvar string $regexp
826 * @return string
827 */
828 public static function getValidateUrlFragmentMatcher()
829 {
830 static $regexp = null;
831
832 if ($regexp === null) {
833 $regexp = '/(' . static::getValidateUrlPchar() . '|\/|\?)*/iu';
834 }
835
836 return $regexp;
837 }
838 }
839