Verzeichnisstruktur phpBB-3.0.0
- Veröffentlicht
- 12.12.2007
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
functions_content.php
0001 <?php
0002 /**
0003 *
0004 * @package phpBB3
0005 * @version $Id$
0006 * @copyright (c) 2005 phpBB Group
0007 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
0008 *
0009 */
0010
0011 /**
0012 * @ignore
0013 */
0014 if (!defined('IN_PHPBB'))
0015 {
0016 exit;
0017 }
0018
0019 /**
0020 * gen_sort_selects()
0021 * make_jumpbox()
0022 * bump_topic_allowed()
0023 * get_context()
0024 * decode_message()
0025 * strip_bbcode()
0026 * generate_text_for_display()
0027 * generate_text_for_storage()
0028 * generate_text_for_edit()
0029 * make_clickable_callback()
0030 * make_clickable()
0031 * censor_text()
0032 * bbcode_nl2br()
0033 * smiley_text()
0034 * parse_attachments()
0035 * extension_allowed()
0036 * truncate_string()
0037 * get_username_string()
0038 * class bitfield
0039 */
0040
0041 /**
0042 * Generate sort selection fields
0043 */
0044 function gen_sort_selects(&$limit_days, &$sort_by_text, &$sort_days, &$sort_key, &$sort_dir, &$s_limit_days, &$s_sort_key, &$s_sort_dir, &$u_sort_param)
0045 {
0046 global $user;
0047
0048 $sort_dir_text = array('a' => $user->lang['ASCENDING'], 'd' => $user->lang['DESCENDING']);
0049
0050 // Check if the key is selectable. If not, we reset to the first key found.
0051 // This ensures the values are always valid.
0052 if (!isset($limit_days[$sort_days]))
0053 {
0054 @reset($limit_days);
0055 $sort_days = key($limit_days);
0056 }
0057
0058 if (!isset($sort_by_text[$sort_key]))
0059 {
0060 @reset($sort_by_text);
0061 $sort_key = key($sort_by_text);
0062 }
0063
0064 if (!isset($sort_dir_text[$sort_dir]))
0065 {
0066 @reset($sort_dir_text);
0067 $sort_dir = key($sort_dir_text);
0068 }
0069
0070 $s_limit_days = '<select name="st">';
0071 foreach ($limit_days as $day => $text)
0072 {
0073 $selected = ($sort_days == $day) ? ' selected="selected"' : '';
0074 $s_limit_days .= '<option value="' . $day . '"' . $selected . '>' . $text . '</option>';
0075 }
0076 $s_limit_days .= '</select>';
0077
0078 $s_sort_key = '<select name="sk">';
0079 foreach ($sort_by_text as $key => $text)
0080 {
0081 $selected = ($sort_key == $key) ? ' selected="selected"' : '';
0082 $s_sort_key .= '<option value="' . $key . '"' . $selected . '>' . $text . '</option>';
0083 }
0084 $s_sort_key .= '</select>';
0085
0086 $s_sort_dir = '<select name="sd">';
0087 foreach ($sort_dir_text as $key => $value)
0088 {
0089 $selected = ($sort_dir == $key) ? ' selected="selected"' : '';
0090 $s_sort_dir .= '<option value="' . $key . '"' . $selected . '>' . $value . '</option>';
0091 }
0092 $s_sort_dir .= '</select>';
0093
0094 $u_sort_param = "st=$sort_days&sk=$sort_key&sd=$sort_dir";
0095
0096 return;
0097 }
0098
0099 /**
0100 * Generate Jumpbox
0101 */
0102 function make_jumpbox($action, $forum_id = false, $select_all = false, $acl_list = false, $force_display = false)
0103 {
0104 global $config, $auth, $template, $user, $db;
0105
0106 // We only return if the jumpbox is not forced to be displayed (in case it is needed for functionality)
0107 if (!$config['load_jumpbox'] && $force_display === false)
0108 {
0109 return;
0110 }
0111
0112 $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, left_id, right_id
0113 FROM ' . FORUMS_TABLE . '
0114 ORDER BY left_id ASC';
0115 $result = $db->sql_query($sql, 600);
0116
0117 $right = $padding = 0;
0118 $padding_store = array('0' => 0);
0119 $display_jumpbox = false;
0120 $iteration = 0;
0121
0122 // Sometimes it could happen that forums will be displayed here not be displayed within the index page
0123 // This is the result of forums not displayed at index, having list permissions and a parent of a forum with no permissions.
0124 // If this happens, the padding could be "broken"
0125
0126 while ($row = $db->sql_fetchrow($result))
0127 {
0128 if ($row['left_id'] < $right)
0129 {
0130 $padding++;
0131 $padding_store[$row['parent_id']] = $padding;
0132 }
0133 else if ($row['left_id'] > $right + 1)
0134 {
0135 // Ok, if the $padding_store for this parent is empty there is something wrong. For now we will skip over it.
0136 // @todo digging deep to find out "how" this can happen.
0137 $padding = (isset($padding_store[$row['parent_id']])) ? $padding_store[$row['parent_id']] : $padding;
0138 }
0139
0140 $right = $row['right_id'];
0141
0142 if ($row['forum_type'] == FORUM_CAT && ($row['left_id'] + 1 == $row['right_id']))
0143 {
0144 // Non-postable forum with no subforums, don't display
0145 continue;
0146 }
0147
0148 if (!$auth->acl_get('f_list', $row['forum_id']))
0149 {
0150 // if the user does not have permissions to list this forum skip
0151 continue;
0152 }
0153
0154 if ($acl_list && !$auth->acl_gets($acl_list, $row['forum_id']))
0155 {
0156 continue;
0157 }
0158
0159 if (!$display_jumpbox)
0160 {
0161 $template->assign_block_vars('jumpbox_forums', array(
0162 'FORUM_ID' => ($select_all) ? 0 : -1,
0163 'FORUM_NAME' => ($select_all) ? $user->lang['ALL_FORUMS'] : $user->lang['SELECT_FORUM'],
0164 'S_FORUM_COUNT' => $iteration)
0165 );
0166
0167 $iteration++;
0168 $display_jumpbox = true;
0169 }
0170
0171 $template->assign_block_vars('jumpbox_forums', array(
0172 'FORUM_ID' => $row['forum_id'],
0173 'FORUM_NAME' => $row['forum_name'],
0174 'SELECTED' => ($row['forum_id'] == $forum_id) ? ' selected="selected"' : '',
0175 'S_FORUM_COUNT' => $iteration,
0176 'S_IS_CAT' => ($row['forum_type'] == FORUM_CAT) ? true : false,
0177 'S_IS_LINK' => ($row['forum_type'] == FORUM_LINK) ? true : false,
0178 'S_IS_POST' => ($row['forum_type'] == FORUM_POST) ? true : false)
0179 );
0180
0181 for ($i = 0; $i < $padding; $i++)
0182 {
0183 $template->assign_block_vars('jumpbox_forums.level', array());
0184 }
0185 $iteration++;
0186 }
0187 $db->sql_freeresult($result);
0188 unset($padding_store);
0189
0190 $template->assign_vars(array(
0191 'S_DISPLAY_JUMPBOX' => $display_jumpbox,
0192 'S_JUMPBOX_ACTION' => $action)
0193 );
0194
0195 return;
0196 }
0197
0198 /**
0199 * Bump Topic Check - used by posting and viewtopic
0200 */
0201 function bump_topic_allowed($forum_id, $topic_bumped, $last_post_time, $topic_poster, $last_topic_poster)
0202 {
0203 global $config, $auth, $user;
0204
0205 // Check permission and make sure the last post was not already bumped
0206 if (!$auth->acl_get('f_bump', $forum_id) || $topic_bumped)
0207 {
0208 return false;
0209 }
0210
0211 // Check bump time range, is the user really allowed to bump the topic at this time?
0212 $bump_time = ($config['bump_type'] == 'm') ? $config['bump_interval'] * 60 : (($config['bump_type'] == 'h') ? $config['bump_interval'] * 3600 : $config['bump_interval'] * 86400);
0213
0214 // Check bump time
0215 if ($last_post_time + $bump_time > time())
0216 {
0217 return false;
0218 }
0219
0220 // Check bumper, only topic poster and last poster are allowed to bump
0221 if ($topic_poster != $user->data['user_id'] && $last_topic_poster != $user->data['user_id'])
0222 {
0223 return false;
0224 }
0225
0226 // A bump time of 0 will completely disable the bump feature... not intended but might be useful.
0227 return $bump_time;
0228 }
0229
0230 /**
0231 * Generates a text with approx. the specified length which contains the specified words and their context
0232 *
0233 * @param string $text The full text from which context shall be extracted
0234 * @param string $words An array of words which should be contained in the result, has to be a valid part of a PCRE pattern (escape with preg_quote!)
0235 * @param int $length The desired length of the resulting text, however the result might be shorter or longer than this value
0236 *
0237 * @return string Context of the specified words separated by "..."
0238 */
0239 function get_context($text, $words, $length = 400)
0240 {
0241 // first replace all whitespaces with single spaces
0242 $text = preg_replace('/ +/', ' ', strtr($text, "\t\n\r\x0C ", ' '), $text);
0243
0244 $word_indizes = array();
0245 if (sizeof($words))
0246 {
0247 $match = '';
0248 // find the starting indizes of all words
0249 foreach ($words as $word)
0250 {
0251 if ($word)
0252 {
0253 if (preg_match('#(?:[^\w]|^)(' . $word . ')(?:[^\w]|$)#i', $text, $match))
0254 {
0255 $pos = utf8_strpos($text, $match[1]);
0256 if ($pos !== false)
0257 {
0258 $word_indizes[] = $pos;
0259 }
0260 }
0261 }
0262 }
0263 unset($match);
0264
0265 if (sizeof($word_indizes))
0266 {
0267 $word_indizes = array_unique($word_indizes);
0268 sort($word_indizes);
0269
0270 $wordnum = sizeof($word_indizes);
0271 // number of characters on the right and left side of each word
0272 $sequence_length = (int) ($length / (2 * $wordnum)) - 2;
0273 $final_text = '';
0274 $word = $j = 0;
0275 $final_text_index = -1;
0276
0277 // cycle through every character in the original text
0278 for ($i = $word_indizes[$word], $n = utf8_strlen($text); $i < $n; $i++)
0279 {
0280 // if the current position is the start of one of the words then append $sequence_length characters to the final text
0281 if (isset($word_indizes[$word]) && ($i == $word_indizes[$word]))
0282 {
0283 if ($final_text_index < $i - $sequence_length - 1)
0284 {
0285 $final_text .= '... ' . preg_replace('#^([^ ]*)#', '', utf8_substr($text, $i - $sequence_length, $sequence_length));
0286 }
0287 else
0288 {
0289 // if the final text is already nearer to the current word than $sequence_length we only append the text
0290 // from its current index on and distribute the unused length to all other sequenes
0291 $sequence_length += (int) (($final_text_index - $i + $sequence_length + 1) / (2 * $wordnum));
0292 $final_text .= utf8_substr($text, $final_text_index + 1, $i - $final_text_index - 1);
0293 }
0294 $final_text_index = $i - 1;
0295
0296 // add the following characters to the final text (see below)
0297 $word++;
0298 $j = 1;
0299 }
0300
0301 if ($j > 0)
0302 {
0303 // add the character to the final text and increment the sequence counter
0304 $final_text .= utf8_substr($text, $i, 1);
0305 $final_text_index++;
0306 $j++;
0307
0308 // if this is a whitespace then check whether we are done with this sequence
0309 if (utf8_substr($text, $i, 1) == ' ')
0310 {
0311 // only check whether we have to exit the context generation completely if we haven't already reached the end anyway
0312 if ($i + 4 < $n)
0313 {
0314 if (($j > $sequence_length && $word >= $wordnum) || utf8_strlen($final_text) > $length)
0315 {
0316 $final_text .= ' ...';
0317 break;
0318 }
0319 }
0320 else
0321 {
0322 // make sure the text really reaches the end
0323 $j -= 4;
0324 }
0325
0326 // stop context generation and wait for the next word
0327 if ($j > $sequence_length)
0328 {
0329 $j = 0;
0330 }
0331 }
0332 }
0333 }
0334 return $final_text;
0335 }
0336 }
0337
0338 if (!sizeof($words) || !sizeof($word_indizes))
0339 {
0340 return (utf8_strlen($text) >= $length + 3) ? utf8_substr($text, 0, $length) . '...' : $text;
0341 }
0342 }
0343
0344 /**
0345 * Decode text whereby text is coming from the db and expected to be pre-parsed content
0346 * We are placing this outside of the message parser because we are often in need of it...
0347 */
0348 function decode_message(&$message, $bbcode_uid = '')
0349 {
0350 global $config;
0351
0352 if ($bbcode_uid)
0353 {
0354 $match = array('<br />', "[/*:m:$bbcode_uid]", ":u:$bbcode_uid", ":o:$bbcode_uid", ":$bbcode_uid");
0355 $replace = array("\n", '', '', '', '');
0356 }
0357 else
0358 {
0359 $match = array('<br />');
0360 $replace = array("\n");
0361 }
0362
0363 $message = str_replace($match, $replace, $message);
0364
0365 $match = get_preg_expression('bbcode_htm');
0366 $replace = array('\1', '\1', '\2', '\1', '', '');
0367
0368 $message = preg_replace($match, $replace, $message);
0369 }
0370
0371 /**
0372 * Strips all bbcode from a text and returns the plain content
0373 */
0374 function strip_bbcode(&$text, $uid = '')
0375 {
0376 if (!$uid)
0377 {
0378 $uid = '[0-9a-z]{5,}';
0379 }
0380
0381 $text = preg_replace("#\[\/?[a-z0-9\*\+\-]+(?:=(?:".*"|[^\]]*))?(?::[a-z])?(\:$uid)\]#", ' ', $text);
0382
0383 $match = get_preg_expression('bbcode_htm');
0384 $replace = array('\1', '\1', '\2', '\1', '', '');
0385
0386 $text = preg_replace($match, $replace, $text);
0387 }
0388
0389 /**
0390 * For display of custom parsed text on user-facing pages
0391 * Expects $text to be the value directly from the database (stored value)
0392 */
0393 function generate_text_for_display($text, $uid, $bitfield, $flags)
0394 {
0395 static $bbcode;
0396
0397 if (!$text)
0398 {
0399 return '';
0400 }
0401
0402 $text = censor_text($text);
0403
0404 // Parse bbcode if bbcode uid stored and bbcode enabled
0405 if ($uid && ($flags & OPTION_FLAG_BBCODE))
0406 {
0407 if (!class_exists('bbcode'))
0408 {
0409 global $phpbb_root_path, $phpEx;
0410 include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
0411 }
0412
0413 if (empty($bbcode))
0414 {
0415 $bbcode = new bbcode($bitfield);
0416 }
0417 else
0418 {
0419 $bbcode->bbcode($bitfield);
0420 }
0421
0422 $bbcode->bbcode_second_pass($text, $uid);
0423 }
0424
0425 $text = bbcode_nl2br($text);
0426 $text = smiley_text($text, !($flags & OPTION_FLAG_SMILIES));
0427
0428 return $text;
0429 }
0430
0431 /**
0432 * For parsing custom parsed text to be stored within the database.
0433 * This function additionally returns the uid and bitfield that needs to be stored.
0434 * Expects $text to be the value directly from request_var() and in it's non-parsed form
0435 */
0436 function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bbcode = false, $allow_urls = false, $allow_smilies = false)
0437 {
0438 global $phpbb_root_path, $phpEx;
0439
0440 $uid = $bitfield = '';
0441
0442 if (!$text)
0443 {
0444 return;
0445 }
0446
0447 if (!class_exists('parse_message'))
0448 {
0449 include($phpbb_root_path . 'includes/message_parser.' . $phpEx);
0450 }
0451
0452 $message_parser = new parse_message($text);
0453 $message_parser->parse($allow_bbcode, $allow_urls, $allow_smilies);
0454
0455 $text = $message_parser->message;
0456 $uid = $message_parser->bbcode_uid;
0457
0458 // If the bbcode_bitfield is empty, there is no need for the uid to be stored.
0459 if (!$message_parser->bbcode_bitfield)
0460 {
0461 $uid = '';
0462 }
0463
0464 $flags = (($allow_bbcode) ? OPTION_FLAG_BBCODE : 0) + (($allow_smilies) ? OPTION_FLAG_SMILIES : 0) + (($allow_urls) ? OPTION_FLAG_LINKS : 0);
0465 $bitfield = $message_parser->bbcode_bitfield;
0466
0467 return;
0468 }
0469
0470 /**
0471 * For decoding custom parsed text for edits as well as extracting the flags
0472 * Expects $text to be the value directly from the database (pre-parsed content)
0473 */
0474 function generate_text_for_edit($text, $uid, $flags)
0475 {
0476 global $phpbb_root_path, $phpEx;
0477
0478 decode_message($text, $uid);
0479
0480 return array(
0481 'allow_bbcode' => ($flags & OPTION_FLAG_BBCODE) ? 1 : 0,
0482 'allow_smilies' => ($flags & OPTION_FLAG_SMILIES) ? 1 : 0,
0483 'allow_urls' => ($flags & OPTION_FLAG_LINKS) ? 1 : 0,
0484 'text' => $text
0485 );
0486 }
0487
0488 /**
0489 * A subroutine of make_clickable used with preg_replace
0490 * It places correct HTML around an url, shortens the displayed text
0491 * and makes sure no entities are inside URLs
0492 */
0493 function make_clickable_callback($type, $whitespace, $url, $relative_url, $class)
0494 {
0495 $append = '';
0496 $url = htmlspecialchars_decode($url);
0497 $relative_url = htmlspecialchars_decode($relative_url);
0498
0499 // make sure no HTML entities were matched
0500 $chars = array('<', '>', '"');
0501 $split = false;
0502
0503 foreach ($chars as $char)
0504 {
0505 $next_split = strpos($url, $char);
0506 if ($next_split !== false)
0507 {
0508 $split = ($split !== false) ? min($split, $next_split) : $next_split;
0509 }
0510 }
0511
0512 if ($split !== false)
0513 {
0514 // an HTML entity was found, so the URL has to end before it
0515 $append = substr($url, $split) . $relative_url;
0516 $url = substr($url, 0, $split);
0517 $relative_url = '';
0518 }
0519 else if ($relative_url)
0520 {
0521 // same for $relative_url
0522 $split = false;
0523 foreach ($chars as $char)
0524 {
0525 $next_split = strpos($relative_url, $char);
0526 if ($next_split !== false)
0527 {
0528 $split = ($split !== false) ? min($split, $next_split) : $next_split;
0529 }
0530 }
0531
0532 if ($split !== false)
0533 {
0534 $append = substr($relative_url, $split);
0535 $relative_url = substr($relative_url, 0, $split);
0536 }
0537 }
0538
0539 // if the last character of the url is a punctuation mark, exclude it from the url
0540 $last_char = ($relative_url) ? $relative_url[strlen($relative_url) - 1] : $url[strlen($url) - 1];
0541
0542 switch ($last_char)
0543 {
0544 case '.':
0545 case '?':
0546 case '!':
0547 case ':':
0548 case ',':
0549 $append = $last_char;
0550 if ($relative_url)
0551 {
0552 $relative_url = substr($relative_url, 0, -1);
0553 }
0554 else
0555 {
0556 $url = substr($url, 0, -1);
0557 }
0558 break;
0559 }
0560
0561 switch ($type)
0562 {
0563 case MAGIC_URL_LOCAL:
0564 $tag = 'l';
0565 $relative_url = preg_replace('/[&?]sid=[0-9a-f]{32}$/', '', preg_replace('/([&?])sid=[0-9a-f]{32}&/', '$1', $relative_url));
0566 $url = $url . '/' . $relative_url;
0567 $text = ($relative_url) ? $relative_url : $url;
0568 break;
0569
0570 case MAGIC_URL_FULL:
0571 $tag = 'm';
0572 $text = (strlen($url) > 55) ? substr($url, 0, 39) . ' ... ' . substr($url, -10) : $url;
0573 break;
0574
0575 case MAGIC_URL_WWW:
0576 $tag = 'w';
0577 $url = 'http://' . $url;
0578 $text = (strlen($url) > 55) ? substr($url, 0, 39) . ' ... ' . substr($url, -10) : $url;
0579 break;
0580
0581 case MAGIC_URL_EMAIL:
0582 $tag = 'e';
0583 $text = (strlen($url) > 55) ? substr($url, 0, 39) . ' ... ' . substr($url, -10) : $url;
0584 $url = 'mailto:' . $url;
0585 break;
0586 }
0587
0588 $url = htmlspecialchars($url);
0589 $text = htmlspecialchars($text);
0590 $append = htmlspecialchars($append);
0591
0592 $html = "$whitespace<!-- $tag --><a$class href=\"$url\">$text</a><!-- $tag -->$append";
0593
0594 return $html;
0595 }
0596
0597 /**
0598 * make_clickable function
0599 *
0600 * Replace magic urls of form http://xxx.xxx., www.xxx. and xxx@xxx.xxx.
0601 * Cuts down displayed size of link if over 50 chars, turns absolute links
0602 * into relative versions when the server/script path matches the link
0603 */
0604 function make_clickable($text, $server_url = false, $class = 'postlink')
0605 {
0606 if ($server_url === false)
0607 {
0608 $server_url = generate_board_url();
0609 }
0610
0611 static $magic_url_match;
0612 static $magic_url_replace;
0613 static $static_class;
0614
0615 if (!is_array($magic_url_match) || $static_class != $class)
0616 {
0617 $static_class = $class;
0618 $class = ($static_class) ? ' class="' . $static_class . '"' : '';
0619 $local_class = ($static_class) ? ' class="' . $static_class . '-local"' : '';
0620
0621 $magic_url_match = $magic_url_replace = array();
0622 // Be sure to not let the matches cross over. ;)
0623
0624 // relative urls for this board
0625 $magic_url_match[] = '#(^|[\n\t (>.])(' . preg_quote($server_url, '#') . ')/(' . get_preg_expression('relative_url_inline') . ')#ie';
0626 $magic_url_replace[] = "make_clickable_callback(MAGIC_URL_LOCAL, '\$1', '\$2', '\$3', '$local_class')";
0627
0628 // matches a xxxx://aaaaa.bbb.cccc. ...
0629 $magic_url_match[] = '#(^|[\n\t (>.])(' . get_preg_expression('url_inline') . ')#ie';
0630 $magic_url_replace[] = "make_clickable_callback(MAGIC_URL_FULL, '\$1', '\$2', '', '$class')";
0631
0632 // matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing
0633 $magic_url_match[] = '#(^|[\n\t (>])(' . get_preg_expression('www_url_inline') . ')#ie';
0634 $magic_url_replace[] = "make_clickable_callback(MAGIC_URL_WWW, '\$1', '\$2', '', '$class')";
0635
0636 // matches an email@domain type address at the start of a line, or after a space or after what might be a BBCode.
0637 $magic_url_match[] = '/(^|[\n\t (>])(' . get_preg_expression('email') . ')/ie';
0638 $magic_url_replace[] = "make_clickable_callback(MAGIC_URL_EMAIL, '\$1', '\$2', '', '')";
0639 }
0640
0641 return preg_replace($magic_url_match, $magic_url_replace, $text);
0642 }
0643
0644 /**
0645 * Censoring
0646 */
0647 function censor_text($text)
0648 {
0649 static $censors;
0650 global $cache;
0651
0652 if (!isset($censors) || !is_array($censors))
0653 {
0654 // obtain_word_list is taking care of the users censor option and the board-wide option
0655 $censors = $cache->obtain_word_list();
0656 }
0657
0658 if (sizeof($censors))
0659 {
0660 return preg_replace($censors['match'], $censors['replace'], $text);
0661 }
0662
0663 return $text;
0664 }
0665
0666 /**
0667 * custom version of nl2br which takes custom BBCodes into account
0668 */
0669 function bbcode_nl2br($text)
0670 {
0671 // custom BBCodes might contain carriage returns so they
0672 // are not converted into <br /> so now revert that
0673 $text = str_replace(array("\n", "\r"), array('<br />', "\n"), $text);
0674 return $text;
0675 }
0676
0677 /**
0678 * Smiley processing
0679 */
0680 function smiley_text($text, $force_option = false)
0681 {
0682 global $config, $user, $phpbb_root_path;
0683
0684 if ($force_option || !$config['allow_smilies'] || !$user->optionget('viewsmilies'))
0685 {
0686 return preg_replace('#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/.*? \/><!\-\- s\1 \-\->#', '\1', $text);
0687 }
0688 else
0689 {
0690 return preg_replace('#<!\-\- s(.*?) \-\-><img src="\{SMILIES_PATH\}\/(.*?) \/><!\-\- s\1 \-\->#', '<img src="' . $phpbb_root_path . $config['smilies_path'] . '/\2 />', $text);
0691 }
0692 }
0693
0694 /**
0695 * General attachment parsing
0696 *
0697 * @param mixed $forum_id The forum id the attachments are displayed in (false if in private message)
0698 * @param string &$message The post/private message
0699 * @param array &$attachments The attachments to parse for (inline) display. The attachments array will hold templated data after parsing.
0700 * @param array &$update_count The attachment counts to be updated - will be filled
0701 * @param bool $preview If set to true the attachments are parsed for preview. Within preview mode the comments are fetched from the given $attachments array and not fetched from the database.
0702 */
0703 function parse_attachments($forum_id, &$message, &$attachments, &$update_count, $preview = false)
0704 {
0705 if (!sizeof($attachments))
0706 {
0707 return;
0708 }
0709
0710 global $template, $cache, $user;
0711 global $extensions, $config, $phpbb_root_path, $phpEx;
0712
0713 //
0714 $compiled_attachments = array();
0715
0716 if (!isset($template->filename['attachment_tpl']))
0717 {
0718 $template->set_filenames(array(
0719 'attachment_tpl' => 'attachment.html')
0720 );
0721 }
0722
0723 if (empty($extensions) || !is_array($extensions))
0724 {
0725 $extensions = $cache->obtain_attach_extensions($forum_id);
0726 }
0727
0728 // Look for missing attachment information...
0729 $attach_ids = array();
0730 foreach ($attachments as $pos => $attachment)
0731 {
0732 // If is_orphan is set, we need to retrieve the attachments again...
0733 if (!isset($attachment['extension']) && !isset($attachment['physical_filename']))
0734 {
0735 $attach_ids[(int) $attachment['attach_id']] = $pos;
0736 }
0737 }
0738
0739 // Grab attachments (security precaution)
0740 if (sizeof($attach_ids))
0741 {
0742 global $db;
0743
0744 $new_attachment_data = array();
0745
0746 $sql = 'SELECT *
0747 FROM ' . ATTACHMENTS_TABLE . '
0748 WHERE ' . $db->sql_in_set('attach_id', array_keys($attach_ids));
0749 $result = $db->sql_query($sql);
0750
0751 while ($row = $db->sql_fetchrow($result))
0752 {
0753 if (!isset($attach_ids[$row['attach_id']]))
0754 {
0755 continue;
0756 }
0757
0758 // If we preview attachments we will set some retrieved values here
0759 if ($preview)
0760 {
0761 $row['attach_comment'] = $attachments[$attach_ids[$row['attach_id']]]['attach_comment'];
0762 }
0763
0764 $new_attachment_data[$attach_ids[$row['attach_id']]] = $row;
0765 }
0766 $db->sql_freeresult($result);
0767
0768 $attachments = $new_attachment_data;
0769 unset($new_attachment_data);
0770 }
0771
0772 // Sort correctly
0773 if ($config['display_order'])
0774 {
0775 // Ascending sort
0776 krsort($attachments);
0777 }
0778 else
0779 {
0780 // Descending sort
0781 ksort($attachments);
0782 }
0783
0784 foreach ($attachments as $attachment)
0785 {
0786 if (!sizeof($attachment))
0787 {
0788 continue;
0789 }
0790
0791 // We need to reset/empty the _file block var, because this function might be called more than once
0792 $template->destroy_block_vars('_file');
0793
0794 $block_array = array();
0795
0796 // Some basics...
0797 $attachment['extension'] = strtolower(trim($attachment['extension']));
0798 $filename = $phpbb_root_path . $config['upload_path'] . '/' . basename($attachment['physical_filename']);
0799 $thumbnail_filename = $phpbb_root_path . $config['upload_path'] . '/thumb_' . basename($attachment['physical_filename']);
0800
0801 $upload_icon = '';
0802
0803 if (isset($extensions[$attachment['extension']]))
0804 {
0805 if ($user->img('icon_topic_attach', '') && !$extensions[$attachment['extension']]['upload_icon'])
0806 {
0807 $upload_icon = $user->img('icon_topic_attach', '');
0808 }
0809 else if ($extensions[$attachment['extension']]['upload_icon'])
0810 {
0811 $upload_icon = '<img src="' . $phpbb_root_path . $config['upload_icons_path'] . '/' . trim($extensions[$attachment['extension']]['upload_icon']) . '" alt="" />';
0812 }
0813 }
0814
0815 $filesize = $attachment['filesize'];
0816 $size_lang = ($filesize >= 1048576) ? $user->lang['MB'] : ( ($filesize >= 1024) ? $user->lang['KB'] : $user->lang['BYTES'] );
0817 $filesize = ($filesize >= 1048576) ? round((round($filesize / 1048576 * 100) / 100), 2) : (($filesize >= 1024) ? round((round($filesize / 1024 * 100) / 100), 2) : $filesize);
0818
0819 $comment = bbcode_nl2br(censor_text($attachment['attach_comment']));
0820
0821 $block_array += array(
0822 'UPLOAD_ICON' => $upload_icon,
0823 'FILESIZE' => $filesize,
0824 'SIZE_LANG' => $size_lang,
0825 'DOWNLOAD_NAME' => basename($attachment['real_filename']),
0826 'COMMENT' => $comment,
0827 );
0828
0829 $denied = false;
0830
0831 if (!extension_allowed($forum_id, $attachment['extension'], $extensions))
0832 {
0833 $denied = true;
0834
0835 $block_array += array(
0836 'S_DENIED' => true,
0837 'DENIED_MESSAGE' => sprintf($user->lang['EXTENSION_DISABLED_AFTER_POSTING'], $attachment['extension'])
0838 );
0839 }
0840
0841 if (!$denied)
0842 {
0843 $l_downloaded_viewed = $download_link = '';
0844 $display_cat = $extensions[$attachment['extension']]['display_cat'];
0845
0846 if ($display_cat == ATTACHMENT_CATEGORY_IMAGE)
0847 {
0848 if ($attachment['thumbnail'])
0849 {
0850 $display_cat = ATTACHMENT_CATEGORY_THUMB;
0851 }
0852 else
0853 {
0854 if ($config['img_display_inlined'])
0855 {
0856 if ($config['img_link_width'] || $config['img_link_height'])
0857 {
0858 $dimension = @getimagesize($filename);
0859
0860 // If the dimensions could not be determined or the image being 0x0 we display it as a link for safety purposes
0861 if ($dimension === false || empty($dimension[0]) || empty($dimension[1]))
0862 {
0863 $display_cat = ATTACHMENT_CATEGORY_NONE;
0864 }
0865 else
0866 {
0867 $display_cat = ($dimension[0] <= $config['img_link_width'] && $dimension[1] <= $config['img_link_height']) ? ATTACHMENT_CATEGORY_IMAGE : ATTACHMENT_CATEGORY_NONE;
0868 }
0869 }
0870 }
0871 else
0872 {
0873 $display_cat = ATTACHMENT_CATEGORY_NONE;
0874 }
0875 }
0876 }
0877
0878 // Make some descisions based on user options being set.
0879 if (($display_cat == ATTACHMENT_CATEGORY_IMAGE || $display_cat == ATTACHMENT_CATEGORY_THUMB) && !$user->optionget('viewimg'))
0880 {
0881 $display_cat = ATTACHMENT_CATEGORY_NONE;
0882 }
0883
0884 if ($display_cat == ATTACHMENT_CATEGORY_FLASH && !$user->optionget('viewflash'))
0885 {
0886 $display_cat = ATTACHMENT_CATEGORY_NONE;
0887 }
0888
0889 $download_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $attachment['attach_id']);
0890
0891 switch ($display_cat)
0892 {
0893 // Images
0894 case ATTACHMENT_CATEGORY_IMAGE:
0895 $l_downloaded_viewed = 'VIEWED_COUNT';
0896 $inline_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $attachment['attach_id']);
0897 $download_link .= '&mode=view';
0898
0899 $block_array += array(
0900 'S_IMAGE' => true,
0901 'U_INLINE_LINK' => $inline_link,
0902 );
0903
0904 $update_count[] = $attachment['attach_id'];
0905 break;
0906
0907 // Images, but display Thumbnail
0908 case ATTACHMENT_CATEGORY_THUMB:
0909 $l_downloaded_viewed = 'VIEWED_COUNT';
0910 $thumbnail_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'id=' . $attachment['attach_id'] . '&t=1');
0911 $download_link .= '&mode=view';
0912
0913 $block_array += array(
0914 'S_THUMBNAIL' => true,
0915 'THUMB_IMAGE' => $thumbnail_link,
0916 );
0917 break;
0918
0919 // Windows Media Streams
0920 case ATTACHMENT_CATEGORY_WM:
0921 $l_downloaded_viewed = 'VIEWED_COUNT';
0922
0923 // Giving the filename directly because within the wm object all variables are in local context making it impossible
0924 // to validate against a valid session (all params can differ)
0925 // $download_link = $filename;
0926
0927 $block_array += array(
0928 'U_FORUM' => generate_board_url(),
0929 'ATTACH_ID' => $attachment['attach_id'],
0930 'S_WM_FILE' => true,
0931 );
0932
0933 // Viewed/Heared File ... update the download count
0934 $update_count[] = $attachment['attach_id'];
0935 break;
0936
0937 // Real Media Streams
0938 case ATTACHMENT_CATEGORY_RM:
0939 case ATTACHMENT_CATEGORY_QUICKTIME:
0940 $l_downloaded_viewed = 'VIEWED_COUNT';
0941
0942 $block_array += array(
0943 'S_RM_FILE' => ($display_cat == ATTACHMENT_CATEGORY_RM) ? true : false,
0944 'S_QUICKTIME_FILE' => ($display_cat == ATTACHMENT_CATEGORY_QUICKTIME) ? true : false,
0945 'U_FORUM' => generate_board_url(),
0946 'ATTACH_ID' => $attachment['attach_id'],
0947 );
0948
0949 // Viewed/Heared File ... update the download count
0950 $update_count[] = $attachment['attach_id'];
0951 break;
0952
0953 // Macromedia Flash Files
0954 case ATTACHMENT_CATEGORY_FLASH:
0955 list($width, $height) = @getimagesize($filename);
0956
0957 $l_downloaded_viewed = 'VIEWED_COUNT';
0958
0959 $block_array += array(
0960 'S_FLASH_FILE' => true,
0961 'WIDTH' => $width,
0962 'HEIGHT' => $height,
0963 );
0964
0965 // Viewed/Heared File ... update the download count
0966 $update_count[] = $attachment['attach_id'];
0967 break;
0968
0969 default:
0970 $l_downloaded_viewed = 'DOWNLOAD_COUNT';
0971
0972 $block_array += array(
0973 'S_FILE' => true,
0974 );
0975 break;
0976 }
0977
0978 $l_download_count = (!isset($attachment['download_count']) || $attachment['download_count'] == 0) ? $user->lang[$l_downloaded_viewed . '_NONE'] : (($attachment['download_count'] == 1) ? sprintf($user->lang[$l_downloaded_viewed], $attachment['download_count']) : sprintf($user->lang[$l_downloaded_viewed . 'S'], $attachment['download_count']));
0979
0980 $block_array += array(
0981 'U_DOWNLOAD_LINK' => $download_link,
0982 'L_DOWNLOAD_COUNT' => $l_download_count
0983 );
0984 }
0985
0986 $template->assign_block_vars('_file', $block_array);
0987
0988 $compiled_attachments[] = $template->assign_display('attachment_tpl');
0989 }
0990
0991 $attachments = $compiled_attachments;
0992 unset($compiled_attachments);
0993
0994 $tpl_size = sizeof($attachments);
0995
0996 $unset_tpl = array();
0997
0998 preg_match_all('#<!\-\- ia([0-9]+) \-\->(.*?)<!\-\- ia\1 \-\->#', $message, $matches, PREG_PATTERN_ORDER);
0999
1000 $replace = array();
1001 foreach ($matches[0] as $num => $capture)
1002 {
1003 // Flip index if we are displaying the reverse way
1004 $index = ($config['display_order']) ? ($tpl_size-($matches[1][$num] + 1)) : $matches[1][$num];
1005
1006 $replace['from'][] = $matches[0][$num];
1007 $replace['to'][] = (isset($attachments[$index])) ? $attachments[$index] : sprintf($user->lang['MISSING_INLINE_ATTACHMENT'], $matches[2][array_search($index, $matches[1])]);
1008
1009 $unset_tpl[] = $index;
1010 }
1011
1012 if (isset($replace['from']))
1013 {
1014 $message = str_replace($replace['from'], $replace['to'], $message);
1015 }
1016
1017 $unset_tpl = array_unique($unset_tpl);
1018
1019 // Needed to let not display the inlined attachments at the end of the post again
1020 foreach ($unset_tpl as $index)
1021 {
1022 unset($attachments[$index]);
1023 }
1024 }
1025
1026 /**
1027 * Check if extension is allowed to be posted.
1028 *
1029 * @param mixed $forum_id The forum id to check or false if private message
1030 * @param string $extension The extension to check, for example zip.
1031 * @param array &$extensions The extension array holding the information from the cache (will be obtained if empty)
1032 *
1033 * @return bool False if the extension is not allowed to be posted, else true.
1034 */
1035 function extension_allowed($forum_id, $extension, &$extensions)
1036 {
1037 if (empty($extensions))
1038 {
1039 global $cache;
1040 $extensions = $cache->obtain_attach_extensions($forum_id);
1041 }
1042
1043 return (!isset($extensions['_allowed_'][$extension])) ? false : true;
1044 }
1045
1046 /**
1047 * Truncates string while retaining special characters if going over the max length
1048 * The default max length is 60 at the moment
1049 */
1050 function truncate_string($string, $max_length = 60, $allow_reply = true, $append = '')
1051 {
1052 $chars = array();
1053
1054 $strip_reply = false;
1055 $stripped = false;
1056 if ($allow_reply && strpos($string, 'Re: ') === 0)
1057 {
1058 $strip_reply = true;
1059 $string = substr($string, 4);
1060 }
1061
1062 $_chars = utf8_str_split(htmlspecialchars_decode($string));
1063 $chars = array_map('utf8_htmlspecialchars', $_chars);
1064
1065 // Now check the length ;)
1066 if (sizeof($chars) > $max_length)
1067 {
1068 // Cut off the last elements from the array
1069 $string = implode('', array_slice($chars, 0, $max_length - utf8_strlen($append)));
1070 $stripped = true;
1071 }
1072
1073 if ($strip_reply)
1074 {
1075 $string = 'Re: ' . $string;
1076 }
1077
1078 if ($append != '' && $stripped)
1079 {
1080 $string = $string . $append;
1081 }
1082
1083 return $string;
1084 }
1085
1086 /**
1087 * Get username details for placing into templates.
1088 *
1089 * @param string $mode Can be profile (for getting an url to the profile), username (for obtaining the username), colour (for obtaining the user colour), full (for obtaining a html string representing a coloured link to the users profile) or no_profile (the same as full but forcing no profile link)
1090 * @param int $user_id The users id
1091 * @param string $username The users name
1092 * @param string $username_colour The users colour
1093 * @param string $guest_username optional parameter to specify the guest username. It will be used in favor of the GUEST language variable then.
1094 * @param string $custom_profile_url optional parameter to specify a profile url. The user id get appended to this url as &u={user_id}
1095 *
1096 * @return string A string consisting of what is wanted based on $mode.
1097 */
1098 function get_username_string($mode, $user_id, $username, $username_colour = '', $guest_username = false, $custom_profile_url = false)
1099 {
1100 global $phpbb_root_path, $phpEx, $user, $auth;
1101
1102 $profile_url = '';
1103 $username_colour = ($username_colour) ? '#' . $username_colour : '';
1104
1105 if ($guest_username === false)
1106 {
1107 $username = ($username) ? $username : $user->lang['GUEST'];
1108 }
1109 else
1110 {
1111 $username = ($user_id && $user_id != ANONYMOUS) ? $username : ((!empty($guest_username)) ? $guest_username : $user->lang['GUEST']);
1112 }
1113
1114 // Only show the link if not anonymous
1115 if ($mode != 'no_profile' && $user_id && $user_id != ANONYMOUS)
1116 {
1117 // Do not show the link if the user is already logged in but do not have u_viewprofile permissions (relevant for bots mostly).
1118 // For all others the link leads to a login page or the profile.
1119 if ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile'))
1120 {
1121 $profile_url = '';
1122 }
1123 else
1124 {
1125 $profile_url = ($custom_profile_url !== false) ? $custom_profile_url . '&u=' . (int) $user_id : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile&u=' . (int) $user_id);
1126 }
1127 }
1128 else
1129 {
1130 $profile_url = '';
1131 }
1132
1133 switch ($mode)
1134 {
1135 case 'profile':
1136 return $profile_url;
1137 break;
1138
1139 case 'username':
1140 return $username;
1141 break;
1142
1143 case 'colour':
1144 return $username_colour;
1145 break;
1146
1147 case 'no_profile':
1148 case 'full':
1149 default:
1150
1151 $tpl = '';
1152 if (!$profile_url && !$username_colour)
1153 {
1154 $tpl = '{USERNAME}';
1155 }
1156 else if (!$profile_url && $username_colour)
1157 {
1158 $tpl = '<span style="color: {USERNAME_COLOUR};" class="username-coloured">{USERNAME}</span>';
1159 }
1160 else if ($profile_url && !$username_colour)
1161 {
1162 $tpl = '<a href="{PROFILE_URL}">{USERNAME}</a>';
1163 }
1164 else if ($profile_url && $username_colour)
1165 {
1166 $tpl = '<a href="{PROFILE_URL}" style="color: {USERNAME_COLOUR};" class="username-coloured">{USERNAME}</a>';
1167 }
1168
1169 return str_replace(array('{PROFILE_URL}', '{USERNAME_COLOUR}', '{USERNAME}'), array($profile_url, $username_colour, $username), $tpl);
1170 break;
1171 }
1172 }
1173
1174 /**
1175 * @package phpBB3
1176 */
1177 class bitfield
1178 {
1179 var $data;
1180
1181 function bitfield($bitfield = '')
1182 {
1183 $this->data = base64_decode($bitfield);
1184 }
1185
1186 /**
1187 */
1188 function get($n)
1189 {
1190 // Get the ($n / 8)th char
1191 $byte = $n >> 3;
1192
1193 if (strlen($this->data) >= $byte + 1)
1194 {
1195 $c = $this->data[$byte];
1196
1197 // Lookup the ($n % 8)th bit of the byte
1198 $bit = 7 - ($n & 7);
1199 return (bool) (ord($c) & (1 << $bit));
1200 }
1201 else
1202 {
1203 return false;
1204 }
1205 }
1206
1207 function set($n)
1208 {
1209 $byte = $n >> 3;
1210 $bit = 7 - ($n & 7);
1211
1212 if (strlen($this->data) >= $byte + 1)
1213 {
1214 $this->data[$byte] = $this->data[$byte] | chr(1 << $bit);
1215 }
1216 else
1217 {
1218 $this->data .= str_repeat("\0", $byte - strlen($this->data));
1219 $this->data .= chr(1 << $bit);
1220 }
1221 }
1222
1223 function clear($n)
1224 {
1225 $byte = $n >> 3;
1226
1227 if (strlen($this->data) >= $byte + 1)
1228 {
1229 $bit = 7 - ($n & 7);
1230 $this->data[$byte] = $this->data[$byte] &~ chr(1 << $bit);
1231 }
1232 }
1233
1234 function get_blob()
1235 {
1236 return $this->data;
1237 }
1238
1239 function get_base64()
1240 {
1241 return base64_encode($this->data);
1242 }
1243
1244 function get_bin()
1245 {
1246 $bin = '';
1247 $len = strlen($this->data);
1248
1249 for ($i = 0; $i < $len; ++$i)
1250 {
1251 $bin .= str_pad(decbin(ord($this->data[$i])), 8, '0', STR_PAD_LEFT);
1252 }
1253
1254 return $bin;
1255 }
1256
1257 function get_all_set()
1258 {
1259 return array_keys(array_filter(str_split($this->get_bin())));
1260 }
1261
1262 function merge($bitfield)
1263 {
1264 $this->data = $this->data | $bitfield->get_blob();
1265 }
1266 }
1267
1268 ?>