1: <?php
2: /**
3: * Smarty plugin
4: *
5: * @package Smarty
6: * @subpackage PluginsFilter
7: */
8: /**
9: * Smarty trimwhitespace outputfilter plugin
10: * Trim unnecessary whitespace from HTML markup.
11: *
12: * @author Rodney Rehm
13: *
14: * @param string $source input string
15: *
16: * @return string filtered output
17: * @todo substr_replace() is not overloaded by mbstring.func_overload - so this function might fail!
18: */
19: function smarty_outputfilter_trimwhitespace($source)
20: {
21: $store = array();
22: $_store = 0;
23: $_offset = 0;
24: // Unify Line-Breaks to \n
25: $source = preg_replace('/\015\012|\015|\012/', "\n", $source);
26: // capture Internet Explorer and KnockoutJS Conditional Comments
27: if (preg_match_all(
28: '#<!--((\[[^\]]+\]>.*?<!\[[^\]]+\])|(\s*/?ko\s+.+))-->#is',
29: $source,
30: $matches,
31: PREG_OFFSET_CAPTURE | PREG_SET_ORDER
32: )
33: ) {
34: foreach ($matches as $match) {
35: $store[] = $match[ 0 ][ 0 ];
36: $_length = strlen($match[ 0 ][ 0 ]);
37: $replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
38: $source = substr_replace($source, $replace, $match[ 0 ][ 1 ] - $_offset, $_length);
39: $_offset += $_length - strlen($replace);
40: $_store++;
41: }
42: }
43: // Strip all HTML-Comments
44: // yes, even the ones in <script> - see http://stackoverflow.com/a/808850/515124
45: $source = preg_replace('#<!--.*?-->#ms', '', $source);
46: // capture html elements not to be messed with
47: $_offset = 0;
48: if (preg_match_all(
49: '#(<script[^>]*>.*?</script[^>]*>)|(<textarea[^>]*>.*?</textarea[^>]*>)|(<pre[^>]*>.*?</pre[^>]*>)#is',
50: $source,
51: $matches,
52: PREG_OFFSET_CAPTURE | PREG_SET_ORDER
53: )
54: ) {
55: foreach ($matches as $match) {
56: $store[] = $match[ 0 ][ 0 ];
57: $_length = strlen($match[ 0 ][ 0 ]);
58: $replace = '@!@SMARTY:' . $_store . ':SMARTY@!@';
59: $source = substr_replace($source, $replace, $match[ 0 ][ 1 ] - $_offset, $_length);
60: $_offset += $_length - strlen($replace);
61: $_store++;
62: }
63: }
64: $expressions = array(// replace multiple spaces between tags by a single space
65: // can't remove them entirely, becaue that might break poorly implemented CSS display:inline-block elements
66: '#(:SMARTY@!@|>)\s+(?=@!@SMARTY:|<)#s' => '\1 \2',
67: // remove spaces between attributes (but not in attribute values!)
68: '#(([a-z0-9]\s*=\s*("[^"]*?")|(\'[^\']*?\'))|<[a-z0-9_]+)\s+([a-z/>])#is' => '\1 \5',
69: // note: for some very weird reason trim() seems to remove spaces inside attributes.
70: // maybe a \0 byte or something is interfering?
71: '#^\s+<#Ss' => '<',
72: '#>\s+$#Ss' => '>',
73: );
74: $source = preg_replace(array_keys($expressions), array_values($expressions), $source);
75: // note: for some very weird reason trim() seems to remove spaces inside attributes.
76: // maybe a \0 byte or something is interfering?
77: // $source = trim( $source );
78: $_offset = 0;
79: if (preg_match_all('#@!@SMARTY:([0-9]+):SMARTY@!@#is', $source, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
80: foreach ($matches as $match) {
81: $_length = strlen($match[ 0 ][ 0 ]);
82: $replace = $store[ $match[ 1 ][ 0 ] ];
83: $source = substr_replace($source, $replace, $match[ 0 ][ 1 ] + $_offset, $_length);
84: $_offset += strlen($replace) - $_length;
85: $_store++;
86: }
87: }
88: return $source;
89: }
90: