Namespaces

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

Classes

  • FileTemplate
  • Helpers
  • Template

Interfaces

  • IFileTemplate
  • ITemplate

Exceptions

  • FilterException
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Templating;
  9: 
 10: use Nette;
 11: use Nette\Utils\Strings;
 12: use Nette\Forms\Form;
 13: use Nette\Utils\Html;
 14: 
 15: 
 16: /**
 17:  * Template helpers.
 18:  *
 19:  * @author     David Grudl
 20:  */
 21: class Helpers
 22: {
 23:     private static $helpers = array(
 24:         'normalize' => 'Nette\Utils\Strings::normalize',
 25:         'toascii' => 'Nette\Utils\Strings::toAscii',
 26:         'webalize' => 'Nette\Utils\Strings::webalize',
 27:         'truncate' => 'Nette\Utils\Strings::truncate',
 28:         'lower' => 'Nette\Utils\Strings::lower',
 29:         'upper' => 'Nette\Utils\Strings::upper',
 30:         'firstupper' => 'Nette\Utils\Strings::firstUpper',
 31:         'capitalize' => 'Nette\Utils\Strings::capitalize',
 32:         'trim' => 'Nette\Utils\Strings::trim',
 33:         'padleft' => 'Nette\Utils\Strings::padLeft',
 34:         'padright' => 'Nette\Utils\Strings::padRight',
 35:         'reverse' =>  'Nette\Utils\Strings::reverse',
 36:         'replacere' => 'Nette\Utils\Strings::replace',
 37:         'url' => 'rawurlencode',
 38:         'escapeurl' => 'rawurlencode',
 39:         'striptags' => 'strip_tags',
 40:         'substr' => 'Nette\Utils\Strings::substring',
 41:         'repeat' => 'str_repeat',
 42:         'implode' => 'implode',
 43:         'number' => 'number_format',
 44:     );
 45: 
 46:     /** @var string default date format */
 47:     public static $dateFormat = '%x';
 48: 
 49: 
 50:     /**
 51:      * Try to load the requested helper.
 52:      * @param  string  helper name
 53:      * @return callable
 54:      */
 55:     public static function loader($helper)
 56:     {
 57:         if (method_exists(__CLASS__, $helper)) {
 58:             return array(__CLASS__, $helper);
 59:         } elseif (isset(self::$helpers[$helper])) {
 60:             return self::$helpers[$helper];
 61:         }
 62:     }
 63: 
 64: 
 65:     /**
 66:      * Escapes string for use inside HTML template.
 67:      * @param  mixed  UTF-8 encoding
 68:      * @param  int    optional attribute quotes
 69:      * @return string
 70:      */
 71:     public static function escapeHtml($s, $quotes = ENT_QUOTES)
 72:     {
 73:         if ($quotes === ENT_NOQUOTES && ($s instanceof ITemplate || $s instanceof Html || $s instanceof Form)) {
 74:             return $s->__toString(TRUE);
 75:         }
 76:         $s = (string) $s;
 77:         if ($quotes !== ENT_NOQUOTES && strpos($s, '`') !== FALSE && strpbrk($s, ' <>"\'') === FALSE) {
 78:             $s .= ' ';
 79:         }
 80:         return htmlSpecialChars($s, $quotes, 'UTF-8');
 81:     }
 82: 
 83: 
 84:     /**
 85:      * Escapes string for use inside HTML comments.
 86:      * @param  string  UTF-8 encoding
 87:      * @return string
 88:      */
 89:     public static function escapeHtmlComment($s)
 90:     {
 91:         $s = (string) $s;
 92:         if ($s && ($s[0] === '-' || $s[0] === '>' || $s[0] === '!')) {
 93:             $s = ' ' . $s;
 94:         }
 95:         $s = str_replace('--', '- - ', $s);
 96:         if (substr($s, -1) === '-') {
 97:             $s .= ' ';
 98:         }
 99:         return $s;
100:     }
101: 
102: 
103:     /**
104:      * Escapes string for use inside XML 1.0 template.
105:      * @param  string UTF-8 encoding
106:      * @return string
107:      */
108:     public static function escapeXML($s)
109:     {
110:         // XML 1.0: \x09 \x0A \x0D and C1 allowed directly, C0 forbidden
111:         // XML 1.1: \x00 forbidden directly and as a character reference,
112:         //   \x09 \x0A \x0D \x85 allowed directly, C0, C1 and \x7F allowed as character references
113:         return htmlSpecialChars(preg_replace('#[\x00-\x08\x0B\x0C\x0E-\x1F]+#', '', $s), ENT_QUOTES, 'UTF-8');
114:     }
115: 
116: 
117:     /**
118:      * Escapes string for use inside CSS template.
119:      * @param  string UTF-8 encoding
120:      * @return string
121:      */
122:     public static function escapeCss($s)
123:     {
124:         // http://www.w3.org/TR/2006/WD-CSS21-20060411/syndata.html#q6
125:         return addcslashes($s, "\x00..\x1F!\"#$%&'()*+,./:;<=>?@[\\]^`{|}~");
126:     }
127: 
128: 
129:     /**
130:      * Escapes variables for use inside <script>.
131:      * @param  mixed  UTF-8 encoding
132:      * @return string
133:      */
134:     public static function escapeJs($s)
135:     {
136:         if (is_object($s) && ($s instanceof ITemplate || $s instanceof Html || $s instanceof Form)) {
137:             $s = $s->__toString(TRUE);
138:         }
139:         return str_replace(array(']]>', '<!'), array(']]\x3E', '\x3C!'), Nette\Utils\Json::encode($s));
140:     }
141: 
142: 
143:     /**
144:      * Escapes string for use inside iCal template.
145:      * @param  mixed  UTF-8 encoding
146:      * @return string
147:      */
148:     public static function escapeICal($s)
149:     {
150:         // http://www.ietf.org/rfc/rfc5545.txt
151:         return addcslashes(preg_replace('#[\x00-\x08\x0B\x0C-\x1F]+#', '', $s), "\";\\,:\n");
152:     }
153: 
154: 
155:     /**
156:      * Sanitizes string for use inside href attribute.
157:      * @param  string
158:      * @return string
159:      */
160:     public static function safeUrl($s)
161:     {
162:         return preg_match('~^(?:(?:https?|ftp)://[^@]+(?:/.*)?|mailto:.+|[/?#].*|[^:]+)\z~i', $s) ? $s : '';
163:     }
164: 
165: 
166:     /**
167:      * Replaces all repeated white spaces with a single space.
168:      * @param  string UTF-8 encoding or 8-bit
169:      * @return string
170:      */
171:     public static function strip($s)
172:     {
173:         return Strings::replace(
174:             $s,
175:             '#(</textarea|</pre|</script|^).*?(?=<textarea|<pre|<script|\z)#si',
176:             function ($m) {
177:                 return trim(preg_replace('#[ \t\r\n]+#', " ", $m[0]));
178:             });
179:     }
180: 
181: 
182:     /**
183:      * Indents the HTML content from the left.
184:      * @param  string UTF-8 encoding or 8-bit
185:      * @param  int
186:      * @param  string
187:      * @return string
188:      */
189:     public static function indent($s, $level = 1, $chars = "\t")
190:     {
191:         if ($level >= 1) {
192:             $s = Strings::replace($s, '#<(textarea|pre).*?</\\1#si', function ($m) {
193:                 return strtr($m[0], " \t\r\n", "\x1F\x1E\x1D\x1A");
194:             });
195:             $s = Strings::indent($s, $level, $chars);
196:             $s = strtr($s, "\x1F\x1E\x1D\x1A", " \t\r\n");
197:         }
198:         return $s;
199:     }
200: 
201: 
202:     /**
203:      * Date/time formatting.
204:      * @param  string|int|DateTime|DateInterval
205:      * @param  string
206:      * @return string
207:      */
208:     public static function date($time, $format = NULL)
209:     {
210:         if ($time == NULL) { // intentionally ==
211:             return NULL;
212:         }
213: 
214:         if (!isset($format)) {
215:             $format = self::$dateFormat;
216:         }
217: 
218:         if ($time instanceof \DateInterval) {
219:             return $time->format($format);
220:         }
221: 
222:         $time = Nette\DateTime::from($time);
223:         return Strings::contains($format, '%')
224:             ? strftime($format, $time->format('U')) // formats according to locales
225:             : $time->format($format); // formats using date()
226:     }
227: 
228: 
229:     /**
230:      * Date/time modification.
231:      * @param  string|int|DateTime
232:      * @param  string|int
233:      * @param  string
234:      * @return Nette\DateTime
235:      */
236:     public static function modifyDate($time, $delta, $unit = NULL)
237:     {
238:         return $time == NULL // intentionally ==
239:             ? NULL
240:             : Nette\DateTime::from($time)->modify($delta . $unit);
241:     }
242: 
243: 
244:     /**
245:      * Converts to human readable file size.
246:      * @param  int
247:      * @param  int
248:      * @return string
249:      */
250:     public static function bytes($bytes, $precision = 2)
251:     {
252:         $bytes = round($bytes);
253:         $units = array('B', 'kB', 'MB', 'GB', 'TB', 'PB');
254:         foreach ($units as $unit) {
255:             if (abs($bytes) < 1024 || $unit === end($units)) {
256:                 break;
257:             }
258:             $bytes = $bytes / 1024;
259:         }
260:         return round($bytes, $precision) . ' ' . $unit;
261:     }
262: 
263: 
264:     /**
265:      * Returns array of string length.
266:      * @param  mixed
267:      * @return int
268:      */
269:     public static function length($var)
270:     {
271:         return is_string($var) ? Strings::length($var) : count($var);
272:     }
273: 
274: 
275:     /**
276:      * Performs a search and replace.
277:      * @param  string
278:      * @param  string
279:      * @param  string
280:      * @return string
281:      */
282:     public static function replace($subject, $search, $replacement = '')
283:     {
284:         return str_replace($search, $replacement, $subject);
285:     }
286: 
287: 
288:     /**
289:      * The data: URI generator.
290:      * @param  string
291:      * @param  string
292:      * @return string
293:      */
294:     public static function dataStream($data, $type = NULL)
295:     {
296:         if ($type === NULL) {
297:             $type = Nette\Utils\MimeTypeDetector::fromString($data);
298:         }
299:         return 'data:' . ($type ? "$type;" : '') . 'base64,' . base64_encode($data);
300:     }
301: 
302: 
303:     /**
304:      * /dev/null.
305:      * @param  mixed
306:      * @return string
307:      */
308:     public static function null()
309:     {
310:         return '';
311:     }
312: 
313: 
314:     /**
315:      * @param  string
316:      * @return string
317:      */
318:     public static function nl2br($value)
319:     {
320:         return nl2br($value, Html::$xhtml);
321:     }
322: 
323: 
324:     /********************* Template tools ****************d*g**/
325: 
326: 
327:     /**
328:      * Removes unnecessary blocks of PHP code.
329:      * @param  string
330:      * @return string
331:      */
332:     public static function optimizePhp($source, $lineLength = 80, $existenceOfThisParameterSolvesDamnBugInPHP535 = NULL)
333:     {
334:         $res = $php = '';
335:         $lastChar = ';';
336:         $tokens = new \ArrayIterator(token_get_all($source));
337:         foreach ($tokens as $key => $token) {
338:             if (is_array($token)) {
339:                 if ($token[0] === T_INLINE_HTML) {
340:                     $lastChar = '';
341:                     $res .= $token[1];
342: 
343:                 } elseif ($token[0] === T_CLOSE_TAG) {
344:                     $next = isset($tokens[$key + 1]) ? $tokens[$key + 1] : NULL;
345:                     if (substr($res, -1) !== '<' && preg_match('#^<\?php\s*\z#', $php)) {
346:                         $php = ''; // removes empty (?php ?), but retains ((?php ?)?php
347: 
348:                     } elseif (is_array($next) && $next[0] === T_OPEN_TAG) { // remove ?)(?php
349:                         if (!strspn($lastChar, ';{}:/')) {
350:                             $php .= $lastChar = ';';
351:                         }
352:                         if (substr($next[1], -1) === "\n") {
353:                             $php .= "\n";
354:                         }
355:                         $tokens->next();
356: 
357:                     } elseif ($next) {
358:                         $res .= preg_replace('#;?(\s)*\z#', '$1', $php) . $token[1]; // remove last semicolon before ?)
359:                         if (strlen($res) - strrpos($res, "\n") > $lineLength
360:                             && (!is_array($next) || strpos($next[1], "\n") === FALSE)
361:                         ) {
362:                             $res .= "\n";
363:                         }
364:                         $php = '';
365: 
366:                     } else { // remove last ?)
367:                         if (!strspn($lastChar, '};')) {
368:                             $php .= ';';
369:                         }
370:                     }
371: 
372:                 } elseif ($token[0] === T_ELSE || $token[0] === T_ELSEIF) {
373:                     if ($tokens[$key + 1] === ':' && $lastChar === '}') {
374:                         $php .= ';'; // semicolon needed in if(): ... if() ... else:
375:                     }
376:                     $lastChar = '';
377:                     $php .= $token[1];
378: 
379:                 } else {
380:                     if (!in_array($token[0], array(T_WHITESPACE, T_COMMENT, T_DOC_COMMENT, T_OPEN_TAG), TRUE)) {
381:                         $lastChar = '';
382:                     }
383:                     $php .= $token[1];
384:                 }
385:             } else {
386:                 $php .= $lastChar = $token;
387:             }
388:         }
389:         return $res . $php;
390:     }
391: 
392: }
393: 
Nette 2.1 API documentation generated by ApiGen 2.8.0