1 | <?php |
||
2 | // This file is part of BOINC. |
||
3 | // http://boinc.berkeley.edu |
||
4 | // Copyright (C) 2008 University of California |
||
5 | // |
||
6 | // BOINC is free software; you can redistribute it and/or modify it |
||
7 | // under the terms of the GNU Lesser General Public License |
||
8 | // as published by the Free Software Foundation, |
||
9 | // either version 3 of the License, or (at your option) any later version. |
||
10 | // |
||
11 | // BOINC is distributed in the hope that it will be useful, |
||
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
||
14 | // See the GNU Lesser General Public License for more details. |
||
15 | // |
||
16 | // You should have received a copy of the GNU Lesser General Public License |
||
17 | // along with BOINC. If not, see <http://www.gnu.org/licenses/>. |
||
18 | |||
19 | // Functions that process user-supplied text (e.g. messages) |
||
20 | // prior to displaying it to users. |
||
21 | // Goals: |
||
22 | // - Security (don't send evil javascript) |
||
23 | // - obey user preferences |
||
24 | // - improve formatting (e.g., convert newlines to <br> tags) |
||
25 | |||
26 | require_once('../inc/sanitize_html.inc'); |
||
27 | |||
28 | class output_options { |
||
29 | var $bb2html; // BBCode as HTML? (on) |
||
30 | var $images_as_links; // Images as hyperlinks? (off) |
||
31 | var $link_popup; // Links in new windows? (off) |
||
32 | var $nl2br; // Convert newlines to <br>'s? (on) |
||
33 | var $htmlitems; // Convert special chars to HTML entities? (on) |
||
34 | var $htmlscrub; // Scrub "bad" HTML tags? (off) |
||
35 | var $highlight_terms;// Array of terms to be highlighted (off) |
||
36 | |||
37 | // Constructor - set the defaults. |
||
38 | |||
39 | function __construct() { |
||
40 | $this->bb2html = 1; |
||
41 | $this->images_as_links = 0; |
||
42 | $this->link_popup = 0; |
||
43 | $this->nl2br = 1; |
||
44 | $this->htmlitems = 1; |
||
45 | $this->htmlscrub = 0; |
||
46 | $this->highlight_terms = 0; |
||
47 | return true; |
||
48 | } |
||
49 | |||
50 | // Define the terms to be highlighted (for use with searches and such) |
||
51 | |||
52 | function setHighlightTerms($terms) { |
||
53 | if (is_array($terms)) { |
||
54 | $this->highlight_terms = $terms; |
||
55 | } else { |
||
56 | return false; |
||
57 | } |
||
58 | return true; |
||
59 | } |
||
60 | } |
||
61 | |||
62 | // Do the actual transformation of the text. |
||
63 | // TODO: Make this part of the above class. |
||
64 | |||
65 | function output_transform($text, $options = NULL) { |
||
66 | // Options is a output_options object, defined above |
||
67 | if (!$options) { |
||
68 | $options = new output_options; // Defaults in the class definition |
||
69 | } |
||
70 | if ($options->htmlitems) { |
||
71 | $text = htmlspecialchars($text, ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE); |
||
72 | } |
||
73 | if (is_array($options->highlight_terms)) { |
||
74 | $text = highlight_terms($text, $options->highlight_terms); |
||
75 | } |
||
76 | // if ($options->htmlscrub) { |
||
77 | // $text = sanitize_html($text); |
||
78 | // } |
||
79 | if ($options->nl2br) { |
||
80 | $text = nl2br($text); |
||
81 | } |
||
82 | if ($options->bb2html) { |
||
83 | $text = bb2html($text); |
||
84 | } |
||
85 | if ($options->images_as_links) { |
||
86 | $text = image_as_link($text); |
||
87 | } |
||
88 | if ($options->link_popup) { |
||
89 | $text = externalize_links($text); |
||
90 | } |
||
91 | return $text; |
||
92 | } |
||
93 | |||
94 | function get_output_options($user) { |
||
95 | $options = new output_options(); |
||
96 | if ($user) { |
||
97 | if ($user->prefs->images_as_links) $options->images_as_links = 1; |
||
98 | if ($user->prefs->link_popup) $options->link_popup = 1; |
||
99 | } |
||
100 | return $options; |
||
101 | } |
||
102 | |||
103 | // Converts bbcode to HTML |
||
104 | // If $export is true, don't use BOINC CSS |
||
105 | |||
106 | // handle [pre] and [code] separately because we need to remove <br />s |
||
107 | // |
||
108 | function replace_pre_code($text, $export) { |
||
109 | if ($export) { |
||
110 | $text = preg_replace_callback( |
||
111 | "@\[pre\](.*?)\[/pre\]@is", |
||
112 | function ($matches) { |
||
113 | $x = remove_br(substr($matches[0], 5, -6)); |
||
114 | $x = htmlspecialchars($x, ENT_COMPAT, "UTF-8", false); |
||
115 | $x = str_replace("[", "[", $x); |
||
116 | return "<pre>$x</pre>"; |
||
117 | }, |
||
118 | $text |
||
119 | ); |
||
120 | return preg_replace_callback( |
||
121 | "@\[code\](.*?)\[/code\]@is", |
||
122 | function ($matches) { |
||
123 | $x = remove_br(substr($matches[0], 6, -7)); |
||
124 | $x = htmlspecialchars($x, ENT_COMPAT, "UTF-8", false); |
||
125 | $x = str_replace("[", "[", $x); |
||
126 | return "<code>$x</code>"; |
||
127 | }, |
||
128 | $text |
||
129 | ); |
||
130 | } else { |
||
131 | $text = preg_replace_callback( |
||
132 | "@\[pre\](.*?)\[/pre\]@is", |
||
133 | function ($matches) { |
||
134 | $x = remove_br(substr($matches[0], 5, -6)); |
||
135 | $x = htmlspecialchars($x, ENT_COMPAT, "UTF-8", false); |
||
136 | $x = str_replace("[", "[", $x); |
||
137 | return "<pre style=\"white-space:pre-wrap; \">$x</pre>"; |
||
138 | }, |
||
139 | $text |
||
140 | ); |
||
141 | return preg_replace_callback( |
||
142 | "@\[code\](.*?)\[/code\]@is", |
||
143 | function ($matches) { |
||
144 | $x = remove_br(substr($matches[0], 6, -7)); |
||
145 | $x = htmlspecialchars($x, ENT_COMPAT, "UTF-8", false); |
||
146 | $x = str_replace("[", "[", $x); |
||
147 | return "<pre style=\"white-space:pre-wrap; \">$x</pre>"; |
||
148 | }, |
||
149 | $text |
||
150 | ); |
||
151 | } |
||
152 | } |
||
153 | |||
154 | function bb2html($text, $export=false) { |
||
155 | $urlregex = "(?:\"?)(?:(http\:\/\/)?)([^\[\"<\ ]+)(?:\"?)"; |
||
156 | // NOTE: |
||
157 | // This matches https:// too; I don't understand why. |
||
158 | // sample results: |
||
159 | // Array |
||
160 | // ( |
||
161 | // [0] => [img]https://a.b.c[/img] |
||
162 | // [1] => |
||
163 | // [2] => https://a.b.c |
||
164 | // ) |
||
165 | // Array |
||
166 | // ( |
||
167 | // [0] => [img]http://a.b.c[/img] |
||
168 | // [1] => http:// |
||
169 | // [2] => a.b.c |
||
170 | // ) |
||
171 | |||
172 | $httpsregex = "(?:\"?)https\:\/\/([^\[\"<\ ]+)(?:\"?)"; |
||
173 | // List of allowable tags |
||
174 | $bbtags = array ( |
||
0 ignored issues
–
show
Coding Style
introduced
by
Loading history...
|
|||
175 | "@\[b\](.*?)\[/b\]@is", |
||
176 | "@\[i\](.*?)\[/i\]@is", |
||
177 | "@\[u\](.*?)\[/u\]@is", |
||
178 | "@\[s\](.*?)\[/s\]@is", |
||
179 | "@\[sup\](.*?)\[/sup\]@is", |
||
180 | "@\[url=$httpsregex\](.*?)\[/url\]@is", |
||
181 | "@\[url\]$httpsregex\[/url\]@is", |
||
182 | "@\[link=$urlregex\](.*?)\[/link\]@is", |
||
183 | "@\[link\]$urlregex\[/link\]@is", |
||
184 | "@\[url=$urlregex\](.*?)\[/url\]@is", |
||
185 | "@\[url\]$urlregex\[/url\]@is", |
||
186 | "@\[quote=(.*?)\](.*?)\[/quote\]@is", |
||
187 | "@\[quote\](.*?)\[/quote\]@is", |
||
188 | "@\[list\](.*?)\[/list\]@is", |
||
189 | "@\[list=1\](.*?)\[/list\]@is", |
||
190 | "@\[img\]$urlregex\[/img\]@is", |
||
191 | "@\[sm_img\]$urlregex\[/sm_img\]@is", |
||
192 | "@\[color=(?:\"?)(.{3,8})(?:\"?)\](.*?)\[/color\]@is", |
||
193 | "@((?:<ol>|<ul>).*?)\n\*([^\n]+)\n(.*?(</ol>|</ul>))@is", |
||
194 | "@\[size=([1-9]|[0-2][0-9])\](.*?)\[/size\]@is", |
||
195 | "@\[mailto\](.*?)\[/mailto\]@is", |
||
196 | "@\[email\](.*?)\[/email\]@is", |
||
197 | "@\[github\](?:\#|ticket:)(\d+)\[/github\]@is", |
||
198 | "@\[github\]wiki:(.*?)\[/github\]@is", |
||
199 | ); |
||
200 | |||
201 | // What the above tags are turned in to |
||
202 | if ($export) { |
||
203 | $htmltags = array ( |
||
204 | "<b>\\1</b>", |
||
205 | "<i>\\1</i>", |
||
206 | "<u>\\1</u>", |
||
207 | "<s>\\1</s>", |
||
208 | "<sup>\\1</sup>", |
||
209 | "<a href=\"https://\\1\" rel=\"nofollow\">\\2</a>", |
||
210 | "<a href=\"https://\\1\" rel=\"nofollow\">https://\\1</a>", |
||
211 | "<a href=\"http://\\2\" rel=\"nofollow\">\\3</a>", |
||
212 | "<a href=\"http://\\2\" rel=\"nofollow\">http://\\2</a>", |
||
213 | "<a href=\"http://\\2\" rel=\"nofollow\">\\3</a>", |
||
214 | "<a href=\"http://\\2\" rel=\"nofollow\">http://\\2</a>", |
||
215 | "<i>\\1 wrote:</i><blockquote>\\2</blockquote>", |
||
216 | "<blockquote>\\1</blockquote>", |
||
217 | "<ul>\\1</ul><p>", |
||
218 | "<ol>\\1</ol><p>", |
||
219 | "<img hspace=\"8\" src=\"\\1\\2\"> ", |
||
220 | "<img hspace=\"8\" width=400 src=\"\\1\\2\"> ", |
||
221 | "<font color=\"\\1\">\\2</font>", |
||
222 | "\\1<li>\\2\n\\3", |
||
223 | "<span style=\"font-size: \\1px;\">\\2</span>", |
||
224 | "<a href=\"mailto:\\1\">\\1</a>", |
||
225 | "<a href=\"mailto:\\1\">\\1</a>", |
||
226 | "<a href=\"https://github.com/BOINC/boinc/issues/\\1\">#\\1</a>", |
||
227 | "<a href=\"https://github.com/BOINC/boinc/wiki/\\1\">\\1</a>", |
||
228 | ); |
||
229 | } else { |
||
230 | $htmltags = array ( |
||
231 | "<b>\\1</b>", |
||
232 | "<i>\\1</i>", |
||
233 | "<u>\\1</u>", |
||
234 | "<s>\\1</s>", |
||
235 | "<sup>\\1</sup>", |
||
236 | "<a href=\"https://\\1\" rel=\"nofollow\">\\2</a>", |
||
237 | "<a href=\"https://\\1\" rel=\"nofollow\">https://\\1</a>", |
||
238 | "<a href=\"http://\\2\" rel=\"nofollow\">\\3</a>", |
||
239 | "<a href=\"http://\\2\" rel=\"nofollow\">http://\\2</a>", |
||
240 | "<a href=\"http://\\2\" rel=\"nofollow\">\\3</a>", |
||
241 | "<a href=\"http://\\2\" rel=\"nofollow\">http://\\2</a>", |
||
242 | "<em>\\1 wrote:</em><blockquote>\\2</blockquote>", |
||
243 | "<blockquote>\\1</blockquote>", |
||
244 | "<ul>\\1</ul><p>", |
||
245 | "<ol>\\1</ol><p>", |
||
246 | "<img hspace=\"8\" class=\"img-responsive\" src=\"\\1\\2\"> ", |
||
247 | "<img hspace=\"8\" width=400 src=\"\\1\\2\"> ", |
||
248 | "<font color=\"\\1\">\\2</font>", |
||
249 | "\\1<li>\\2\n\\3", |
||
250 | "<span style=\"font-size: \\1px;\">\\2</span>", |
||
251 | "<a href=\"mailto:\\1\">\\1</a>", |
||
252 | "<a href=\"mailto:\\1\">\\1</a>", |
||
253 | "<a href=\"https://github.com/BOINC/boinc/issues/\\1\">#\\1</a>", |
||
254 | "<a href=\"https://github.com/BOINC/boinc/wiki/\\1\">\\1</a>", |
||
255 | ); |
||
256 | } |
||
257 | |||
258 | // Do the actual replacing - iterations for nested items |
||
259 | $lasttext = ""; |
||
260 | $i = 0; |
||
261 | // $i<1000 to prevent DoS |
||
262 | while ($text != $lasttext && $i<1000) { |
||
263 | $lasttext = $text; |
||
264 | $text = replace_pre_code($text, $export); |
||
265 | $text = preg_replace($bbtags, $htmltags, $text); |
||
266 | $i = $i + 1; |
||
0 ignored issues
–
show
|
|||
267 | } |
||
268 | $text = str_replace("<ul>", '<ul style="word-break:break-word;">', $text); |
||
269 | $text = str_replace("<ol>", '<ol style="word-break:break-word;">', $text); |
||
270 | return $text; |
||
271 | } |
||
272 | |||
273 | // Removes any <br> tags added by nl2br which are not wanted, |
||
274 | // for example inside <pre> containers |
||
275 | // The original \n was retained after the br when it was added |
||
276 | // |
||
277 | function remove_br($text){ |
||
278 | return str_replace("<br />", "", $text); |
||
279 | } |
||
280 | |||
281 | // Make links open in new windows. |
||
282 | // |
||
283 | function externalize_links($text) { |
||
284 | // TODO: Convert this to PCRE |
||
285 | $i=0; |
||
286 | $linkpos=true; |
||
287 | $out = ""; |
||
288 | while (true){ |
||
289 | //Find a link |
||
290 | // |
||
291 | $linkpos=strpos($text, "<a ", $i); |
||
292 | if ($linkpos===false) break; |
||
293 | |||
294 | //Replace with target='_new' |
||
295 | // |
||
296 | $out .= substr($text, $i, $linkpos-$i)."<a target=\"_new\" "; |
||
297 | $i = $linkpos+3; |
||
298 | } |
||
299 | $out .= substr($text, $i); |
||
300 | return $out; |
||
301 | } |
||
302 | |||
303 | // Converts image tags to links to the images. |
||
304 | |||
305 | function image_as_link($text){ |
||
306 | /* This function depends on sanitized HTML */ |
||
307 | // Build some regex (should be a *lot* faster) |
||
308 | $pattern = '@<img([\S\s]+?)src=([^>]+?)>@si'; |
||
309 | $replacement = '<a href=${2}>[Image link]</a>'; // Turns that URL into a hyperlink |
||
310 | $text = preg_replace($pattern, $replacement, $text); |
||
311 | return $text; |
||
312 | } |
||
313 | |||
314 | // Highlight terms in text (most likely used with searches) |
||
315 | |||
316 | function highlight_terms($text, $terms) { |
||
317 | $search = $terms; |
||
318 | $replace = array(); |
||
319 | |||
320 | foreach ($search as $key => $value) { |
||
321 | $replace[$key] = "<span class=\"mark\">".$value."</span>"; |
||
322 | } |
||
323 | if (substr(phpversion(), 0, 1) > 4) { // PHP 4.x doesn't support str_ireplace |
||
324 | return str_ireplace($search, $replace, $text); |
||
325 | } else { |
||
326 | return str_replace($search, $replace, $text); |
||
327 | } |
||
328 | } |
||
329 | |||
330 | $cvs_version_tracker[]="\$Id$"; //Generated automatically - do not edit |
||
331 | ?> |
||
332 |