diff options
Diffstat (limited to 'phpBB/includes')
47 files changed, 1511 insertions, 218 deletions
diff --git a/phpBB/includes/acm/acm_file.php b/phpBB/includes/acm/acm_file.php index 234be5c5d1..5a758aa2bb 100644 --- a/phpBB/includes/acm/acm_file.php +++ b/phpBB/includes/acm/acm_file.php @@ -410,7 +410,7 @@ class acm { if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) { - return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field] : false; + return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++][$field] : false; } return false; diff --git a/phpBB/includes/acm/acm_memory.php b/phpBB/includes/acm/acm_memory.php index e315e979e5..efbfd4dd62 100644 --- a/phpBB/includes/acm/acm_memory.php +++ b/phpBB/includes/acm/acm_memory.php @@ -50,6 +50,8 @@ class acm_memory if (isset($this->function) && !function_exists($this->function)) { + global $acm_type; + trigger_error("The required function [{$this->function}] is not available for the ACM module $acm_type.", E_USER_ERROR); } } @@ -364,7 +366,7 @@ class acm_memory { if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) { - return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field] : false; + return (isset($this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]][$field])) ? $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++][$field] : false; } return false; diff --git a/phpBB/includes/acp/acp_attachments.php b/phpBB/includes/acp/acp_attachments.php index 849c076f0e..25e51814c4 100644 --- a/phpBB/includes/acp/acp_attachments.php +++ b/phpBB/includes/acp/acp_attachments.php @@ -124,11 +124,11 @@ class acp_attachments 'legend2' => $l_legend_cat_images, 'img_display_inlined' => array('lang' => 'DISPLAY_INLINED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'img_create_thumbnail' => array('lang' => 'CREATE_THUMBNAIL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'img_max_thumb_width' => array('lang' => 'MAX_THUMB_WIDTH', 'validate' => 'int', 'type' => 'text:7:15', 'explain' => true, 'append' => ' px'), + 'img_max_thumb_width' => array('lang' => 'MAX_THUMB_WIDTH', 'validate' => 'int', 'type' => 'text:7:15', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), 'img_min_thumb_filesize' => array('lang' => 'MIN_THUMB_FILESIZE', 'validate' => 'int', 'type' => 'text:7:15', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']), 'img_imagick' => array('lang' => 'IMAGICK_PATH', 'validate' => 'string', 'type' => 'text:20:200', 'explain' => true, 'append' => ' <span>[ <a href="' . $this->u_action . '&action=imgmagick">' . $user->lang['SEARCH_IMAGICK'] . '</a> ]</span>'), - 'img_max' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' px'), - 'img_link' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' px'), + 'img_max' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), + 'img_link' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), ) ); diff --git a/phpBB/includes/acp/acp_bbcodes.php b/phpBB/includes/acp/acp_bbcodes.php index b827d1107e..2b706394c4 100644 --- a/phpBB/includes/acp/acp_bbcodes.php +++ b/phpBB/includes/acp/acp_bbcodes.php @@ -124,121 +124,137 @@ class acp_bbcodes case 'modify': case 'create': - $data = $this->build_regexp($bbcode_match, $bbcode_tpl); + $warn_text = preg_match('%<[^>]*\{text[\d]*\}[^>]*>%i', $bbcode_tpl); + if (!$warn_text || confirm_box(true)) + { + $data = $this->build_regexp($bbcode_match, $bbcode_tpl); - // Make sure the user didn't pick a "bad" name for the BBCode tag. - $hard_coded = array('code', 'quote', 'quote=', 'attachment', 'attachment=', 'b', 'i', 'url', 'url=', 'img', 'size', 'size=', 'color', 'color=', 'u', 'list', 'list=', 'email', 'email=', 'flash', 'flash='); + // Make sure the user didn't pick a "bad" name for the BBCode tag. + $hard_coded = array('code', 'quote', 'quote=', 'attachment', 'attachment=', 'b', 'i', 'url', 'url=', 'img', 'size', 'size=', 'color', 'color=', 'u', 'list', 'list=', 'email', 'email=', 'flash', 'flash='); - if (($action == 'modify' && strtolower($data['bbcode_tag']) !== strtolower($row['bbcode_tag'])) || ($action == 'create')) - { - $sql = 'SELECT 1 as test - FROM ' . BBCODES_TABLE . " - WHERE LOWER(bbcode_tag) = '" . $db->sql_escape(strtolower($data['bbcode_tag'])) . "'"; - $result = $db->sql_query($sql); - $info = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // Grab the end, interrogate the last closing tag - if ($info['test'] === '1' || in_array(strtolower($data['bbcode_tag']), $hard_coded) || (preg_match('#\[/([^[]*)]$#', $bbcode_match, $regs) && in_array(strtolower($regs[1]), $hard_coded))) + if (($action == 'modify' && strtolower($data['bbcode_tag']) !== strtolower($row['bbcode_tag'])) || ($action == 'create')) { - trigger_error($user->lang['BBCODE_INVALID_TAG_NAME'] . adm_back_link($this->u_action), E_USER_WARNING); + $sql = 'SELECT 1 as test + FROM ' . BBCODES_TABLE . " + WHERE LOWER(bbcode_tag) = '" . $db->sql_escape(strtolower($data['bbcode_tag'])) . "'"; + $result = $db->sql_query($sql); + $info = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + // Grab the end, interrogate the last closing tag + if ($info['test'] === '1' || in_array(strtolower($data['bbcode_tag']), $hard_coded) || (preg_match('#\[/([^[]*)]$#', $bbcode_match, $regs) && in_array(strtolower($regs[1]), $hard_coded))) + { + trigger_error($user->lang['BBCODE_INVALID_TAG_NAME'] . adm_back_link($this->u_action), E_USER_WARNING); + } } - } - if (substr($data['bbcode_tag'], -1) === '=') - { - $test = substr($data['bbcode_tag'], 0, -1); - } - else - { - $test = $data['bbcode_tag']; - } + if (substr($data['bbcode_tag'], -1) === '=') + { + $test = substr($data['bbcode_tag'], 0, -1); + } + else + { + $test = $data['bbcode_tag']; + } - if (!preg_match('%\\[' . $test . '[^]]*].*?\\[/' . $test . ']%s', $bbcode_match)) - { - trigger_error($user->lang['BBCODE_OPEN_ENDED_TAG'] . adm_back_link($this->u_action), E_USER_WARNING); - } + if (!preg_match('%\\[' . $test . '[^]]*].*?\\[/' . $test . ']%s', $bbcode_match)) + { + trigger_error($user->lang['BBCODE_OPEN_ENDED_TAG'] . adm_back_link($this->u_action), E_USER_WARNING); + } - if (strlen($data['bbcode_tag']) > 16) - { - trigger_error($user->lang['BBCODE_TAG_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); - } + if (strlen($data['bbcode_tag']) > 16) + { + trigger_error($user->lang['BBCODE_TAG_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); + } - if (strlen($bbcode_match) > 4000) - { - trigger_error($user->lang['BBCODE_TAG_DEF_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); - } - - - if (strlen($bbcode_helpline) > 255) - { - trigger_error($user->lang['BBCODE_HELPLINE_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); - } + if (strlen($bbcode_match) > 4000) + { + trigger_error($user->lang['BBCODE_TAG_DEF_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); + } - $sql_ary = array( - 'bbcode_tag' => $data['bbcode_tag'], - 'bbcode_match' => $bbcode_match, - 'bbcode_tpl' => $bbcode_tpl, - 'display_on_posting' => $display_on_posting, - 'bbcode_helpline' => $bbcode_helpline, - 'first_pass_match' => $data['first_pass_match'], - 'first_pass_replace' => $data['first_pass_replace'], - 'second_pass_match' => $data['second_pass_match'], - 'second_pass_replace' => $data['second_pass_replace'] - ); - if ($action == 'create') - { - $sql = 'SELECT MAX(bbcode_id) as max_bbcode_id - FROM ' . BBCODES_TABLE; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); + if (strlen($bbcode_helpline) > 255) + { + trigger_error($user->lang['BBCODE_HELPLINE_TOO_LONG'] . adm_back_link($this->u_action), E_USER_WARNING); + } - if ($row) + $sql_ary = array( + 'bbcode_tag' => $data['bbcode_tag'], + 'bbcode_match' => $bbcode_match, + 'bbcode_tpl' => $bbcode_tpl, + 'display_on_posting' => $display_on_posting, + 'bbcode_helpline' => $bbcode_helpline, + 'first_pass_match' => $data['first_pass_match'], + 'first_pass_replace' => $data['first_pass_replace'], + 'second_pass_match' => $data['second_pass_match'], + 'second_pass_replace' => $data['second_pass_replace'] + ); + + if ($action == 'create') { - $bbcode_id = $row['max_bbcode_id'] + 1; + $sql = 'SELECT MAX(bbcode_id) as max_bbcode_id + FROM ' . BBCODES_TABLE; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if ($row) + { + $bbcode_id = $row['max_bbcode_id'] + 1; - // Make sure it is greater than the core bbcode ids... - if ($bbcode_id <= NUM_CORE_BBCODES) + // Make sure it is greater than the core bbcode ids... + if ($bbcode_id <= NUM_CORE_BBCODES) + { + $bbcode_id = NUM_CORE_BBCODES + 1; + } + } + else { $bbcode_id = NUM_CORE_BBCODES + 1; } + + if ($bbcode_id > 1511) + { + trigger_error($user->lang['TOO_MANY_BBCODES'] . adm_back_link($this->u_action), E_USER_WARNING); + } + + $sql_ary['bbcode_id'] = (int) $bbcode_id; + + $db->sql_query('INSERT INTO ' . BBCODES_TABLE . $db->sql_build_array('INSERT', $sql_ary)); + $cache->destroy('sql', BBCODES_TABLE); + + $lang = 'BBCODE_ADDED'; + $log_action = 'LOG_BBCODE_ADD'; } else { - $bbcode_id = NUM_CORE_BBCODES + 1; - } + $sql = 'UPDATE ' . BBCODES_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' + WHERE bbcode_id = ' . $bbcode_id; + $db->sql_query($sql); + $cache->destroy('sql', BBCODES_TABLE); - if ($bbcode_id > 1511) - { - trigger_error($user->lang['TOO_MANY_BBCODES'] . adm_back_link($this->u_action), E_USER_WARNING); + $lang = 'BBCODE_EDITED'; + $log_action = 'LOG_BBCODE_EDIT'; } - $sql_ary['bbcode_id'] = (int) $bbcode_id; - - $db->sql_query('INSERT INTO ' . BBCODES_TABLE . $db->sql_build_array('INSERT', $sql_ary)); - $cache->destroy('sql', BBCODES_TABLE); + add_log('admin', $log_action, $data['bbcode_tag']); - $lang = 'BBCODE_ADDED'; - $log_action = 'LOG_BBCODE_ADD'; + trigger_error($user->lang[$lang] . adm_back_link($this->u_action)); } else { - $sql = 'UPDATE ' . BBCODES_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $sql_ary) . ' - WHERE bbcode_id = ' . $bbcode_id; - $db->sql_query($sql); - $cache->destroy('sql', BBCODES_TABLE); - - $lang = 'BBCODE_EDITED'; - $log_action = 'LOG_BBCODE_EDIT'; + confirm_box(false, $user->lang['BBCODE_DANGER'], build_hidden_fields(array( + 'action' => $action, + 'bbcode' => $bbcode_id, + 'bbcode_match' => $bbcode_match, + 'bbcode_tpl' => htmlspecialchars($bbcode_tpl), + 'bbcode_helpline' => $bbcode_helpline, + 'display_on_posting' => $display_on_posting, + )) + , 'confirm_bbcode.html'); } - add_log('admin', $log_action, $data['bbcode_tag']); - - trigger_error($user->lang[$lang] . adm_back_link($this->u_action)); - break; case 'delete': @@ -299,6 +315,18 @@ class acp_bbcodes { $bbcode_match = trim($bbcode_match); $bbcode_tpl = trim($bbcode_tpl); + $utf8 = strpos($bbcode_match, 'INTTEXT') !== false; + + // make sure we have utf8 support + $utf8_pcre_properties = false; + if (version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.0', '>='))) + { + // While this is the proper range of PHP versions, PHP may not be linked with the bundled PCRE lib and instead with an older version + if (@preg_match('/\p{L}/u', 'a') !== false) + { + $utf8_pcre_properties = true; + } + } $fp_match = preg_quote($bbcode_match, '!'); $fp_replace = preg_replace('#^\[(.*?)\]#', '[$1:$uid]', $bbcode_match); @@ -326,6 +354,9 @@ class acp_bbcodes 'SIMPLETEXT' => array( '!([a-zA-Z0-9-+.,_ ]+)!' => "$1" ), + 'INTTEXT' => array( + ($utf8_pcre_properties) ? '!([\p{L}\p{N}\-+,_. ]+)!u' : '!([a-zA-Z0-9\-+,_. ]+)!u' => "$1" + ), 'IDENTIFIER' => array( '!([a-zA-Z0-9-_]+)!' => "$1" ), @@ -343,6 +374,7 @@ class acp_bbcodes 'EMAIL' => '(' . get_preg_expression('email') . ')', 'TEXT' => '(.*?)', 'SIMPLETEXT' => '([a-zA-Z0-9-+.,_ ]+)', + 'INTTEXT' => ($utf8_pcre_properties) ? '([\p{L}\p{N}\-+,_. ]+)' : '([a-zA-Z0-9\-+,_. ]+)', 'IDENTIFIER' => '([a-zA-Z0-9-_]+)', 'COLOR' => '([a-zA-Z]+|#[0-9abcdefABCDEF]+)', 'NUMBER' => '([0-9]+)', @@ -350,6 +382,7 @@ class acp_bbcodes $pad = 0; $modifiers = 'i'; + $modifiers .= ($utf8 && $utf8_pcre_properties) ? 'u' : ''; if (preg_match_all('/\{(' . implode('|', array_keys($tokens)) . ')[0-9]*\}/i', $bbcode_match, $m)) { @@ -398,7 +431,7 @@ class acp_bbcodes } $fp_match = '!' . $fp_match . '!' . $modifiers; - $sp_match = '!' . $sp_match . '!s'; + $sp_match = '!' . $sp_match . '!s' . (($utf8) ? 'u' : ''); if (strpos($fp_match, 'e') !== false) { diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index 9f0bcf210f..a5feac1902 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -29,11 +29,12 @@ class acp_board { global $db, $user, $auth, $template; global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + global $cache; $user->add_lang('acp/board'); $action = request_var('action', ''); - $submit = (isset($_POST['submit'])) ? true : false; + $submit = (isset($_POST['submit']) || isset($_POST['allow_quick_reply_enable'])) ? true : false; $form_key = 'acp_board'; add_form_key($form_key); @@ -88,7 +89,7 @@ class acp_board 'allow_nocensors' => array('lang' => 'ALLOW_NO_CENSORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'allow_bookmarks' => array('lang' => 'ALLOW_BOOKMARKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'allow_birthdays' => array('lang' => 'ALLOW_BIRTHDAYS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_quick_reply' => array('lang' => 'ALLOW_QUICK_REPLY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_quick_reply' => array('lang' => 'ALLOW_QUICK_REPLY', 'validate' => 'bool', 'type' => 'custom', 'method' => 'quick_reply', 'explain' => true), 'legend2' => 'ACP_LOAD_SETTINGS', 'load_birthdays' => array('lang' => 'YES_BIRTHDAYS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), @@ -172,7 +173,7 @@ class acp_board 'allow_nocensors' => array('lang' => 'ALLOW_NO_CENSORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'allow_bookmarks' => array('lang' => 'ALLOW_BOOKMARKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'enable_post_confirm' => array('lang' => 'VISUAL_CONFIRM_POST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'allow_quick_reply' => array('lang' => 'ALLOW_QUICK_REPLY', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), + 'allow_quick_reply' => array('lang' => 'ALLOW_QUICK_REPLY', 'validate' => 'bool', 'type' => 'custom', 'method' => 'quick_reply', 'explain' => true), 'legend2' => 'POSTING', 'bump_type' => false, @@ -266,14 +267,22 @@ class acp_board 'legend1' => 'ACP_FEED_GENERAL', 'feed_enable' => array('lang' => 'ACP_FEED_ENABLE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), 'feed_item_statistics' => array('lang' => 'ACP_FEED_ITEM_STATISTICS', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), - 'feed_limit' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5', 'type' => 'text:3:4', 'explain' => true), - 'feed_overall_forums' => array('lang' => 'ACP_FEED_OVERALL_FORUMS', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_overall_forums_limit' => array('lang' => 'ACP_FEED_OVERALL_FORUMS_LIMIT', 'validate' => 'int:5', 'type' => 'text:3:4', 'explain' => false), - 'feed_overall_topics' => array('lang' => 'ACP_FEED_OVERALL_TOPIC', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), - 'feed_overall_topics_limit' => array('lang' => 'ACP_FEED_OVERALL_TOPIC_LIMIT', 'validate' => 'int:5', 'type' => 'text:3:4', 'explain' => false), + 'feed_http_auth' => array('lang' => 'ACP_FEED_HTTP_AUTH', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true), + + 'legend2' => 'ACP_FEED_POST_BASED', + 'feed_limit_post' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5', 'type' => 'text:3:4', 'explain' => true), + 'feed_overall' => array('lang' => 'ACP_FEED_OVERALL', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), 'feed_forum' => array('lang' => 'ACP_FEED_FORUM', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), 'feed_topic' => array('lang' => 'ACP_FEED_TOPIC', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), + + 'legend3' => 'ACP_FEED_TOPIC_BASED', + 'feed_limit_topic' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5', 'type' => 'text:3:4', 'explain' => true), + 'feed_topics_new' => array('lang' => 'ACP_FEED_TOPICS_NEW', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), + 'feed_topics_active' => array('lang' => 'ACP_FEED_TOPICS_ACTIVE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), 'feed_news_id' => array('lang' => 'ACP_FEED_NEWS', 'validate' => 'string', 'type' => 'custom', 'method' => 'select_news_forums', 'explain' => true), + + 'legend4' => 'ACP_FEED_SETTINGS_OTHER', + 'feed_overall_forums' => array('lang' => 'ACP_FEED_OVERALL_FORUMS', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ), 'feed_exclude_id' => array('lang' => 'ACP_FEED_EXCLUDE_ID', 'validate' => 'string', 'type' => 'custom', 'method' => 'select_exclude_forums', 'explain' => true), ) ); @@ -463,12 +472,20 @@ class acp_board if ($submit) { set_config($config_name, $config_value); + + if ($config_name == 'allow_quick_reply' && isset($_POST['allow_quick_reply_enable'])) + { + enable_bitfield_column_flag(FORUMS_TABLE, 'forum_flags', log(FORUM_FLAG_QUICK_REPLY, 2)); + } } } // Store news and exclude ids if ($mode == 'feed' && $submit) { + $cache->destroy('_feed_news_forum_ids'); + $cache->destroy('_feed_excluded_forum_ids'); + $this->store_feed_forums(FORUM_OPTION_FEED_NEWS, 'feed_news_id'); $this->store_feed_forums(FORUM_OPTION_FEED_EXCLUDE, 'feed_exclude_id'); } @@ -847,6 +864,20 @@ class acp_board } /** + * Global quick reply enable/disable setting and button to enable in all forums + */ + function quick_reply($value, $key) + { + global $user; + + $radio_ary = array(1 => 'YES', 0 => 'NO'); + + return h_radio('config[allow_quick_reply]', $radio_ary, $value) . + '<br /><br /><input class="button2" type="submit" id="' . $key . '_enable" name="' . $key . '_enable" value="' . $user->lang['ALLOW_QUICK_REPLY_BUTTON'] . '" />'; + } + + + /** * Select default dateformat */ function dateformat_select($value, $key) @@ -910,7 +941,7 @@ class acp_board { global $user, $config; - $forum_list = make_forum_select(false, false, true, false, false, false, true); + $forum_list = make_forum_select(false, false, true, true, true, false, true); // Build forum options $s_forum_options = '<select id="' . $key . '" name="' . $key . '[]" multiple="multiple">'; diff --git a/phpBB/includes/acp/acp_captcha.php b/phpBB/includes/acp/acp_captcha.php index e1fa764191..56a57e319c 100644 --- a/phpBB/includes/acp/acp_captcha.php +++ b/phpBB/includes/acp/acp_captcha.php @@ -56,6 +56,7 @@ class acp_captcha 'enable_post_confirm' => array('tpl' => 'POST_ENABLE', 'default' => false), 'confirm_refresh' => array('tpl' => 'CONFIRM_REFRESH', 'default' => false), 'max_reg_attempts' => array('tpl' => 'REG_LIMIT', 'default' => 0), + 'max_login_attempts' => array('tpl' => 'MAX_LOGIN_ATTEMPTS', 'default' => 0), ); $this->tpl_name = 'acp_captcha'; diff --git a/phpBB/includes/acp/acp_database.php b/phpBB/includes/acp/acp_database.php index 5d7450bdfd..abfad2b90b 100644 --- a/phpBB/includes/acp/acp_database.php +++ b/phpBB/includes/acp/acp_database.php @@ -109,6 +109,7 @@ class acp_database case 'mssql': case 'mssql_odbc': + case 'mssqlnative': $extractor = new mssql_extractor($download, $store, $format, $filename, $time); break; @@ -138,6 +139,7 @@ class acp_database case 'mssql': case 'mssql_odbc': + case 'mssqlnative': $extractor->flush('TRUNCATE TABLE ' . $table_name . "GO\n"); break; @@ -435,7 +437,7 @@ class acp_database { if (in_array($matches[2], $methods)) { - $backup_files[gmdate("d-m-Y H:i:s", $matches[1])] = $file; + $backup_files[(int) $matches[1]] = $file; } } } @@ -450,7 +452,7 @@ class acp_database { $template->assign_block_vars('files', array( 'FILE' => $file, - 'NAME' => $name, + 'NAME' => $user->format_date($name, 'd-m-Y H:i:s', true), 'SUPPORTED' => true, )); } @@ -1509,6 +1511,10 @@ class mssql_extractor extends base_extractor { $this->write_data_mssql($table_name); } + else if($db->sql_layer === 'mssqlnative') + { + $this->write_data_mssqlnative($table_name); + } else { $this->write_data_odbc($table_name); @@ -1608,7 +1614,103 @@ class mssql_extractor extends base_extractor } $this->flush($sql_data); } + + function write_data_mssqlnative($table_name) + { + global $db; + $ary_type = $ary_name = $meta_array = array(); + $ident_set = false; + $sql_data = ''; + + // Grab all of the data from current table. + $sql = "SELECT * FROM $table_name"; + $result = $db->sql_query($sql); + + $retrieved_data = $db->mssqlnative_num_rows($result); + + $meta_array = sqlsrv_field_metadata($result); + $i_num_fields = sqlsrv_num_fields($result); + + for ($i = 0; $i < $i_num_fields; $i++) + { + $info = $db->mssqlnative_fieldInfo($table_name, $meta_array[$i]['Name']); + $ary_type[$i] = $info->type(); + $ary_name[$i] = $info->name(); + } + + if ($retrieved_data) + { + $sql = "SELECT 1 as has_identity + FROM INFORMATION_SCHEMA.COLUMNS + WHERE COLUMNPROPERTY(object_id('$table_name'), COLUMN_NAME, 'IsIdentity') = 1"; + $result2 = $db->sql_query($sql); + $row2 = $db->sql_fetchrow($result2); + + if (!empty($row2['has_identity'])) + { + $sql_data .= "\nSET IDENTITY_INSERT $table_name ON\nGO\n"; + $ident_set = true; + } + $db->sql_freeresult($result2); + } + + while ($row = $db->sql_fetchrow($result)) + { + $schema_vals = $schema_fields = array(); + // Build the SQL statement to recreate the data. + for ($i = 0; $i < $i_num_fields; $i++) + { + $str_val = $row[$ary_name[$i]]; + + if (preg_match('#char|text|bool|varbinary#i', $ary_type[$i])) + { + $str_quote = ''; + $str_empty = "''"; + $str_val = sanitize_data_mssql(str_replace("'", "''", $str_val)); + } + else if (preg_match('#date|timestamp#i', $ary_type[$i])) + { + if (empty($str_val)) + { + $str_quote = ''; + } + else + { + $str_quote = "'"; + } + } + else + { + $str_quote = ''; + $str_empty = 'NULL'; + } + + if (empty($str_val) && $str_val !== '0' && !(is_int($str_val) || is_float($str_val))) + { + $str_val = $str_empty; + } + + $schema_vals[$i] = $str_quote . $str_val . $str_quote; + $schema_fields[$i] = $ary_name[$i]; + } + + // Take the ordered fields and their associated data and build it + // into a valid sql statement to recreate that field in the data. + $sql_data .= "INSERT INTO $table_name (" . implode(', ', $schema_fields) . ') VALUES (' . implode(', ', $schema_vals) . ");\nGO\n"; + + $this->flush($sql_data); + $sql_data = ''; + } + $db->sql_freeresult($result); + + if ($retrieved_data && $ident_set) + { + $sql_data .= "\nSET IDENTITY_INSERT $table_name OFF\nGO\n"; + } + $this->flush($sql_data); + } + function write_data_odbc($table_name) { global $db; diff --git a/phpBB/includes/acp/acp_icons.php b/phpBB/includes/acp/acp_icons.php index e1deb7e533..3d64a2acda 100644 --- a/phpBB/includes/acp/acp_icons.php +++ b/phpBB/includes/acp/acp_icons.php @@ -941,11 +941,12 @@ class acp_icons { global $db; - $sql = "SELECT COUNT(*) AS count + $sql = "SELECT COUNT(*) AS item_count FROM $table"; $result = $db->sql_query($sql); - $item_count = (int) $db->sql_fetchfield('count'); + $item_count = (int) $db->sql_fetchfield('item_count'); $db->sql_freeresult($result); + return $item_count; } } diff --git a/phpBB/includes/acp/acp_language.php b/phpBB/includes/acp/acp_language.php index 8ca45a27f6..fedae6fe67 100644 --- a/phpBB/includes/acp/acp_language.php +++ b/phpBB/includes/acp/acp_language.php @@ -1120,6 +1120,11 @@ class acp_language { while (($file = readdir($dp)) !== false) { + if (!is_dir($phpbb_root_path . 'language/' . $file)) + { + continue; + } + if ($file[0] != '.' && file_exists("{$phpbb_root_path}language/$file/iso.txt")) { if (!in_array($file, $installed)) diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php index cd83c52e01..b8712b2a3d 100644 --- a/phpBB/includes/acp/acp_main.php +++ b/phpBB/includes/acp/acp_main.php @@ -398,6 +398,14 @@ class acp_main // Version check $user->add_lang('install'); + if ($auth->acl_get('a_server') && version_compare(PHP_VERSION, '5.2.0', '<')) + { + $template->assign_vars(array( + 'S_PHP_VERSION_OLD' => true, + 'L_PHP_VERSION_OLD' => sprintf($user->lang['PHP_VERSION_OLD'], '<a href="http://www.phpbb.com/community/viewtopic.php?f=14&t=1958605">', '</a>'), + )); + } + $latest_version_info = false; if (($latest_version_info = obtain_latest_version_info(request_var('versioncheck_force', false))) === false) { diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php index fbf3eadcb2..d2a0f9210f 100644 --- a/phpBB/includes/acp/acp_styles.php +++ b/phpBB/includes/acp/acp_styles.php @@ -643,6 +643,11 @@ parse_css_file = {PARSE_CSS_FILE} { while (($file = readdir($dp)) !== false) { + if (!is_dir($phpbb_root_path . 'styles/' . $file)) + { + continue; + } + $subpath = ($mode != 'style') ? "$mode/" : ''; if ($file[0] != '.' && file_exists("{$phpbb_root_path}styles/$file/$subpath$mode.cfg")) { diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php index 71f8a7c082..73c4f92976 100644 --- a/phpBB/includes/auth/auth_db.php +++ b/phpBB/includes/auth/auth_db.php @@ -62,16 +62,22 @@ function login_db(&$username, &$password) 'user_row' => array('user_id' => ANONYMOUS), ); } + $show_captcha = $config['max_login_attempts'] && $row['user_login_attempts'] >= $config['max_login_attempts']; // If there are too much login attempts, we need to check for an confirm image // Every auth module is able to define what to do by itself... - if ($config['max_login_attempts'] && $row['user_login_attempts'] >= $config['max_login_attempts']) + if ($show_captcha) { // Visual Confirmation handling + if (!class_exists('phpbb_captcha_factory')) + { + global $phpbb_root_path, $phpEx; + include ($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); + } $captcha =& phpbb_captcha_factory::get_instance($config['captcha_plugin']); $captcha->init(CONFIRM_LOGIN); - $vc_response = $captcha->validate(); + $vc_response = $captcha->validate($row); if ($vc_response) { return array( @@ -80,6 +86,10 @@ function login_db(&$username, &$password) 'user_row' => $row, ); } + else + { + $captcha->reset(); + } } @@ -189,8 +199,8 @@ function login_db(&$username, &$password) // Give status about wrong password... return array( - 'status' => LOGIN_ERROR_PASSWORD, - 'error_msg' => 'LOGIN_ERROR_PASSWORD', + 'status' => ($show_captcha) ? LOGIN_ERROR_ATTEMPTS : LOGIN_ERROR_PASSWORD, + 'error_msg' => ($show_captcha) ? 'LOGIN_ERROR_ATTEMPTS' : 'LOGIN_ERROR_PASSWORD', 'user_row' => $row, ); } diff --git a/phpBB/includes/bbcode.php b/phpBB/includes/bbcode.php index f58852c00b..d77bb3c4a7 100644 --- a/phpBB/includes/bbcode.php +++ b/phpBB/includes/bbcode.php @@ -137,7 +137,7 @@ class bbcode if (!@file_exists($this->template_filename)) { - if (isset($template->orig_tpl_inherits_id) && $template->orig_tpl_inherits_id) + if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id']) { $this->template_filename = $phpbb_root_path . 'styles/' . $user->theme['template_inherit_path'] . '/template/bbcode.html'; if (!@file_exists($this->template_filename)) @@ -360,7 +360,7 @@ class bbcode // In order to use templates with custom bbcodes we need // to replace all {VARS} to corresponding backreferences // Note that backreferences are numbered from bbcode_match - if (preg_match_all('/\{(URL|LOCAL_URL|EMAIL|TEXT|SIMPLETEXT|IDENTIFIER|COLOR|NUMBER)[0-9]*\}/', $rowset[$bbcode_id]['bbcode_match'], $m)) + if (preg_match_all('/\{(URL|LOCAL_URL|EMAIL|TEXT|SIMPLETEXT|INTTEXT|IDENTIFIER|COLOR|NUMBER)[0-9]*\}/', $rowset[$bbcode_id]['bbcode_match'], $m)) { foreach ($m[0] as $i => $tok) { diff --git a/phpBB/includes/cache.php b/phpBB/includes/cache.php index a0142292ed..6b1e078ca4 100644 --- a/phpBB/includes/cache.php +++ b/phpBB/includes/cache.php @@ -82,9 +82,11 @@ class cache extends acm $result = $db->sql_query($sql); $censors = array(); + $unicode = ((version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.0', '>='))) && @preg_match('/\p{L}/u', 'a') !== false) ? true : false; + while ($row = $db->sql_fetchrow($result)) { - if ((version_compare(PHP_VERSION, '5.1.0', '>=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.0', '>='))) && @preg_match('/\p{L}/u', 'a') !== false) + if ($unicode) { $censors['match'][] = '#(?<![\p{Nd}\p{L}_])(' . str_replace('\*', '[\p{Nd}\p{L}_]*?', preg_quote($row['word'], '#')) . ')(?![\p{Nd}\p{L}_])#iu'; } @@ -297,6 +299,7 @@ class cache extends acm { case 'mssql': case 'mssql_odbc': + case 'mssqlnative': $sql = 'SELECT user_id, bot_agent, bot_ip FROM ' . BOTS_TABLE . ' WHERE bot_active = 1 diff --git a/phpBB/includes/captcha/plugins/captcha_abstract.php b/phpBB/includes/captcha/plugins/captcha_abstract.php index db4b7649c7..e7b8742b05 100644 --- a/phpBB/includes/captcha/plugins/captcha_abstract.php +++ b/phpBB/includes/captcha/plugins/captcha_abstract.php @@ -193,6 +193,11 @@ class phpbb_default_captcha { global $config, $db, $user; + if (empty($user->lang)) + { + $user->setup(); + } + $error = ''; if (!$this->confirm_id) { diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php index 45811c5d26..49a64b9339 100644 --- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -87,9 +87,9 @@ class phpbb_captcha_qa } $db->sql_freeresult($result); } - - // okay, if there is a confirm_id, we try to load that confirm's state - if (!strlen($this->confirm_id) || !$this->load_answer()) + + // okay, if there is a confirm_id, we try to load that confirm's state. If not, we try to find one + if (!$this->load_answer() && (!$this->load_confirm_id() || !$this->load_answer())) { // we have no valid confirm ID, better get ready to ask something $this->select_question(); @@ -137,14 +137,14 @@ class phpbb_captcha_qa return false; } - $sql = 'SELECT COUNT(question_id) as count + $sql = 'SELECT COUNT(question_id) AS question_count FROM ' . CAPTCHA_QUESTIONS_TABLE . " WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - return ((bool) $row['count']); + return ((bool) $row['question_count']); } /** @@ -214,6 +214,22 @@ class phpbb_captcha_qa */ function get_demo_template() { + global $config, $db, $template; + + if ($this->is_available()) + { + $sql = 'SELECT question_text + FROM ' . CAPTCHA_QUESTIONS_TABLE . " + WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; + $result = $db->sql_query_limit($sql, 1); + if ($row = $db->sql_fetchrow($result)) + { + $template->assign_vars(array( + 'QA_CONFIRM_QUESTION' => $row['question_text'], + )); + } + $db->sql_freeresult($result); + } return 'captcha_qa_acp_demo.html'; } @@ -237,11 +253,11 @@ class phpbb_captcha_qa /** * API function */ - function garbage_collect($type) + function garbage_collect($type = 0) { global $db, $config; - $sql = 'SELECT DISTINCT c.session_id + $sql = 'SELECT c.confirm_id FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' c LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id) @@ -255,14 +271,14 @@ class phpbb_captcha_qa do { - $sql_in[] = (string) $row['session_id']; + $sql_in[] = (string) $row['confirm_id']; } while ($row = $db->sql_fetchrow($result)); if (sizeof($sql_in)) { $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' - WHERE ' . $db->sql_in_set('session_id', $sql_in); + WHERE ' . $db->sql_in_set('confirm_id', $sql_in); $db->sql_query($sql); } } @@ -393,7 +409,6 @@ class phpbb_captcha_qa { global $db, $user; - if (!sizeof($this->question_ids)) { return false; @@ -458,6 +473,32 @@ class phpbb_captcha_qa $this->load_answer(); } + + /** + * See if there is already an entry for the current session. + */ + function load_confirm_id() + { + global $db, $user; + + $sql = 'SELECT confirm_id + FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " + WHERE + session_id = '" . $db->sql_escape($user->session_id) . "' + AND lang_iso = '" . $db->sql_escape($this->question_lang) . "' + AND confirm_type = " . $this->type; + $result = $db->sql_query_limit($sql, 1); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if ($row) + { + $this->confirm_id = $row['confirm_id']; + return true; + } + return false; + } + /** * Look up everything we need and populate the instance variables. */ @@ -465,7 +506,7 @@ class phpbb_captcha_qa { global $db, $user; - if (!sizeof($this->question_ids)) + if (!strlen($this->confirm_id) || !sizeof($this->question_ids)) { return false; } @@ -617,21 +658,28 @@ class phpbb_captcha_qa } else if ($question_id && $action == 'delete') { - if (confirm_box(true)) + if ($this->get_class_name() !== $config['captcha_plugin'] || !$this->acp_is_last($question_id)) { - $this->acp_delete_question($question_id); + if (confirm_box(true)) + { + $this->acp_delete_question($question_id); - trigger_error($user->lang['QUESTION_DELETED'] . adm_back_link($list_url)); + trigger_error($user->lang['QUESTION_DELETED'] . adm_back_link($list_url)); + } + else + { + confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( + 'question_id' => $question_id, + 'action' => $action, + 'configure' => 1, + 'select_captcha' => $this->get_class_name(), + )) + ); + } } else { - confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( - 'question_id' => $question_id, - 'action' => $action, - 'configure' => 1, - 'select_captcha' => $this->get_class_name(), - )) - ); + trigger_error($user->lang['QA_LAST_QUESTION'] . adm_back_link($list_url), E_USER_WARNING); } } else @@ -711,7 +759,7 @@ class phpbb_captcha_qa } else if ($submit) { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url)); + trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url), E_USER_WARNING); } } } @@ -942,6 +990,33 @@ class phpbb_captcha_qa return $langs; } + + + + /** + * See if there is a question other than the one we have + */ + function acp_is_last($question_id) + { + global $config, $db; + + if ($question_id) + { + $sql = 'SELECT question_id + FROM ' . CAPTCHA_QUESTIONS_TABLE . " + WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "' + AND question_id <> " . (int) $question_id; + $result = $db->sql_query_limit($sql, 1); + $question = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if (!$question) + { + return true; + } + return false; + } + } } ?>
\ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php index d4543dddfc..0f0bfc4156 100644 --- a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php +++ b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php @@ -28,10 +28,17 @@ if (!class_exists('phpbb_default_captcha')) class phpbb_recaptcha extends phpbb_default_captcha { var $recaptcha_server = 'http://api.recaptcha.net'; + var $recaptcha_server_secure = 'https://api-secure.recaptcha.net'; // class constants :( var $recaptcha_verify_server = 'api-verify.recaptcha.net'; var $challenge; var $response; + // PHP4 Constructor + function phpbb_recaptcha() + { + $this->recaptcha_server = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? $this->recaptcha_server_secure : $this->recaptcha_server; + } + function init($type) { global $config, $db, $user; diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index 398611d24e..f58b29d232 100644 --- a/phpBB/includes/constants.php +++ b/phpBB/includes/constants.php @@ -25,7 +25,7 @@ if (!defined('IN_PHPBB')) */ // phpBB Version -define('PHPBB_VERSION', '3.0.6'); +define('PHPBB_VERSION', '3.0.7'); // QA-related // define('PHPBB_QA', 1); diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index a762b31681..819ef69c96 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -160,6 +160,36 @@ class phpbb_db_tools 'VARBINARY' => '[varchar] (255)', ), + 'mssqlnative' => array( + 'INT:' => '[int]', + 'BINT' => '[float]', + 'UINT' => '[int]', + 'UINT:' => '[int]', + 'TINT:' => '[int]', + 'USINT' => '[int]', + 'BOOL' => '[int]', + 'VCHAR' => '[varchar] (255)', + 'VCHAR:' => '[varchar] (%d)', + 'CHAR:' => '[char] (%d)', + 'XSTEXT' => '[varchar] (1000)', + 'STEXT' => '[varchar] (3000)', + 'TEXT' => '[varchar] (8000)', + 'MTEXT' => '[text]', + 'XSTEXT_UNI'=> '[varchar] (100)', + 'STEXT_UNI' => '[varchar] (255)', + 'TEXT_UNI' => '[varchar] (4000)', + 'MTEXT_UNI' => '[text]', + 'TIMESTAMP' => '[int]', + 'DECIMAL' => '[float]', + 'DECIMAL:' => '[float]', + 'PDECIMAL' => '[float]', + 'PDECIMAL:' => '[float]', + 'VCHAR_UNI' => '[varchar] (255)', + 'VCHAR_UNI:'=> '[varchar] (%d)', + 'VCHAR_CI' => '[varchar] (255)', + 'VARBINARY' => '[varchar] (255)', + ), + 'oracle' => array( 'INT:' => 'number(%d)', 'BINT' => 'number(20)', @@ -261,7 +291,7 @@ class phpbb_db_tools * A list of supported DBMS. We change this class to support more DBMS, the DBMS itself only need to follow some rules. * @var array */ - var $supported_dbms = array('firebird', 'mssql', 'mysql_40', 'mysql_41', 'oracle', 'postgres', 'sqlite'); + var $supported_dbms = array('firebird', 'mssql', 'mssqlnative', 'mysql_40', 'mysql_41', 'oracle', 'postgres', 'sqlite'); /** * This is set to true if user only wants to return the 'to-be-executed' SQL statement(s) (as an array). @@ -307,6 +337,10 @@ class phpbb_db_tools $this->sql_layer = 'mssql'; break; + case 'mssqlnative': + $this->sql_layer = 'mssqlnative'; + break; + default: $this->sql_layer = $this->db->sql_layer; break; @@ -368,6 +402,7 @@ class phpbb_db_tools switch ($this->sql_layer) { case 'mssql': + case 'mssqlnative': $table_sql = 'CREATE TABLE [' . $table_name . '] (' . "\n"; break; @@ -386,6 +421,7 @@ class phpbb_db_tools switch ($this->sql_layer) { case 'mssql': + case 'mssqlnative': $columns[] = "\t [{$column_name}] " . $prepared_column['column_type_sql_default']; break; @@ -425,6 +461,7 @@ class phpbb_db_tools break; case 'mssql': + case 'mssqlnative': $table_sql .= "\n) ON [PRIMARY]" . (($create_textimage) ? ' TEXTIMAGE_ON [PRIMARY]' : ''); $statements[] = $table_sql; break; @@ -453,6 +490,7 @@ class phpbb_db_tools case 'firebird': case 'mssql': + case 'mssqlnative': // We need the data here $old_return_statements = $this->return_statements; $this->return_statements = true; @@ -970,6 +1008,7 @@ class phpbb_db_tools // same deal with PostgreSQL, we must perform more complex operations than // we technically could case 'mssql': + case 'mssqlnative': $sql = "SELECT c.name FROM syscolumns c LEFT JOIN sysobjects o ON c.id = o.id @@ -1187,6 +1226,7 @@ class phpbb_db_tools break; case 'mssql': + case 'mssqlnative': $sql .= " {$column_type} "; $sql_default = " {$column_type} "; @@ -1335,6 +1375,7 @@ class phpbb_db_tools break; case 'mssql': + case 'mssqlnative': $statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default']; break; @@ -1348,7 +1389,29 @@ class phpbb_db_tools break; case 'postgres': - $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql']; + if (version_compare($this->db->sql_server_info(true), '8.0', '>=')) + { + $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql']; + } + else + { + // old versions cannot add columns with default and null information + $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type'] . ' ' . $column_data['constraint']; + + if (isset($column_data['null'])) + { + if ($column_data['null'] == 'NOT NULL') + { + $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET NOT NULL'; + } + } + + if (isset($column_data['default'])) + { + $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default']; + } + } + break; case 'sqlite': @@ -1433,6 +1496,7 @@ class phpbb_db_tools break; case 'mssql': + case 'mssqlnative': $statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']'; break; @@ -1527,6 +1591,7 @@ class phpbb_db_tools switch ($this->sql_layer) { case 'mssql': + case 'mssqlnative': $statements[] = 'DROP INDEX ' . $table_name . '.' . $index_name; break; @@ -1630,6 +1695,7 @@ class phpbb_db_tools break; case 'mssql': + case 'mssqlnative': $sql = "ALTER TABLE [{$table_name}] WITH NOCHECK ADD "; $sql .= "CONSTRAINT [PK_{$table_name}] PRIMARY KEY CLUSTERED ("; $sql .= '[' . implode("],\n\t\t[", $column) . ']'; @@ -1723,6 +1789,7 @@ class phpbb_db_tools break; case 'mssql': + case 'mssqlnative': $statements[] = 'CREATE UNIQUE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ') ON [PRIMARY]'; break; } @@ -1752,6 +1819,7 @@ class phpbb_db_tools break; case 'mssql': + case 'mssqlnative': $statements[] = 'CREATE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ') ON [PRIMARY]'; break; } @@ -1769,7 +1837,7 @@ class phpbb_db_tools { $index_array = array(); - if ($this->sql_layer == 'mssql') + if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative') { $sql = "EXEC sp_statistics '$table_name'"; $result = $this->db->sql_query($sql); @@ -1878,6 +1946,7 @@ class phpbb_db_tools break; case 'mssql': + case 'mssqlnative': $statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql']; if (!empty($column_data['default'])) diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php index a962696bb8..eeddf1f41b 100644 --- a/phpBB/includes/db/dbal.php +++ b/phpBB/includes/db/dbal.php @@ -430,6 +430,24 @@ class dbal } /** + * Run binary OR operator on DB column. + * Results in sql statement: "{$column_name} | (1 << {$bit}) {$compare}" + * + * @param string $column_name The column name to use + * @param int $bit The value to use for the OR operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29 + * @param string $compare Any custom SQL code after the check (for example "= 0") + */ + function sql_bit_or($column_name, $bit, $compare = '') + { + if (method_exists($this, '_sql_bit_or')) + { + return $this->_sql_bit_or($column_name, $bit, $compare); + } + + return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); + } + + /** * Run more than one insert statement. * * @param string $table table name to run the statements on diff --git a/phpBB/includes/db/firebird.php b/phpBB/includes/db/firebird.php index fb1ef44c55..e554b0f2fb 100644 --- a/phpBB/includes/db/firebird.php +++ b/phpBB/includes/db/firebird.php @@ -451,6 +451,11 @@ class dbal_firebird extends dbal return 'BIN_AND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); } + function _sql_bit_or($column_name, $bit, $compare = '') + { + return 'BIN_OR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); + } + /** * return sql error array * @access private diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php new file mode 100644 index 0000000000..08ee70907c --- /dev/null +++ b/phpBB/includes/db/mssqlnative.php @@ -0,0 +1,610 @@ +<?php +/** +* +* @package dbal +* @version $Id$ +* @copyright (c) 2010 phpBB Group +* @license http://opensource.org/licenses/gpl-license.php GNU Public License +* +* This is the MS SQL Server Native database abstraction layer. +* PHP mssql native driver required. +* @author Chris Pucci +* +*/ + +/** +* @ignore +*/ +if (!defined('IN_PHPBB')) +{ + exit; +} + +include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); + +/** + * Prior to version 1.1 the SQL Server Native PHP driver didn't support sqlsrv_num_rows, or cursor based seeking so we recall all rows into an array + * and maintain our own cursor index into that array. + */ +class result_mssqlnative +{ + public function result_mssqlnative($queryresult = false) + { + $this->m_cursor = 0; + $this->m_rows = array(); + $this->m_num_fields = sqlsrv_num_fields($queryresult); + $this->m_field_meta = sqlsrv_field_metadata($queryresult); + + while ($row = sqlsrv_fetch_array($queryresult, SQLSRV_FETCH_ASSOC)) + { + if ($row !== null) + { + foreach($row as $k => $v) + { + if (is_object($v) && method_exists($v, 'format')) + { + $row[$k] = $v->format("Y-m-d\TH:i:s\Z"); + } + } + $this->m_rows[] = $row;//read results into memory, cursors are not supported + } + } + + $this->m_row_count = count($this->m_rows); + sqlsrv_free_stmt($queryresult); + } + + private function array_to_obj($array, &$obj) + { + foreach ($array as $key => $value) + { + if (is_array($value)) + { + $obj->$key = new stdClass(); + array_to_obj($value, $obj->$key); + } + else + { + $obj->$key = $value; + } + } + return $obj; + } + + public function fetch($mode = SQLSRV_FETCH_BOTH, $object_class = 'stdClass') + { + if ($this->m_cursor >= $this->m_row_count || $this->m_row_count == 0) + { + return false; + } + + $ret = false; + $arr_num = array(); + + if ($mode == SQLSRV_FETCH_NUMERIC || $mode == SQLSRV_FETCH_BOTH) + { + foreach($this->m_rows[$this->m_cursor] as $key => $value) + { + $arr_num[] = $value; + } + } + + switch ($mode) + { + case SQLSRV_FETCH_ASSOC: + $ret = $this->m_rows[$this->m_cursor]; + break; + case SQLSRV_FETCH_NUMERIC: + $ret = $arr_num; + break; + case 'OBJECT': + $ret = $this->array_to_obj($this->m_rows[$this->m_cursor], $o = new $object_class); + break; + case SQLSRV_FETCH_BOTH: + default: + $ret = $this->m_rows[$this->m_cursor] + $arr_num; + break; + } + $this->m_cursor++; + return $ret; + } + + public function get($pos, $fld) + { + return $this->m_rows[$pos][$fld]; + } + + public function num_rows() + { + return $this->m_row_count; + } + + public function seek($iRow) + { + $this->m_cursor = min($iRow, $this->m_row_count); + } + + public function num_fields() + { + return $this->m_num_fields; + } + + public function field_name($nr) + { + $arr_keys = array_keys($this->m_rows[0]); + return $arr_keys[$nr]; + } + + public function field_type($nr) + { + $i = 0; + $int_type = -1; + $str_type = ''; + + foreach ($this->m_field_meta as $meta) + { + if ($nr == $i) + { + $int_type = $meta['Type']; + break; + } + $i++; + } + + //http://msdn.microsoft.com/en-us/library/cc296183.aspx contains type table + switch ($int_type) + { + case SQLSRV_SQLTYPE_BIGINT: $str_type = 'bigint'; break; + case SQLSRV_SQLTYPE_BINARY: $str_type = 'binary'; break; + case SQLSRV_SQLTYPE_BIT: $str_type = 'bit'; break; + case SQLSRV_SQLTYPE_CHAR: $str_type = 'char'; break; + case SQLSRV_SQLTYPE_DATETIME: $str_type = 'datetime'; break; + case SQLSRV_SQLTYPE_DECIMAL/*($precision, $scale)*/: $str_type = 'decimal'; break; + case SQLSRV_SQLTYPE_FLOAT: $str_type = 'float'; break; + case SQLSRV_SQLTYPE_IMAGE: $str_type = 'image'; break; + case SQLSRV_SQLTYPE_INT: $str_type = 'int'; break; + case SQLSRV_SQLTYPE_MONEY: $str_type = 'money'; break; + case SQLSRV_SQLTYPE_NCHAR/*($charCount)*/: $str_type = 'nchar'; break; + case SQLSRV_SQLTYPE_NUMERIC/*($precision, $scale)*/: $str_type = 'numeric'; break; + case SQLSRV_SQLTYPE_NVARCHAR/*($charCount)*/: $str_type = 'nvarchar'; break; + case SQLSRV_SQLTYPE_NTEXT: $str_type = 'ntext'; break; + case SQLSRV_SQLTYPE_REAL: $str_type = 'real'; break; + case SQLSRV_SQLTYPE_SMALLDATETIME: $str_type = 'smalldatetime'; break; + case SQLSRV_SQLTYPE_SMALLINT: $str_type = 'smallint'; break; + case SQLSRV_SQLTYPE_SMALLMONEY: $str_type = 'smallmoney'; break; + case SQLSRV_SQLTYPE_TEXT: $str_type = 'text'; break; + case SQLSRV_SQLTYPE_TIMESTAMP: $str_type = 'timestamp'; break; + case SQLSRV_SQLTYPE_TINYINT: $str_type = 'tinyint'; break; + case SQLSRV_SQLTYPE_UNIQUEIDENTIFIER: $str_type = 'uniqueidentifier'; break; + case SQLSRV_SQLTYPE_UDT: $str_type = 'UDT'; break; + case SQLSRV_SQLTYPE_VARBINARY/*($byteCount)*/: $str_type = 'varbinary'; break; + case SQLSRV_SQLTYPE_VARCHAR/*($charCount)*/: $str_type = 'varchar'; break; + case SQLSRV_SQLTYPE_XML: $str_type = 'xml'; break; + default: $str_type = $int_type; + } + return $str_type; + } + + public function free() + { + unset($this->m_rows); + return; + } +} + +/** +* @package dbal +*/ +class dbal_mssqlnative extends dbal +{ + var $m_insert_id = NULL; + var $last_query_text = ''; + + /** + * Connect to server + */ + function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) + { + # Test for driver support, to avoid suppressed fatal error + if (!function_exists('sqlsrv_connect')) + { + trigger_error('Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx\n', E_USER_ERROR); + } + + //set up connection variables + $this->persistency = $persistency; + $this->user = $sqluser; + $this->dbname = $database; + $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':'; + $this->server = $sqlserver . (($port) ? $port_delimiter . $port : ''); + + //connect to database + error_reporting(E_ALL); + $this->db_connect_id = sqlsrv_connect($this->server, array( + 'Database' => $this->dbname, + 'UID' => $this->user, + 'PWD' => $sqlpassword + )); + + return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); + } + + /** + * Version information about used database + * @param bool $raw if true, only return the fetched sql_server_version + * @return string sql server version + */ + function sql_server_info($raw = false) + { + global $cache; + + if (empty($cache) || ($this->sql_server_version = $cache->get('mssql_version')) === false) + { + $arr_server_info = sqlsrv_server_info($this->db_connect_id); + $this->sql_server_version = $arr_server_info['SQLServerVersion']; + + if (!empty($cache)) + { + $cache->put('mssql_version', $this->sql_server_version); + } + } + + if ($raw) + { + return $this->sql_server_version; + } + + return ($this->sql_server_version) ? 'MSSQL<br />' . $this->sql_server_version : 'MSSQL'; + } + + /** + * SQL Transaction + * @access private + */ + function _sql_transaction($status = 'begin') + { + switch ($status) + { + case 'begin': + return sqlsrv_begin_transaction($this->db_connect_id); + break; + + case 'commit': + return sqlsrv_commit($this->db_connect_id); + break; + + case 'rollback': + return sqlsrv_rollback($this->db_connect_id); + break; + } + return true; + } + + /** + * Base query method + * + * @param string $query Contains the SQL query which shall be executed + * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache + * @return mixed When casted to bool the returned value returns true on success and false on failure + * + * @access public + */ + function sql_query($query = '', $cache_ttl = 0) + { + if ($query != '') + { + global $cache; + + // EXPLAIN only in extra debug mode + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('start', $query); + } + + $this->last_query_text = $query; + $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; + $this->sql_add_num_queries($this->query_result); + + if ($this->query_result === false) + { + if (($this->query_result = @sqlsrv_query($this->db_connect_id, $query)) === false) + { + $this->sql_error($query); + } + + if (defined('DEBUG_EXTRA')) + { + $this->sql_report('stop', $query); + } + + if ($cache_ttl && method_exists($cache, 'sql_save')) + { + $this->open_queries[(int) $this->query_result] = $this->query_result; + $cache->sql_save($query, $this->query_result, $cache_ttl); + } + else if (strpos($query, 'SELECT') === 0 && $this->query_result) + { + $this->open_queries[(int) $this->query_result] = $this->query_result; + } + } + else if (defined('DEBUG_EXTRA')) + { + $this->sql_report('fromcache', $query); + } + } + else + { + return false; + } + return $this->query_result; + } + + /** + * Build LIMIT query + */ + function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) + { + $this->query_result = false; + + if ($offset === false || $offset == 0) + { + if (strpos($query, "SELECT") === false) + { + $query = "TOP {$total} " . $query; + } + else + { + $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP '.$total, $query); + } + } + else + { + $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP(10000000) ', $query); + $query = 'SELECT * + FROM (SELECT sub2.*, ROW_NUMBER() OVER(ORDER BY sub2.line2) AS line3 + FROM (SELECT 1 AS line2, sub1.* FROM (' . $query . ') AS sub1) as sub2) AS sub3 + WHERE line3 BETWEEN ' . ($offset+1) . ' AND ' . ($offset + $total); + } + + $result = $this->sql_query($query, $cache_ttl); + + return $result; + } + + /** + * Return number of affected rows + */ + function sql_affectedrows() + { + return ($this->db_connect_id) ? @sqlsrv_rows_affected($this->db_connect_id) : false; + } + + /** + * Fetch current row + */ + function sql_fetchrow($query_id = false) + { + global $cache; + + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if (isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_fetchrow($query_id); + } + + if ($query_id === false) + { + return false; + } + + $row = @sqlsrv_fetch_array($query_id, SQLSRV_FETCH_ASSOC); + + // I hope i am able to remove this later... hopefully only a PHP or MSSQL bug + if ($row) + { + foreach ($row as $key => $value) + { + $row[$key] = ($value === ' ' || $value === NULL) ? '' : $value; + } + } + return $row; + } + + /** + * Seek to given row number + * rownum is zero-based + */ + function sql_rowseek($rownum, &$query_id) + { + global $cache; + + if (isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_rowseek($rownum, $query_id); + } + + $seek = new result_mssqlnative($query_id); + $row = $seek->seek($rownum); + return ($row = $seek->fetch()) ? $row : false; + } + + /** + * Get last inserted id after insert statement + */ + function sql_nextid() + { + $result_id = @sqlsrv_query($this->db_connect_id, 'SELECT @@IDENTITY'); + + if ($result_id !== false) + { + $row = @sqlsrv_fetch_array($result_id); + $id = $row[0]; + @sqlsrv_free_stmt($result_id); + return $id; + } + else + { + return false; + } + } + + /** + * Free sql result + */ + function sql_freeresult($query_id = false) + { + global $cache; + + if ($query_id === false) + { + $query_id = $this->query_result; + } + + if (isset($cache->sql_rowset[$query_id])) + { + return $cache->sql_freeresult($query_id); + } + + if (isset($this->open_queries[$query_id])) + { + unset($this->open_queries[$query_id]); + return @sqlsrv_free_stmt($query_id); + } + return false; + } + + /** + * Escape string used in sql query + */ + function sql_escape($msg) + { + return str_replace(array("'", "\0"), array("''", ''), $msg); + } + + /** + * Build LIKE expression + * @access private + */ + function _sql_like_expression($expression) + { + return $expression . " ESCAPE '\\'"; + } + + /** + * return sql error array + * @access private + */ + function _sql_error() + { + $errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS); + $error_message = ''; + + if ($errors != null) + { + foreach ($errors as $error) + { + $error_message .= "SQLSTATE: ".$error[ 'SQLSTATE']."\n"; + $error_message .= "code: ".$error[ 'code']."\n"; + $error_message .= "message: ".$error[ 'message']."\n"; + } + $this->last_error_result = $error_message; + $error = $this->last_error_result; + } + else + { + $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); + } + return $error; + } + + /** + * Build db-specific query data + * @access private + */ + function _sql_custom_build($stage, $data) + { + return $data; + } + + /** + * Close sql connection + * @access private + */ + function _sql_close() + { + return @sqlsrv_close($this->db_connect_id); + } + + /** + * Build db-specific report + * @access private + */ + function _sql_report($mode, $query = '') + { + switch ($mode) + { + case 'start': + $html_table = false; + @sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT ON;'); + if ($result = @sqlsrv_query($this->db_connect_id, $query)) + { + @sqlsrv_next_result($result); + while ($row = @sqlsrv_fetch_array($result)) + { + $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); + } + } + @sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT OFF;'); + @sqlsrv_free_stmt($result); + + if ($html_table) + { + $this->html_hold .= '</table>'; + } + break; + + case 'fromcache': + $endtime = explode(' ', microtime()); + $endtime = $endtime[0] + $endtime[1]; + + $result = @sqlsrv_query($this->db_connect_id, $query); + while ($void = @sqlsrv_fetch_array($result)) + { + // Take the time spent on parsing rows into account + } + @sqlsrv_free_stmt($result); + + $splittime = explode(' ', microtime()); + $splittime = $splittime[0] + $splittime[1]; + + $this->sql_report('record_fromcache', $query, $endtime, $splittime); + + break; + } + } + + /** + * Utility method used to retrieve number of rows + * Emulates mysql_num_rows + * Used in acp_database.php -> write_data_mssqlnative() + */ + function mssqlnative_num_rows($res) + { + if ($res !== false) + { + $row = new result_mssqlnative($res); + $num_rows = $row->num_rows(); + return $num_rows; + } + else + { + return false; + } + } +} + +?>
\ No newline at end of file diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php index c03b38708c..0487dfa6d2 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/mysql.php @@ -44,7 +44,7 @@ class dbal_mysql extends dbal $this->sql_layer = 'mysql4'; - $this->db_connect_id = ($this->persistency) ? @mysql_pconnect($this->server, $this->user, $sqlpassword, $new_link) : @mysql_connect($this->server, $this->user, $sqlpassword, $new_link); + $this->db_connect_id = ($this->persistency) ? @mysql_pconnect($this->server, $this->user, $sqlpassword) : @mysql_connect($this->server, $this->user, $sqlpassword, $new_link); if ($this->db_connect_id && $this->dbname != '') { diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php index 63cdb7126d..55b3599800 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/oracle.php @@ -622,6 +622,11 @@ class dbal_oracle extends dbal return 'BITAND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); } + function _sql_bit_or($column_name, $bit, $compare = '') + { + return 'BITOR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); + } + /** * return sql error array * @access private diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 396267432a..38f910974a 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -202,7 +202,7 @@ function set_config_count($config_name, $increment, $is_dynamic = false) function gen_rand_string($num_chars = 8) { $rand_str = unique_id(); - $rand_str = str_replace('0', 'Z', strtoupper(base_convert($rand_str, 16, 35))); + $rand_str = str_replace(array('0', 'O'), array('Z', 'Y'), strtoupper(base_convert($rand_str, 16, 34))); return substr($rand_str, 0, $num_chars); } @@ -556,11 +556,11 @@ function _hash_crypt_private($password, $setting, &$itoa64) * * @param string $email Email address * -* @return string Big Integer +* @return string Unsigned Big Integer */ function phpbb_email_hash($email) { - return crc32(strtolower($email)) . strlen($email); + return sprintf('%u', crc32(strtolower($email))) . strlen($email); } /** @@ -2336,6 +2336,19 @@ function redirect($url, $return = false, $disable_cd_check = false) // Relative uri $pathinfo = pathinfo($url); + if (!$disable_cd_check && !file_exists($pathinfo['dirname'])) + { + $url = str_replace('../', '', $url); + $pathinfo = pathinfo($url); + + if (!file_exists($pathinfo['dirname'])) + { + // fallback to "last known user page" + $url = generate_board_url() . '/' . $user->page['page']; + break; + } + } + // Is the uri pointing to the current directory? if ($pathinfo['dirname'] == '.') { @@ -3531,7 +3544,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline) } } - if (defined('DEBUG') || defined('IN_CRON') || defined('IMAGE_OUTPUT')) + if ((defined('DEBUG') || defined('IN_CRON') || defined('IMAGE_OUTPUT')) && isset($db)) { // let's avoid loops $db->sql_return_on_error(true); @@ -3921,6 +3934,108 @@ function phpbb_optionset($bit, $set, $data) } /** +* Login using http authenticate. +* +* @param array $param Parameter array, see $param_defaults array. +* +* @return void +*/ +function phpbb_http_login($param) +{ + global $auth, $user; + global $config; + + $param_defaults = array( + 'auth_message' => '', + + 'autologin' => false, + 'viewonline' => true, + 'admin' => false, + ); + + // Overwrite default values with passed values + $param = array_merge($param_defaults, $param); + + // User is already logged in + // We will not overwrite his session + if (!empty($user->data['is_registered'])) + { + return; + } + + // $_SERVER keys to check + $username_keys = array( + 'PHP_AUTH_USER', + 'Authorization', + 'REMOTE_USER', 'REDIRECT_REMOTE_USER', + 'HTTP_AUTHORIZATION', 'REDIRECT_HTTP_AUTHORIZATION', + 'REMOTE_AUTHORIZATION', 'REDIRECT_REMOTE_AUTHORIZATION', + 'AUTH_USER', + ); + + $password_keys = array( + 'PHP_AUTH_PW', + 'REMOTE_PASSWORD', + 'AUTH_PASSWORD', + ); + + $username = null; + foreach ($username_keys as $k) + { + if (isset($_SERVER[$k])) + { + $username = $_SERVER[$k]; + break; + } + } + + $password = null; + foreach ($password_keys as $k) + { + if (isset($_SERVER[$k])) + { + $password = $_SERVER[$k]; + break; + } + } + + // Decode encoded information (IIS, CGI, FastCGI etc.) + if (!is_null($username) && is_null($password) && strpos($username, 'Basic ') === 0) + { + list($username, $password) = explode(':', base64_decode(substr($username, 6)), 2); + } + + if (!is_null($username) && !is_null($password)) + { + set_var($username, $username, 'string', true); + set_var($password, $password, 'string', true); + + $auth_result = $auth->login($username, $password, $param['autologin'], $param['viewonline'], $param['admin']); + + if ($auth_result['status'] == LOGIN_SUCCESS) + { + return; + } + else if ($auth_result['status'] == LOGIN_ERROR_ATTEMPTS) + { + header('HTTP/1.0 401 Unauthorized'); + trigger_error('NOT_AUTHORISED'); + } + } + + // Prepend sitename to auth_message + $param['auth_message'] = ($param['auth_message'] === '') ? $config['sitename'] : $config['sitename'] . ' - ' . $param['auth_message']; + + // We should probably filter out non-ASCII characters - RFC2616 + $param['auth_message'] = preg_replace('/[\x80-\xFF]/', '?', $param['auth_message']); + + header('WWW-Authenticate: Basic realm="' . $param['auth_message'] . '"'); + header('HTTP/1.0 401 Unauthorized'); + + trigger_error('NOT_AUTHORISED'); +} + +/** * Generate page header */ function page_header($page_title = '', $display_online_list = true, $item_id = 0, $item = 'forum') @@ -4139,8 +4254,10 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 'S_LOGIN_REDIRECT' => build_hidden_fields(array('redirect' => str_replace('&', '&', build_url()))), 'S_ENABLE_FEEDS' => ($config['feed_enable']) ? true : false, + 'S_ENABLE_FEEDS_OVERALL' => ($config['feed_overall']) ? true : false, 'S_ENABLE_FEEDS_FORUMS' => ($config['feed_overall_forums']) ? true : false, - 'S_ENABLE_FEEDS_TOPICS' => ($config['feed_overall_topics']) ? true : false, + 'S_ENABLE_FEEDS_TOPICS' => ($config['feed_topics_new']) ? true : false, + 'S_ENABLE_FEEDS_TOPICS_ACTIVE' => ($config['feed_topics_active']) ? true : false, 'S_ENABLE_FEEDS_NEWS' => ($s_feed_news) ? true : false, 'T_THEME_PATH' => "{$web_path}styles/" . $user->theme['theme_path'] . '/theme', diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index ddadda8ed2..93244be55c 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -66,8 +66,6 @@ function make_forum_select($select_id = false, $ignore_id = false, $ignore_acl = { global $db, $user, $auth; - $acl = ($ignore_acl) ? '' : (($only_acl_post) ? 'f_post' : array('f_list', 'a_forum', 'a_forumadd', 'a_forumdel')); - // This query is identical to the jumpbox one $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, forum_flags, forum_options, left_id, right_id FROM ' . FORUMS_TABLE . ' @@ -98,18 +96,21 @@ function make_forum_select($select_id = false, $ignore_id = false, $ignore_acl = $right = $row['right_id']; $disabled = false; - if ($acl && !$auth->acl_gets($acl, $row['forum_id'])) + if (!$ignore_acl && $auth->acl_get('f_list', $row['forum_id'])) { - // List permission? - if ($auth->acl_get('f_list', $row['forum_id'])) + if ($only_acl_post && !$auth->acl_get('f_post', $row['forum_id']) || (!$auth->acl_get('m_approve', $row['forum_id']) && !$auth->acl_get('f_noapprove', $row['forum_id']))) { $disabled = true; } - else + else if (!$only_acl_post && !$auth->acl_gets(array('f_list', 'a_forum', 'a_forumadd', 'a_forumdel'), $row['forum_id'])) { - continue; + $disabled = true; } } + else if (!$ignore_acl) + { + continue; + } if ( ((is_array($ignore_id) && in_array($row['forum_id'], $ignore_id)) || $row['forum_id'] == $ignore_id) @@ -912,7 +913,13 @@ function delete_attachments($mode, $ids, $resync = true) { global $db, $config; - if (is_array($ids) && sizeof($ids)) + // 0 is as bad as an empty array + if (empty($ids)) + { + return false; + } + + if (is_array($ids)) { $ids = array_unique($ids); $ids = array_map('intval', $ids); @@ -922,11 +929,6 @@ function delete_attachments($mode, $ids, $resync = true) $ids = array((int) $ids); } - if (!sizeof($ids)) - { - return false; - } - $sql_where = ''; switch ($mode) @@ -3040,6 +3042,7 @@ function get_database_size() case 'mssql': case 'mssql_odbc': + case 'mssqlnative': $sql = 'SELECT ((SUM(size) * 8.0) * 1024.0) as dbsize FROM sysfiles'; $result = $db->sql_query($sql, 7200); @@ -3307,4 +3310,24 @@ function obtain_latest_version_info($force_update = false, $warn_fail = false, $ return $info; } +/** + * Enables a particular flag in a bitfield column of a given table. + * + * @param string $table_name The table to update + * @param string $column_name The column containing a bitfield to update + * @param int $flag The binary flag which is OR-ed with the current column value + * @param string $sql_more This string is attached to the sql query generated to update the table. + * + * @return void + */ +function enable_bitfield_column_flag($table_name, $column_name, $flag, $sql_more = '') +{ + global $db; + + $sql = 'UPDATE ' . $table_name . ' + SET ' . $column_name . ' = ' . $db->sql_bit_or($column_name, $flag) . ' + ' . $sql_more; + $db->sql_query($sql); +} + ?>
\ No newline at end of file diff --git a/phpBB/includes/functions_compress.php b/phpBB/includes/functions_compress.php index 590daabf1d..f17c780a65 100644 --- a/phpBB/includes/functions_compress.php +++ b/phpBB/includes/functions_compress.php @@ -80,6 +80,11 @@ class compress } } } + else + { + // $src does not exist + return false; + } return true; } @@ -89,6 +94,11 @@ class compress */ function add_custom_file($src, $filename) { + if (!file_exists($src)) + { + return false; + } + $this->data($filename, file_get_contents($src), false, stat($src)); return true; } diff --git a/phpBB/includes/functions_content.php b/phpBB/includes/functions_content.php index c265d0ae41..faff9dd0de 100644 --- a/phpBB/includes/functions_content.php +++ b/phpBB/includes/functions_content.php @@ -1106,10 +1106,11 @@ function extension_allowed($forum_id, $extension, &$extensions) * @param string $string The text to truncate to the given length. String is specialchared. * @param int $max_length Maximum length of string (multibyte character count as 1 char / Html entity count as 1 char) * @param int $max_store_length Maximum character length of string (multibyte character count as 1 char / Html entity count as entity chars). -* @param bool $allow_reply Allow Re: in front of string +* @param bool $allow_reply Allow Re: in front of string +* NOTE: This parameter can cause undesired behavior (returning strings longer than $max_store_legnth) and is deprecated. * @param string $append String to be appended */ -function truncate_string($string, $max_length = 60, $max_store_length = 255, $allow_reply = true, $append = '') +function truncate_string($string, $max_length = 60, $max_store_length = 255, $allow_reply = false, $append = '') { $chars = array(); diff --git a/phpBB/includes/functions_convert.php b/phpBB/includes/functions_convert.php index 82ec114c09..0fdae9b274 100644 --- a/phpBB/includes/functions_convert.php +++ b/phpBB/includes/functions_convert.php @@ -205,10 +205,12 @@ function get_group_id($group_name) /** * Generate the email hash stored in the users table +* +* Note: Deprecated, calls should directly go to phpbb_email_hash() */ function gen_email_hash($email) { - return (crc32(strtolower($email)) . strlen($email)); + return phpbb_email_hash($email); } /** @@ -1232,6 +1234,11 @@ function get_config() $convert->p_master->error($user->lang['FILE_NOT_FOUND'] . ': ' . $filename, __LINE__, __FILE__); } + if (isset($convert->config_schema['array_name'])) + { + unset($convert->config_schema['array_name']); + } + $convert_config = extract_variables_from_file($filename); if (!empty($convert->config_schema['array_name'])) { @@ -1264,6 +1271,7 @@ function restore_config($schema) global $db, $config; $convert_config = get_config(); + foreach ($schema['settings'] as $config_name => $src) { if (preg_match('/(.*)\((.*)\)/', $src, $m)) @@ -1274,8 +1282,16 @@ function restore_config($schema) } else { - $config_value = (isset($convert_config[$src])) ? $convert_config[$src] : ''; - } + if ($schema['table_format'] != 'file' || empty($schema['array_name'])) + { + $config_value = (isset($convert_config[$src])) ? $convert_config[$src] : ''; + } + else if (!empty($schema['array_name'])) + { + $src_ary = $schema['array_name']; + $config_value = (isset($convert_config[$src_ary][$src])) ? $convert_config[$src_ary][$src] : ''; + } + } if ($config_value !== '') { @@ -1629,6 +1645,7 @@ function mass_auth($ug_type, $forum_id, $ug_id, $acl_list, $setting = ACL_NO) case 'mssql': case 'sqlite': + case 'mssqlnative': $sql = implode(' UNION ALL ', preg_replace('#^(.*?)$#', 'SELECT \1', $sql_subary)); break; diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php index 58cbdaef5b..f49aa42324 100644 --- a/phpBB/includes/functions_display.php +++ b/phpBB/includes/functions_display.php @@ -594,7 +594,7 @@ function generate_forum_nav(&$forum_data) 'FORUM_NAME' => $forum_data['forum_name'], 'FORUM_DESC' => generate_text_for_display($forum_data['forum_desc'], $forum_data['forum_desc_uid'], $forum_data['forum_desc_bitfield'], $forum_data['forum_desc_options']), - 'S_ENABLE_FEEDS_FORUM' => ($config['feed_forum'] && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $forum_data['forum_options'])) ? true : false, + 'S_ENABLE_FEEDS_FORUM' => ($config['feed_forum'] && $forum_data['forum_type'] == FORUM_POST && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $forum_data['forum_options'])) ? true : false, )); return; diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php index a5889224a1..992e8d6bb0 100644 --- a/phpBB/includes/functions_install.php +++ b/phpBB/includes/functions_install.php @@ -23,7 +23,14 @@ function can_load_dll($dll) { // SQLite2 is a tricky thing, from 5.0.0 it requires PDO; if PDO is not loaded we must state that SQLite is unavailable // as the installer doesn't understand that the extension has a prerequisite. - if ($dll == 'sqlite' && version_compare(PHP_VERSION, '5.0.0', '>=') && !extension_loaded('pdo')) + // + // On top of this sometimes the SQLite extension is compiled for a different version of PDO + // by some Linux distributions which causes phpBB to bomb out with a blank page. + // + // Net result we'll disable automatic inclusion of SQLite support + // + // See: r9618 and #56105 + if ($dll == 'sqlite') { return false; } @@ -88,6 +95,16 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'AVAILABLE' => true, '2.0.x' => true, ), + 'mssqlnative' => array( + 'LABEL' => 'MS SQL Server 2005+ [ Native ]', + 'SCHEMA' => 'mssql', + 'MODULE' => 'sqlsrv', + 'DELIM' => 'GO', + 'COMMENTS' => 'remove_comments', + 'DRIVER' => 'mssqlnative', + 'AVAILABLE' => true, + '2.0.x' => false, + ), 'oracle' => array( 'LABEL' => 'Oracle', 'SCHEMA' => 'oracle', @@ -213,6 +230,7 @@ function get_tables($db) case 'mssql': case 'mssql_odbc': + case 'mssqlnative': $sql = "SELECT name FROM sysobjects WHERE type='U'"; @@ -306,6 +324,7 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, case 'mssql': case 'mssql_odbc': + case 'mssqlnative': $prefix_length = 90; break; diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index 8f4e582b3c..99883cd9ca 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -184,6 +184,9 @@ class messenger if (!trim($template_lang)) { + // fall back to board default language if the user's language is + // missing $template_file. If this does not exist either, + // $tpl->set_custom_template will do a trigger_error $template_lang = basename($config['default_lang']); } @@ -193,13 +196,23 @@ class messenger $this->tpl_msg[$template_lang . $template_file] = new template(); $tpl = &$this->tpl_msg[$template_lang . $template_file]; + $fallback_template_path = false; + if (!$template_path) { $template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; $template_path .= $template_lang . '/email'; + + // we can only specify default language fallback when the path is not a custom one for which we + // do not know the default language alternative + if ($template_lang !== basename($config['default_lang'])) + { + $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; + $fallback_template_path .= basename($config['default_lang']) . '/email'; + } } - $tpl->set_custom_template($template_path, $template_lang . '_email', 'email'); + $tpl->set_custom_template($template_path, $template_lang . '_email', $fallback_template_path); $tpl->set_filenames(array( 'body' => $template_file . '.txt', diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index 069740ebda..21c5fe7aca 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -46,7 +46,7 @@ function generate_smilies($mode, $forum_id) page_header($user->lang['SMILIES']); - $sql = 'SELECT COUNT(smiley_id) AS count + $sql = 'SELECT COUNT(smiley_id) AS item_count FROM ' . SMILIES_TABLE . ' GROUP BY smiley_url'; $result = $db->sql_query($sql, 3600); @@ -85,10 +85,10 @@ function generate_smilies($mode, $forum_id) if ($mode == 'window') { - $sql = 'SELECT smiley_url, MIN(emotion) as emotion, MIN(code) AS code, smiley_width, smiley_height + $sql = 'SELECT smiley_url, MIN(emotion) as emotion, MIN(code) AS code, smiley_width, smiley_height, MIN(smiley_order) AS min_smiley_order FROM ' . SMILIES_TABLE . ' GROUP BY smiley_url, smiley_width, smiley_height - ORDER BY smiley_order'; + ORDER BY min_smiley_order'; $result = $db->sql_query_limit($sql, $config['smilies_per_page'], $start, 3600); } else @@ -2525,7 +2525,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u VALUES (' . $user->data['user_id'] . ', ' . $data['topic_id'] . ')'; $db->sql_query($sql); } - else if ($data['notify_set'] && !$data['notify']) + else if (($config['email_enable'] || $config['jab_enable']) && $data['notify_set'] && !$data['notify']) { $sql = 'DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE user_id = ' . $user->data['user_id'] . ' diff --git a/phpBB/includes/mcp/mcp_logs.php b/phpBB/includes/mcp/mcp_logs.php index 429e19b668..6da810a489 100644 --- a/phpBB/includes/mcp/mcp_logs.php +++ b/phpBB/includes/mcp/mcp_logs.php @@ -175,7 +175,7 @@ class mcp_logs $template->assign_vars(array( 'PAGE_NUMBER' => on_page($log_count, $config['topics_per_page'], $start), 'TOTAL' => ($log_count == 1) ? $user->lang['TOTAL_LOG'] : sprintf($user->lang['TOTAL_LOGS'], $log_count), - 'PAGINATION' => generate_pagination($this->u_action . "&$u_sort_param$keywords_param", $log_count, $config['topics_per_page'], $start, true), + 'PAGINATION' => generate_pagination($this->u_action . "&$u_sort_param$keywords_param", $log_count, $config['topics_per_page'], $start), 'L_TITLE' => $user->lang['MCP_LOGS'], diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index 50b05e989f..80c3559649 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -568,7 +568,7 @@ function mcp_move_topic($topic_ids) { $additional_msg = $user->lang['FORUM_NOT_POSTABLE']; } - else if (!$auth->acl_get('f_post', $to_forum_id)) + else if (!$auth->acl_get('f_post', $to_forum_id) || (!$auth->acl_get('m_approve', $to_forum_id) && !$auth->acl_get('f_noapprove', $to_forum_id))) { $additional_msg = $user->lang['USER_CANNOT_POST']; } diff --git a/phpBB/includes/mcp/mcp_notes.php b/phpBB/includes/mcp/mcp_notes.php index 757860e1af..c684eb6f52 100644 --- a/phpBB/includes/mcp/mcp_notes.php +++ b/phpBB/includes/mcp/mcp_notes.php @@ -198,7 +198,7 @@ class mcp_notes $log_data = array(); $log_count = 0; - view_log('user', $log_data, $log_count, $config['posts_per_page'], $start, 0, 0, $user_id, $sql_where, $sql_sort, $keywords); + view_log('user', $log_data, $log_count, $config['topics_per_page'], $start, 0, 0, $user_id, $sql_where, $sql_sort, $keywords); if ($log_count) { @@ -226,8 +226,8 @@ class mcp_notes 'L_TITLE' => $user->lang['MCP_NOTES_USER'], - 'PAGE_NUMBER' => on_page($log_count, $config['posts_per_page'], $start), - 'PAGINATION' => generate_pagination($this->u_action . "&$u_sort_param$keywords_param", $log_count, $config['topics_per_page'], $start, true), + 'PAGE_NUMBER' => on_page($log_count, $config['topics_per_page'], $start), + 'PAGINATION' => generate_pagination($this->u_action . "&$u_sort_param$keywords_param", $log_count, $config['topics_per_page'], $start), 'TOTAL_REPORTS' => ($log_count == 1) ? $user->lang['LIST_REPORT'] : sprintf($user->lang['LIST_REPORTS'], $log_count), 'RANK_TITLE' => $rank_title, diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index abdb839e7b..9779478330 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -106,7 +106,14 @@ function mcp_topic_view($id, $mode, $action) if ($total == -1) { - $total = $topic_info['topic_replies'] + 1; + if ($auth->acl_get('m_approve', $topic_info['forum_id'])) + { + $total = $topic_info['topic_replies_real'] + 1; + } + else + { + $total = $topic_info['topic_replies'] + 1; + } } $posts_per_page = max(0, request_var('posts_per_page', intval($config['posts_per_page']))); diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index 8979511d9a..50aad8588a 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -1284,6 +1284,7 @@ class parse_message extends bbcode_firstpass { case 'mssql': case 'mssql_odbc': + case 'mssqlnative': $sql = 'SELECT * FROM ' . SMILIES_TABLE . ' ORDER BY LEN(code) DESC'; diff --git a/phpBB/includes/questionnaire/questionnaire.php b/phpBB/includes/questionnaire/questionnaire.php index 659c088763..cbd7638809 100644 --- a/phpBB/includes/questionnaire/questionnaire.php +++ b/phpBB/includes/questionnaire/questionnaire.php @@ -162,25 +162,59 @@ class phpbb_questionnaire_system_data_provider $server_address = $_SERVER['LOCAL_ADDR']; } - $ip_address_ary = explode('.', $server_address); - - // build ip - if (!isset($ip_address_ary[0]) || !isset($ip_address_ary[1])) - { - $ip_address_ary = explode('.', '0.0.0.0'); - } - return array( 'os' => PHP_OS, 'httpd' => $_SERVER['SERVER_SOFTWARE'], // we don't want the real IP address (for privacy policy reasons) but only // a network address to see whether your installation is running on a private or public network. + 'private_ip' => $this->is_private_ip($server_address), + 'ipv6' => strpos($server_address, ':') !== false, + ); + } + + /** + * Checks whether the given IP is in a private network. + * + * @param string $ip IP in v4 dot-decimal or v6 hex format + * @return bool true if the IP is from a private network, else false + */ + function is_private_ip($ip) + { + // IPv4 + if (strpos($ip, ':') === false) + { + $ip_address_ary = explode('.', $ip); + + // build ip + if (!isset($ip_address_ary[0]) || !isset($ip_address_ary[1])) + { + $ip_address_ary = explode('.', '0.0.0.0'); + } + // IANA reserved addresses for private networks (RFC 1918) are: // - 10.0.0.0/8 // - 172.16.0.0/12 // - 192.168.0.0/16 - 'ip' => $ip_address_ary[0] . '.' . $ip_address_ary[1] . '.XXX.YYY', - ); + if ($ip_address_ary[0] == '10' || + ($ip_address_ary[0] == '172' && intval($ip_address_ary[1]) > 15 && intval($ip_address_ary[1]) < 32) || + ($ip_address_ary[0] == '192' && $ip_address_ary[1] == '168') || + ($ip_address_ary[0] == '192' && $ip_address_ary[1] == '168')) + { + return true; + } + } + // IPv6 + else + { + // unique local unicast + $prefix = substr($ip, 0, 2); + if ($prefix == 'fc' || $prefix == 'fd') + { + return true; + } + } + + return false; } } @@ -233,6 +267,7 @@ class phpbb_questionnaire_phpbb_data_provider { global $phpbb_root_path, $phpEx; include("{$phpbb_root_path}config.$phpEx"); + unset($dbhost, $dbport, $dbname, $dbuser, $dbpasswd); // Just a precaution // Only send certain config vars $config_vars = array( @@ -315,13 +350,15 @@ class phpbb_questionnaire_phpbb_data_provider 'enable_pm_icons' => true, 'enable_post_confirm' => true, 'feed_enable' => true, - 'feed_limit' => true, + 'feed_http_auth' => true, + 'feed_limit_post' => true, + 'feed_limit_topic' => true, + 'feed_overall' => true, 'feed_overall_forums' => true, - 'feed_overall_forums_limit' => true, - 'feed_overall_topics' => true, - 'feed_overall_topics_limit' => true, 'feed_forum' => true, 'feed_topic' => true, + 'feed_topics_new' => true, + 'feed_topics_active' => true, 'feed_item_statistics' => true, 'flood_interval' => true, 'force_server_vars' => true, @@ -445,10 +482,13 @@ class phpbb_questionnaire_phpbb_data_provider } } + global $db; + $result['dbms'] = $dbms; $result['acm_type'] = $acm_type; $result['load_extensions'] = $load_extensions; $result['user_agent'] = 'Unknown'; + $result['dbms_version'] = $db->sql_server_info(true); // Try to get user agent vendor and version $match = array(); diff --git a/phpBB/includes/search/fulltext_mysql.php b/phpBB/includes/search/fulltext_mysql.php index c72e674011..da3833754e 100644 --- a/phpBB/includes/search/fulltext_mysql.php +++ b/phpBB/includes/search/fulltext_mysql.php @@ -473,7 +473,7 @@ class fulltext_mysql extends search_backend while ($row = $db->sql_fetchrow($result)) { - $id_ary[] = $row[$field]; + $id_ary[] = (int) $row[$field]; } $db->sql_freeresult($result); @@ -650,7 +650,7 @@ class fulltext_mysql extends search_backend while ($row = $db->sql_fetchrow($result)) { - $id_ary[] = $row[$field]; + $id_ary[] = (int) $row[$field]; } $db->sql_freeresult($result); diff --git a/phpBB/includes/search/fulltext_native.php b/phpBB/includes/search/fulltext_native.php index 5af3929ccd..c89e92711e 100644 --- a/phpBB/includes/search/fulltext_native.php +++ b/phpBB/includes/search/fulltext_native.php @@ -202,7 +202,8 @@ class fulltext_native extends search_backend { $sql = 'SELECT word_id, word_text, word_common FROM ' . SEARCH_WORDLIST_TABLE . ' - WHERE ' . $db->sql_in_set('word_text', $exact_words); + WHERE ' . $db->sql_in_set('word_text', $exact_words) . ' + ORDER BY word_count ASC'; $result = $db->sql_query($sql); // store an array of words and ids, remove common words @@ -377,10 +378,6 @@ class fulltext_native extends search_backend return false; } - sort($this->must_contain_ids); - sort($this->must_not_contain_ids); - sort($this->must_exclude_one_ids); - if (!empty($this->search_query)) { return true; @@ -420,11 +417,19 @@ class fulltext_native extends search_backend return false; } + $must_contain_ids = $this->must_contain_ids; + $must_not_contain_ids = $this->must_not_contain_ids; + $must_exclude_one_ids = $this->must_exclude_one_ids; + + sort($must_contain_ids); + sort($must_not_contain_ids); + sort($must_exclude_one_ids); + // generate a search_key from all the options to identify the results $search_key = md5(implode('#', array( - serialize($this->must_contain_ids), - serialize($this->must_not_contain_ids), - serialize($this->must_exclude_one_ids), + serialize($must_contain_ids), + serialize($must_not_contain_ids), + serialize($must_exclude_one_ids), $type, $fields, $terms, @@ -739,7 +744,7 @@ class fulltext_native extends search_backend while ($row = $db->sql_fetchrow($result)) { - $id_ary[] = $row[(($type == 'posts') ? 'post_id' : 'topic_id')]; + $id_ary[] = (int) $row[(($type == 'posts') ? 'post_id' : 'topic_id')]; } $db->sql_freeresult($result); @@ -981,7 +986,7 @@ class fulltext_native extends search_backend while ($row = $db->sql_fetchrow($result)) { - $id_ary[] = $row[$field]; + $id_ary[] = (int) $row[$field]; } $db->sql_freeresult($result); diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index 933bd47347..11f1896332 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -1361,7 +1361,7 @@ class session WHERE user_id = ' . (int) $user_id; $db->sql_query($sql); - // Update last visit info first before deleting sessions + // If the user is logged in, update last visit info first before deleting sessions $sql = 'SELECT session_time, session_page FROM ' . SESSIONS_TABLE . ' WHERE session_user_id = ' . (int) $user_id . ' @@ -1370,10 +1370,13 @@ class session $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_lastvisit = ' . (int) $row['session_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' - WHERE user_id = " . (int) $user_id; - $db->sql_query($sql); + if ($row) + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_lastvisit = ' . (int) $row['session_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "' + WHERE user_id = " . (int) $user_id; + $db->sql_query($sql); + } // Let's also clear any current sessions for the specified user_id // If it's the current user then we'll leave this session intact diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index af5c9d3a47..f1c8094a9b 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -90,7 +90,7 @@ class template * Set custom template location (able to use directory outside of phpBB) * @access public */ - function set_custom_template($template_path, $template_name, $template_mode = 'template') + function set_custom_template($template_path, $template_name, $fallback_template_path = false) { global $phpbb_root_path, $user; @@ -103,13 +103,25 @@ class template $this->root = $template_path; $this->cachepath = $phpbb_root_path . 'cache/ctpl_' . str_replace('_', '-', $template_name) . '_'; - // As the template-engine is used for more than the template (emails, etc.), we should not set $user->theme in all cases, but only on the real template. - if ($template_mode == 'template') + if ($fallback_template_path !== false) { - $user->theme['template_storedb'] = false; - $user->theme['template_inherits_id'] = false; + if (substr($fallback_template_path, -1) == '/') + { + $fallback_template_path = substr($fallback_template_path, 0, -1); + } + + $this->inherit_root = $fallback_template_path; + $this->orig_tpl_inherits_id = true; + } + else + { + $this->orig_tpl_inherits_id = false; } + // the database does not store the path or name of a custom template + // so there is no way we can properly store custom templates there + $this->orig_tpl_storedb = false; + $this->_rootref = &$this->_tpldata['.'][0]; return true; @@ -254,6 +266,12 @@ class template trigger_error("template->_tpl_load(): No file specified for handle $handle", E_USER_ERROR); } + // reload these settings to have the values they had when this object was initialised + // using set_template or set_custom_template, they might otherwise have been overwritten + // by other template class instances in between. + $user->theme['template_storedb'] = $this->orig_tpl_storedb; + $user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id; + $filename = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx; $this->files_template[$handle] = (isset($user->theme['template_id'])) ? $user->theme['template_id'] : 0; diff --git a/phpBB/includes/ucp/ucp_pm_options.php b/phpBB/includes/ucp/ucp_pm_options.php index e80c0672cf..58c2d087c8 100644 --- a/phpBB/includes/ucp/ucp_pm_options.php +++ b/phpBB/includes/ucp/ucp_pm_options.php @@ -637,12 +637,29 @@ function define_action_option($hardcoded, $action_option, $action_lang, $folder) function define_rule_option($hardcoded, $rule_option, $rule_lang, $check_ary) { global $template; + global $module; + + $exclude = array(); + + if (!$module->loaded('zebra', 'friends')) + { + $exclude[RULE_IS_FRIEND] = true; + } + + if (!$module->loaded('zebra', 'foes')) + { + $exclude[RULE_IS_FOE] = true; + } $s_rule_options = ''; if (!$hardcoded) { foreach ($check_ary as $value => $_check) { + if (isset($exclude[$value])) + { + continue; + } $s_rule_options .= '<option value="' . $value . '"' . (($value == $rule_option) ? ' selected="selected"' : '') . '>' . $rule_lang[$value] . '</option>'; } } diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php index e24acd89fc..f4f4abad4a 100644 --- a/phpBB/includes/ucp/ucp_profile.php +++ b/phpBB/includes/ucp/ucp_profile.php @@ -133,7 +133,7 @@ class ucp_profile $message = 'PROFILE_UPDATED'; - if ($config['email_enable'] && $data['email'] != $user->data['user_email'] && $user->data['user_type'] != USER_FOUNDER && ($config['require_activation'] == USER_ACTIVATION_SELF || $config['require_activation'] == USER_ACTIVATION_ADMIN)) + if ($auth->acl_get('u_chgemail') && $config['email_enable'] && $data['email'] != $user->data['user_email'] && $user->data['user_type'] != USER_FOUNDER && ($config['require_activation'] == USER_ACTIVATION_SELF || $config['require_activation'] == USER_ACTIVATION_ADMIN)) { $message = ($config['require_activation'] == USER_ACTIVATION_SELF) ? 'ACCOUNT_EMAIL_CHANGED' : 'ACCOUNT_EMAIL_CHANGED_ADMIN'; diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index 8359c223e0..9656a4a3af 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -333,6 +333,12 @@ class ucp_register trigger_error('NO_USER', E_USER_ERROR); } + // Okay, captcha, your job is done. + if ($config['enable_confirm'] && isset($captcha)) + { + $captcha->reset(); + } + if ($coppa && $config['email_enable']) { $message = $user->lang['ACCOUNT_COPPA']; diff --git a/phpBB/includes/ucp/ucp_remind.php b/phpBB/includes/ucp/ucp_remind.php index df6733d038..f9b792de20 100644 --- a/phpBB/includes/ucp/ucp_remind.php +++ b/phpBB/includes/ucp/ucp_remind.php @@ -77,11 +77,12 @@ class ucp_remind $server_url = generate_board_url(); - $key_len = 54 - strlen($server_url); - $key_len = max(6, $key_len); // we want at least 6 - $key_len = ($config['max_pass_chars']) ? min($key_len, $config['max_pass_chars']) : $key_len; // we want at most $config['max_pass_chars'] - $user_actkey = substr(gen_rand_string(10), 0, $key_len); - $user_password = gen_rand_string(8); + // Make password at least 8 characters long, make it longer if admin wants to. + // gen_rand_string() however has a limit of 12 or 13. + $user_password = gen_rand_string(max(8, rand((int) $config['min_pass_chars'], (int) $config['max_pass_chars']))); + + // For the activation key a random length between 6 and 10 will do. + $user_actkey = gen_rand_string(rand(6, 10)); $sql = 'UPDATE ' . USERS_TABLE . " SET user_newpasswd = '" . $db->sql_escape(phpbb_hash($user_password)) . "', user_actkey = '" . $db->sql_escape($user_actkey) . "' |