]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - extlib/HTMLPurifier/HTMLPurifier/Generator.php
Merge branch 'testing' of gitorious.org:statusnet/mainline into 0.9.x
[quix0rs-gnu-social.git] / extlib / HTMLPurifier / HTMLPurifier / Generator.php
1 <?php
2
3 /**
4  * Generates HTML from tokens.
5  * @todo Refactor interface so that configuration/context is determined
6  *       upon instantiation, no need for messy generateFromTokens() calls
7  * @todo Make some of the more internal functions protected, and have
8  *       unit tests work around that
9  */
10 class HTMLPurifier_Generator
11 {
12
13     /**
14      * Whether or not generator should produce XML output
15      */
16     private $_xhtml = true;
17
18     /**
19      * :HACK: Whether or not generator should comment the insides of <script> tags
20      */
21     private $_scriptFix = false;
22
23     /**
24      * Cache of HTMLDefinition during HTML output to determine whether or
25      * not attributes should be minimized.
26      */
27     private $_def;
28
29     /**
30      * Cache of %Output.SortAttr
31      */
32     private $_sortAttr;
33
34     /**
35      * Configuration for the generator
36      */
37     protected $config;
38
39     /**
40      * @param $config Instance of HTMLPurifier_Config
41      * @param $context Instance of HTMLPurifier_Context
42      */
43     public function __construct($config, $context) {
44         $this->config = $config;
45         $this->_scriptFix = $config->get('Output.CommentScriptContents');
46         $this->_sortAttr = $config->get('Output.SortAttr');
47         $this->_def = $config->getHTMLDefinition();
48         $this->_xhtml = $this->_def->doctype->xml;
49     }
50
51     /**
52      * Generates HTML from an array of tokens.
53      * @param $tokens Array of HTMLPurifier_Token
54      * @param $config HTMLPurifier_Config object
55      * @return Generated HTML
56      */
57     public function generateFromTokens($tokens) {
58         if (!$tokens) return '';
59
60         // Basic algorithm
61         $html = '';
62         for ($i = 0, $size = count($tokens); $i < $size; $i++) {
63             if ($this->_scriptFix && $tokens[$i]->name === 'script'
64                 && $i + 2 < $size && $tokens[$i+2] instanceof HTMLPurifier_Token_End) {
65                 // script special case
66                 // the contents of the script block must be ONE token
67                 // for this to work.
68                 $html .= $this->generateFromToken($tokens[$i++]);
69                 $html .= $this->generateScriptFromToken($tokens[$i++]);
70             }
71             $html .= $this->generateFromToken($tokens[$i]);
72         }
73
74         // Tidy cleanup
75         if (extension_loaded('tidy') && $this->config->get('Output.TidyFormat')) {
76             $tidy = new Tidy;
77             $tidy->parseString($html, array(
78                'indent'=> true,
79                'output-xhtml' => $this->_xhtml,
80                'show-body-only' => true,
81                'indent-spaces' => 2,
82                'wrap' => 68,
83             ), 'utf8');
84             $tidy->cleanRepair();
85             $html = (string) $tidy; // explicit cast necessary
86         }
87
88         // Normalize newlines to system defined value
89         $nl = $this->config->get('Output.Newline');
90         if ($nl === null) $nl = PHP_EOL;
91         if ($nl !== "\n") $html = str_replace("\n", $nl, $html);
92         return $html;
93     }
94
95     /**
96      * Generates HTML from a single token.
97      * @param $token HTMLPurifier_Token object.
98      * @return Generated HTML
99      */
100     public function generateFromToken($token) {
101         if (!$token instanceof HTMLPurifier_Token) {
102             trigger_error('Cannot generate HTML from non-HTMLPurifier_Token object', E_USER_WARNING);
103             return '';
104
105         } elseif ($token instanceof HTMLPurifier_Token_Start) {
106             $attr = $this->generateAttributes($token->attr, $token->name);
107             return '<' . $token->name . ($attr ? ' ' : '') . $attr . '>';
108
109         } elseif ($token instanceof HTMLPurifier_Token_End) {
110             return '</' . $token->name . '>';
111
112         } elseif ($token instanceof HTMLPurifier_Token_Empty) {
113             $attr = $this->generateAttributes($token->attr, $token->name);
114              return '<' . $token->name . ($attr ? ' ' : '') . $attr .
115                 ( $this->_xhtml ? ' /': '' ) // <br /> v. <br>
116                 . '>';
117
118         } elseif ($token instanceof HTMLPurifier_Token_Text) {
119             return $this->escape($token->data, ENT_NOQUOTES);
120
121         } elseif ($token instanceof HTMLPurifier_Token_Comment) {
122             return '<!--' . $token->data . '-->';
123         } else {
124             return '';
125
126         }
127     }
128
129     /**
130      * Special case processor for the contents of script tags
131      * @warning This runs into problems if there's already a literal
132      *          --> somewhere inside the script contents.
133      */
134     public function generateScriptFromToken($token) {
135         if (!$token instanceof HTMLPurifier_Token_Text) return $this->generateFromToken($token);
136         // Thanks <http://lachy.id.au/log/2005/05/script-comments>
137         $data = preg_replace('#//\s*$#', '', $token->data);
138         return '<!--//--><![CDATA[//><!--' . "\n" . trim($data) . "\n" . '//--><!]]>';
139     }
140
141     /**
142      * Generates attribute declarations from attribute array.
143      * @note This does not include the leading or trailing space.
144      * @param $assoc_array_of_attributes Attribute array
145      * @param $element Name of element attributes are for, used to check
146      *        attribute minimization.
147      * @return Generate HTML fragment for insertion.
148      */
149     public function generateAttributes($assoc_array_of_attributes, $element = false) {
150         $html = '';
151         if ($this->_sortAttr) ksort($assoc_array_of_attributes);
152         foreach ($assoc_array_of_attributes as $key => $value) {
153             if (!$this->_xhtml) {
154                 // Remove namespaced attributes
155                 if (strpos($key, ':') !== false) continue;
156                 // Check if we should minimize the attribute: val="val" -> val
157                 if ($element && !empty($this->_def->info[$element]->attr[$key]->minimized)) {
158                     $html .= $key . ' ';
159                     continue;
160                 }
161             }
162             $html .= $key.'="'.$this->escape($value).'" ';
163         }
164         return rtrim($html);
165     }
166
167     /**
168      * Escapes raw text data.
169      * @todo This really ought to be protected, but until we have a facility
170      *       for properly generating HTML here w/o using tokens, it stays
171      *       public.
172      * @param $string String data to escape for HTML.
173      * @param $quote Quoting style, like htmlspecialchars. ENT_NOQUOTES is
174      *               permissible for non-attribute output.
175      * @return String escaped data.
176      */
177     public function escape($string, $quote = ENT_COMPAT) {
178         return htmlspecialchars($string, $quote, 'UTF-8');
179     }
180
181 }
182
183 // vim: et sw=4 sts=4