106
104
// Converts bbcode to proper HTML
105
// If $export is true, don't use BOINC CSS
108
function bb2html($text) {
107
function bb2html($text, $export=false) {
109
108
$urlregex = "(?:\"?)(?:(http\:\/\/)?)([^\[\"<\ ]+)(?:\"?)";
110
109
$httpsregex = "(?:\"?)https\:\/\/([^\[\"<\ ]+)(?:\"?)";
111
110
// List of allowable tags
112
111
$bbtags = array (
112
"@\[pre\](.*?)\[/pre\]@eis",
113
"@\[code\](.*?)\[/code\]@eis",
113
114
"@\[b\](.*?)\[/b\]@is",
114
115
"@\[i\](.*?)\[/i\]@is",
115
116
"@\[u\](.*?)\[/u\]@is",
116
"@\[url=$httpsregex\](.*?)\[/url\]@i",
117
"@\[url\]$httpsregex\[/url\]@i",
118
"@\[link=$urlregex\](.*?)\[/link\]@i",
119
"@\[link\]$urlregex\[/link\]@i",
120
"@\[url=$urlregex\](.*?)\[/url\]@i",
121
"@\[url\]$urlregex\[/url\]@i",
117
"@\[url=$httpsregex\](.*?)\[/url\]@is",
118
"@\[url\]$httpsregex\[/url\]@is",
119
"@\[link=$urlregex\](.*?)\[/link\]@is",
120
"@\[link\]$urlregex\[/link\]@is",
121
"@\[url=$urlregex\](.*?)\[/url\]@is",
122
"@\[url\]$urlregex\[/url\]@is",
122
123
"@\[quote=(.*?)\](.*?)\[/quote\]@is",
123
124
"@\[quote\](.*?)\[/quote\]@is",
124
125
"@\[list\](.*?)\[/list\]@is",
125
126
"@\[list=1\](.*?)\[/list\]@is",
126
"@\[pre\](.*?)\[/pre\]@is",
127
127
"@\[img\]$urlregex\[/img\]@is",
128
128
"@\[color=(?:\"?)(.{3,8})(?:\"?)\](.*?)\[/color\]@is",
129
129
"@((?:<ol>|<ul>).*?)\n\*([^\n]+)\n(.*?(</ol>|</ul>))@is",
130
130
"@\[size=([1-9]|[0-2][0-9])\](.*?)\[/size\]@is",
131
"@\[code\](.*?)\[/code\]@is",
132
131
"@\[mailto\](.*?)\[/mailto\]@is",
133
132
"@\[email\](.*?)\[/email\]@is",
134
133
"@\[trac\](?:\#|ticket:)(\d+)\[/trac\]@is",
142
141
// What the above tags are turned in to
147
"<a href=\"https://\\1\" rel=\"nofollow\">\\2</a>",
148
"<a href=\"https://\\1\" rel=\"nofollow\">https://\\1</a>",
149
"<a href=\"http://\\2\" rel=\"nofollow\">\\3</a>",
150
"<a href=\"http://\\2\" rel=\"nofollow\">http://\\2</a>",
151
"<a href=\"http://\\2\" rel=\"nofollow\">\\3</a>",
152
"<a href=\"http://\\2\" rel=\"nofollow\">http://\\2</a>",
153
"<div style='font-style: oblique'>\\1 wrote:</div><blockquote class='postbody'>\\2</blockquote>",
154
"<blockquote class='postbody'>\\1</blockquote>",
158
"<img src=\"http://\\2\">",
159
"<font color=\"\\1\">\\2</font>",
161
"<span style=\"font-size: \\1px;\">\\2</span>",
162
"<div class=\"code\">\\1</div>",
163
"<a href=\"mailto:\\1\">\\1</a>",
164
"<a href=\"mailto:\\1\">\\1</a>",
165
"<a href=\"http://boinc.berkeley.edu/trac/ticket/\\1\">#\\1</a>",
166
"<a href=\"http://boinc.berkeley.edu/trac/wiki/\\1\">\\1</a>",
167
"<a href=\"http://boinc.berkeley.edu/trac/changeset/\\1\">[\\1]</a>"
144
"'<pre>'.stop_recursion(remove_br('\\1')).'</pre>'",
145
"'<code>'.stop_recursion('\\1').'</code>'",
149
"<a href=\"https://\\1\" rel=\"nofollow\">\\2</a>",
150
"<a href=\"https://\\1\" rel=\"nofollow\">https://\\1</a>",
151
"<a href=\"http://\\2\" rel=\"nofollow\">\\3</a>",
152
"<a href=\"http://\\2\" rel=\"nofollow\">http://\\2</a>",
153
"<a href=\"http://\\2\" rel=\"nofollow\">\\3</a>",
154
"<a href=\"http://\\2\" rel=\"nofollow\">http://\\2</a>",
155
"<i>\\1 wrote:</i><blockquote>\\2</blockquote>",
156
"<blockquote>\\1</blockquote>",
159
"<img hspace=\"8\" src=\"http://\\2\">",
160
"<font color=\"\\1\">\\2</font>",
162
"<span style=\"font-size: \\1px;\">\\2</span>",
163
"<a href=\"mailto:\\1\">\\1</a>",
164
"<a href=\"mailto:\\1\">\\1</a>",
165
"<a href=\"http://boinc.berkeley.edu/trac/ticket/\\1\">#\\1</a>",
166
"<a href=\"http://boinc.berkeley.edu/trac/wiki/\\1\">\\1</a>",
167
"<a href=\"http://boinc.berkeley.edu/trac/changeset/\\1\">[\\1]</a>"
171
"'<div class=\"pre\">'.stop_recursion(remove_br('\\1')).'</div>'",
172
"'<div class=\"code\">'.stop_recursion('\\1').'</div>'",
176
"<a href=\"https://\\1\" rel=\"nofollow\">\\2</a>",
177
"<a href=\"https://\\1\" rel=\"nofollow\">https://\\1</a>",
178
"<a href=\"http://\\2\" rel=\"nofollow\">\\3</a>",
179
"<a href=\"http://\\2\" rel=\"nofollow\">http://\\2</a>",
180
"<a href=\"http://\\2\" rel=\"nofollow\">\\3</a>",
181
"<a href=\"http://\\2\" rel=\"nofollow\">http://\\2</a>",
182
"<div style='font-style: oblique'>\\1 wrote:</div><blockquote class='postbody'>\\2</blockquote>",
183
"<blockquote class='postbody'>\\1</blockquote>",
186
"<img hspace=\"8\" src=\"http://\\2\">",
187
"<font color=\"\\1\">\\2</font>",
189
"<span style=\"font-size: \\1px;\">\\2</span>",
190
"<a href=\"mailto:\\1\">\\1</a>",
191
"<a href=\"mailto:\\1\">\\1</a>",
192
"<a href=\"http://boinc.berkeley.edu/trac/ticket/\\1\">#\\1</a>",
193
"<a href=\"http://boinc.berkeley.edu/trac/wiki/\\1\">\\1</a>",
194
"<a href=\"http://boinc.berkeley.edu/trac/changeset/\\1\">[\\1]</a>"
170
198
// Do the actual replacing - iterations for nested items
173
// $i<20 to prevent DoS
174
while ($text != $lasttext && $i<20) {
201
// $i<1000 to prevent DoS
202
while ($text != $lasttext && $i<1000) {
175
203
$lasttext = $text;
176
204
$text = preg_replace($bbtags,$htmltags,$text);
210
// Removes any <br> tags added by nl2br which are not wanted,
211
// for example inside <pre> containers
212
// The original \n was retained after the br when it was added
214
function remove_br($text){
215
return str_replace("<br />", "", $text);
219
// Stops recursion of BBCode by escaping any [ in the given text
220
// @param $text The text to stop recursion in
221
// @return A text that no longer can cause recursion
223
function stop_recursion($text){
224
return str_replace("[", "[", $text);
182
227
// Make links open in new windows.
184
228
function externalize_links($text) {
185
229
// TODO: Convert this to PCRE
186
230
$i=0;$linkpos=true;
199
243
function image_as_link($text){
200
244
/* This function depends on sanitized HTML */
201
245
// Build some regex (should be a *lot* faster)
202
$pattern = '@<img src=([^>]+)>@si'; // Gives us the URL in ${1}...
203
$replacement = '<a href=${1}>[Image Link]</a>'; // Turns that URL into a hyperlink
246
$pattern = '@<img([\S\s]+?)src=([^>]+?)>@si';
247
$replacement = '<a href=${2}>[Image link]</a>'; // Turns that URL into a hyperlink
204
248
$text = preg_replace($pattern, $replacement, $text);
208
// Closes open HTML tags. Not quite perfect...
210
function closeTags($str = null) {
211
// Function from http://episteme.arstechnica.com/eve/ubb.x/a/tpc/f/6330927813/m/139006252731/r/287008552731#287008552731
212
// (thanks Ageless for finding it)
213
// Edited by Rob to better fit in with boinc's needs
215
// List of tags to check $str for
216
// TODO: Adapt to use the pre-existing array of tags above
217
$tags = array('b', 'i', 'a', 'p', 'font[^>]?', 'strong', 'ul', 'li', 'pre', 'blockquote', 'u');
218
// Note on $tags - no br or img, as they have no closing tags - can we define this above?
219
// Maybe define two arrays, those with closing tags and those without, and combine the
220
// two of them for the standard HTML sanitizing function?
222
// Don't do anything if the string is too short
223
if (strlen($str) < 3) {
226
// Loop over $str and count the opening and closing for each tag in $tags
227
foreach ($tags as $tag) {
229
$o = preg_match_all("/<(".$tag.")>/", $str, $m);
230
$c = substr_count($str, "</{$tag}>");
232
$open[$tag] = ($o < $c) ? $c - $o : 0;
233
$close[$tag] = ($c < $o) ? $o - $c : 0;
236
//echo "<pre>Tag: {$tag}\nOpen: {$o}\nClose: {$c}\nOT: {$open[$tag]}\nCT: {$close[$tag]}</pre><hr />";
239
// Prepend the return string with an opening tag as needed
240
/* $pre = ''; ...uhh... doesn't work right
242
foreach ($open as $tag => $cnt) {
243
$pre .= ($cnt > 0) ? "<{$tag}>" : '';
246
// Append the return string with a closing tag as needed
249
foreach ($close as $tag => $cnt) {
250
$post .= ($cnt > 0) ? "</{$tag}>" : '';
253
return /*$pre.*/$str.$post;
258
252
// Highlight terms in text (most likely used with searches)
260
254
function highlight_terms($text, $terms) {