Packages

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • None
  • PHP

Classes

  • Arrays
  • Finder
  • Html
  • Json
  • LimitedScope
  • MimeTypeDetector
  • Neon
  • NeonEntity
  • Paginator
  • Strings
  • Tokenizer
  • Validators

Exceptions

  • AssertionException
  • JsonException
  • NeonException
  • RegexpException
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  * @package Nette\Utils
 11:  */
 12: 
 13: 
 14: 
 15: /**
 16:  * String tools library.
 17:  *
 18:  * @author     David Grudl
 19:  * @package Nette\Utils
 20:  */
 21: class Strings
 22: {
 23: 
 24:     /**
 25:      * Static class - cannot be instantiated.
 26:      */
 27:     final public function __construct()
 28:     {
 29:         throw new StaticClassException;
 30:     }
 31: 
 32: 
 33: 
 34:     /**
 35:      * Checks if the string is valid for the specified encoding.
 36:      * @param  string  byte stream to check
 37:      * @param  string  expected encoding
 38:      * @return bool
 39:      */
 40:     public static function checkEncoding($s, $encoding = 'UTF-8')
 41:     {
 42:         return $s === self::fixEncoding($s, $encoding);
 43:     }
 44: 
 45: 
 46: 
 47:     /**
 48:      * Returns correctly encoded string.
 49:      * @param  string  byte stream to fix
 50:      * @param  string  encoding
 51:      * @return string
 52:      */
 53:     public static function fixEncoding($s, $encoding = 'UTF-8')
 54:     {
 55:         // removes xD800-xDFFF, xFEFF, xFFFF, x110000 and higher
 56:         $s = @iconv('UTF-16', $encoding . '//IGNORE', iconv($encoding, 'UTF-16//IGNORE', $s)); // intentionally @
 57:         return str_replace("\xEF\xBB\xBF", '', $s); // remove UTF-8 BOM
 58:     }
 59: 
 60: 
 61: 
 62:     /**
 63:      * Returns a specific character.
 64:      * @param  int     codepoint
 65:      * @param  string  encoding
 66:      * @return string
 67:      */
 68:     public static function chr($code, $encoding = 'UTF-8')
 69:     {
 70:         return iconv('UTF-32BE', $encoding . '//IGNORE', pack('N', $code));
 71:     }
 72: 
 73: 
 74: 
 75:     /**
 76:      * Starts the $haystack string with the prefix $needle?
 77:      * @param  string
 78:      * @param  string
 79:      * @return bool
 80:      */
 81:     public static function startsWith($haystack, $needle)
 82:     {
 83:         return strncmp($haystack, $needle, strlen($needle)) === 0;
 84:     }
 85: 
 86: 
 87: 
 88:     /**
 89:      * Ends the $haystack string with the suffix $needle?
 90:      * @param  string
 91:      * @param  string
 92:      * @return bool
 93:      */
 94:     public static function endsWith($haystack, $needle)
 95:     {
 96:         return strlen($needle) === 0 || substr($haystack, -strlen($needle)) === $needle;
 97:     }
 98: 
 99: 
100: 
101:     /**
102:      * Does $haystack contain $needle?
103:      * @param  string
104:      * @param  string
105:      * @return bool
106:      */
107:     public static function contains($haystack, $needle)
108:     {
109:         return strpos($haystack, $needle) !== FALSE;
110:     }
111: 
112: 
113: 
114:     /**
115:      * Returns a part of UTF-8 string.
116:      * @param  string
117:      * @param  int
118:      * @param  int
119:      * @return string
120:      */
121:     public static function substring($s, $start, $length = NULL)
122:     {
123:         if ($length === NULL) {
124:             $length = self::length($s);
125:         }
126:         return function_exists('mb_substr') ? mb_substr($s, $start, $length, 'UTF-8') : iconv_substr($s, $start, $length, 'UTF-8'); // MB is much faster
127:     }
128: 
129: 
130: 
131:     /**
132:      * Removes special controls characters and normalizes line endings and spaces.
133:      * @param  string  UTF-8 encoding or 8-bit
134:      * @return string
135:      */
136:     public static function normalize($s)
137:     {
138:         // standardize line endings to unix-like
139:         $s = str_replace("\r\n", "\n", $s); // DOS
140:         $s = strtr($s, "\r", "\n"); // Mac
141: 
142:         // remove control characters; leave \t + \n
143:         $s = preg_replace('#[\x00-\x08\x0B-\x1F\x7F]+#', '', $s);
144: 
145:         // right trim
146:         $s = preg_replace("#[\t ]+$#m", '', $s);
147: 
148:         // leading and trailing blank lines
149:         $s = trim($s, "\n");
150: 
151:         return $s;
152:     }
153: 
154: 
155: 
156:     /**
157:      * Converts to ASCII.
158:      * @param  string  UTF-8 encoding
159:      * @return string  ASCII
160:      */
161:     public static function toAscii($s)
162:     {
163:         $s = preg_replace('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u', '', $s);
164:         $s = strtr($s, '`\'"^~', "\x01\x02\x03\x04\x05");
165:         if (ICONV_IMPL === 'glibc') {
166:             $s = @iconv('UTF-8', 'WINDOWS-1250//TRANSLIT', $s); // intentionally @
167:             $s = strtr($s, "\xa5\xa3\xbc\x8c\xa7\x8a\xaa\x8d\x8f\x8e\xaf\xb9\xb3\xbe\x9c\x9a\xba\x9d\x9f\x9e"
168:                 . "\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3"
169:                 . "\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8"
170:                 . "\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf8\xf9\xfa\xfb\xfc\xfd\xfe",
171:                 "ALLSSSSTZZZallssstzzzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTsraaaalccceeeeiiddnnooooruuuuyt");
172:         } else {
173:             $s = @iconv('UTF-8', 'ASCII//TRANSLIT', $s); // intentionally @
174:         }
175:         $s = str_replace(array('`', "'", '"', '^', '~'), '', $s);
176:         return strtr($s, "\x01\x02\x03\x04\x05", '`\'"^~');
177:     }
178: 
179: 
180: 
181:     /**
182:      * Converts to web safe characters [a-z0-9-] text.
183:      * @param  string  UTF-8 encoding
184:      * @param  string  allowed characters
185:      * @param  bool
186:      * @return string
187:      */
188:     public static function webalize($s, $charlist = NULL, $lower = TRUE)
189:     {
190:         $s = self::toAscii($s);
191:         if ($lower) {
192:             $s = strtolower($s);
193:         }
194:         $s = preg_replace('#[^a-z0-9' . preg_quote($charlist, '#') . ']+#i', '-', $s);
195:         $s = trim($s, '-');
196:         return $s;
197:     }
198: 
199: 
200: 
201:     /**
202:      * Truncates string to maximal length.
203:      * @param  string  UTF-8 encoding
204:      * @param  int
205:      * @param  string  UTF-8 encoding
206:      * @return string
207:      */
208:     public static function truncate($s, $maxLen, $append = "\xE2\x80\xA6")
209:     {
210:         if (self::length($s) > $maxLen) {
211:             $maxLen = $maxLen - self::length($append);
212:             if ($maxLen < 1) {
213:                 return $append;
214: 
215:             } elseif ($matches = self::match($s, '#^.{1,'.$maxLen.'}(?=[\s\x00-/:-@\[-`{-~])#us')) {
216:                 return $matches[0] . $append;
217: 
218:             } else {
219:                 return self::substring($s, 0, $maxLen) . $append;
220:             }
221:         }
222:         return $s;
223:     }
224: 
225: 
226: 
227:     /**
228:      * Indents the content from the left.
229:      * @param  string  UTF-8 encoding or 8-bit
230:      * @param  int
231:      * @param  string
232:      * @return string
233:      */
234:     public static function indent($s, $level = 1, $chars = "\t")
235:     {
236:         return $level < 1 ? $s : self::replace($s, '#(?:^|[\r\n]+)(?=[^\r\n])#', '$0' . str_repeat($chars, $level));
237:     }
238: 
239: 
240: 
241:     /**
242:      * Convert to lower case.
243:      * @param  string  UTF-8 encoding
244:      * @return string
245:      */
246:     public static function lower($s)
247:     {
248:         return mb_strtolower($s, 'UTF-8');
249:     }
250: 
251: 
252: 
253:     /**
254:      * Convert to upper case.
255:      * @param  string  UTF-8 encoding
256:      * @return string
257:      */
258:     public static function upper($s)
259:     {
260:         return mb_strtoupper($s, 'UTF-8');
261:     }
262: 
263: 
264: 
265:     /**
266:      * Convert first character to upper case.
267:      * @param  string  UTF-8 encoding
268:      * @return string
269:      */
270:     public static function firstUpper($s)
271:     {
272:         return self::upper(self::substring($s, 0, 1)) . self::substring($s, 1);
273:     }
274: 
275: 
276: 
277:     /**
278:      * Capitalize string.
279:      * @param  string  UTF-8 encoding
280:      * @return string
281:      */
282:     public static function capitalize($s)
283:     {
284:         return mb_convert_case($s, MB_CASE_TITLE, 'UTF-8');
285:     }
286: 
287: 
288: 
289:     /**
290:      * Case-insensitive compares UTF-8 strings.
291:      * @param  string
292:      * @param  string
293:      * @param  int
294:      * @return bool
295:      */
296:     public static function compare($left, $right, $len = NULL)
297:     {
298:         if ($len < 0) {
299:             $left = self::substring($left, $len, -$len);
300:             $right = self::substring($right, $len, -$len);
301:         } elseif ($len !== NULL) {
302:             $left = self::substring($left, 0, $len);
303:             $right = self::substring($right, 0, $len);
304:         }
305:         return self::lower($left) === self::lower($right);
306:     }
307: 
308: 
309: 
310:     /**
311:      * Returns UTF-8 string length.
312:      * @param  string
313:      * @return int
314:      */
315:     public static function length($s)
316:     {
317:         return strlen(utf8_decode($s)); // fastest way
318:     }
319: 
320: 
321: 
322:     /**
323:      * Strips whitespace.
324:      * @param  string  UTF-8 encoding
325:      * @param  string
326:      * @return string
327:      */
328:     public static function trim($s, $charlist = " \t\n\r\0\x0B\xC2\xA0")
329:     {
330:         $charlist = preg_quote($charlist, '#');
331:         return self::replace($s, '#^['.$charlist.']+|['.$charlist.']+$#u', '');
332:     }
333: 
334: 
335: 
336:     /**
337:      * Pad a string to a certain length with another string.
338:      * @param  string  UTF-8 encoding
339:      * @param  int
340:      * @param  string
341:      * @return string
342:      */
343:     public static function padLeft($s, $length, $pad = ' ')
344:     {
345:         $length = max(0, $length - self::length($s));
346:         $padLen = self::length($pad);
347:         return str_repeat($pad, $length / $padLen) . self::substring($pad, 0, $length % $padLen) . $s;
348:     }
349: 
350: 
351: 
352:     /**
353:      * Pad a string to a certain length with another string.
354:      * @param  string  UTF-8 encoding
355:      * @param  int
356:      * @param  string
357:      * @return string
358:      */
359:     public static function padRight($s, $length, $pad = ' ')
360:     {
361:         $length = max(0, $length - self::length($s));
362:         $padLen = self::length($pad);
363:         return $s . str_repeat($pad, $length / $padLen) . self::substring($pad, 0, $length % $padLen);
364:     }
365: 
366: 
367: 
368:     /**
369:      * Reverse string.
370:      * @param  string  UTF-8 encoding
371:      * @return string
372:      */
373:     public static function reverse($s)
374:     {
375:         return @iconv('UTF-32LE', 'UTF-8', strrev(@iconv('UTF-8', 'UTF-32BE', $s)));
376:     }
377: 
378: 
379: 
380:     /**
381:      * Generate random string.
382:      * @param  int
383:      * @param  string
384:      * @return string
385:      */
386:     public static function random($length = 10, $charlist = '0-9a-z')
387:     {
388:         $charlist = str_shuffle(preg_replace_callback('#.-.#', create_function('$m', '
389:             return implode(\'\', range($m[0][0], $m[0][2]));
390:         '), $charlist));
391:         $chLen = strlen($charlist);
392: 
393:         $s = '';
394:         for ($i = 0; $i < $length; $i++) {
395:             if ($i % 5 === 0) {
396:                 $rand = lcg_value();
397:                 $rand2 = microtime(TRUE);
398:             }
399:             $rand *= $chLen;
400:             $s .= $charlist[($rand + $rand2) % $chLen];
401:             $rand -= (int) $rand;
402:         }
403:         return $s;
404:     }
405: 
406: 
407: 
408:     /**
409:      * Splits string by a regular expression.
410:      * @param  string
411:      * @param  string
412:      * @param  int
413:      * @return array
414:      */
415:     public static function split($subject, $pattern, $flags = 0)
416:     {
417:         Debugger::tryError();
418:         $res = preg_split($pattern, $subject, -1, $flags | PREG_SPLIT_DELIM_CAPTURE);
419:         if (Debugger::catchError($e) || preg_last_error()) { // compile error XOR run-time error
420:             throw new RegexpException($e ? $e->getMessage() : NULL, $e ? NULL : preg_last_error(), $pattern);
421:         }
422:         return $res;
423:     }
424: 
425: 
426: 
427:     /**
428:      * Performs a regular expression match.
429:      * @param  string
430:      * @param  string
431:      * @param  int  can be PREG_OFFSET_CAPTURE (returned in bytes)
432:      * @param  int  offset in bytes
433:      * @return mixed
434:      */
435:     public static function match($subject, $pattern, $flags = 0, $offset = 0)
436:     {
437:         if ($offset > strlen($subject)) {
438:             return NULL;
439:         }
440:         Debugger::tryError();
441:         $res = preg_match($pattern, $subject, $m, $flags, $offset);
442:         if (Debugger::catchError($e) || preg_last_error()) { // compile error XOR run-time error
443:             throw new RegexpException($e ? $e->getMessage() : NULL, $e ? NULL : preg_last_error(), $pattern);
444:         }
445:         if ($res) {
446:             return $m;
447:         }
448:     }
449: 
450: 
451: 
452:     /**
453:      * Performs a global regular expression match.
454:      * @param  string
455:      * @param  string
456:      * @param  int  can be PREG_OFFSET_CAPTURE (returned in bytes); PREG_SET_ORDER is default
457:      * @param  int  offset in bytes
458:      * @return array
459:      */
460:     public static function matchAll($subject, $pattern, $flags = 0, $offset = 0)
461:     {
462:         if ($offset > strlen($subject)) {
463:             return array();
464:         }
465:         Debugger::tryError();
466:         $res = preg_match_all(
467:             $pattern, $subject, $m,
468:             ($flags & PREG_PATTERN_ORDER) ? $flags : ($flags | PREG_SET_ORDER),
469:             $offset
470:         );
471:         if (Debugger::catchError($e) || preg_last_error()) { // compile error XOR run-time error
472:             throw new RegexpException($e ? $e->getMessage() : NULL, $e ? NULL : preg_last_error(), $pattern);
473:         }
474:         return $m;
475:     }
476: 
477: 
478: 
479:     /**
480:      * Perform a regular expression search and replace.
481:      * @param  string
482:      * @param  string|array
483:      * @param  string|callable
484:      * @param  int
485:      * @return string
486:      */
487:     public static function replace($subject, $pattern, $replacement = NULL, $limit = -1)
488:     {
489:         if (is_object($replacement) || is_array($replacement)) {
490:             if ($replacement instanceof Callback) {
491:                 $replacement = $replacement->getNative();
492:             }
493:             if (!is_callable($replacement, FALSE, $textual)) {
494:                 throw new InvalidStateException("Callback '$textual' is not callable.");
495:             }
496: 
497:             foreach ((array) $pattern as $tmp) {
498:                 Debugger::tryError();
499:                 preg_match($tmp, '');
500:                 if (Debugger::catchError($e)) { // compile error
501:                     throw new RegexpException($e->getMessage(), NULL, $tmp);
502:                 }
503:             }
504: 
505:             $res = preg_replace_callback($pattern, $replacement, $subject, $limit);
506:             if ($res === NULL && preg_last_error()) { // run-time error
507:                 throw new RegexpException(NULL, preg_last_error(), $pattern);
508:             }
509:             return $res;
510: 
511:         } elseif ($replacement === NULL && is_array($pattern)) {
512:             $replacement = array_values($pattern);
513:             $pattern = array_keys($pattern);
514:         }
515: 
516:         Debugger::tryError();
517:         $res = preg_replace($pattern, $replacement, $subject, $limit);
518:         if (Debugger::catchError($e) || preg_last_error()) { // compile error XOR run-time error
519:             throw new RegexpException($e ? $e->getMessage() : NULL, $e ? NULL : preg_last_error(), $pattern);
520:         }
521:         return $res;
522:     }
523: 
524: }
525: 
526: 
527: 
528: /**
529:  * The exception that indicates error of the last Regexp execution.
530:  * @package Nette\Utils
531:  */
532: class RegexpException extends Exception
533: {
534:     static public $messages = array(
535:                 PREG_INTERNAL_ERROR => 'Internal error',
536:                 PREG_BACKTRACK_LIMIT_ERROR => 'Backtrack limit was exhausted',
537:                 PREG_RECURSION_LIMIT_ERROR => 'Recursion limit was exhausted',
538:                 PREG_BAD_UTF8_ERROR => 'Malformed UTF-8 data',
539:                 5 => 'Offset didn\'t correspond to the begin of a valid UTF-8 code point', // PREG_BAD_UTF8_OFFSET_ERROR
540:             );
541: 
542:     public function __construct($message, $code = NULL, $pattern = NULL)
543:     {
544:         if (!$message) {
545:             $message = (isset(self::$messages[$code]) ? self::$messages[$code] : 'Unknown error') . ($pattern ? " (pattern: $pattern)" : '');
546:         } elseif ($pattern) {
547:             $message .= " in pattern: $pattern";
548:         }
549:         parent::__construct($message, $code);
550:     }
551: 
552: }
553: 
Nette Framework 2.0.3 (for PHP 5.2, un-prefixed) API API documentation generated by ApiGen 2.7.0