diff --git a/phpBB/adm/index.php b/phpBB/adm/index.php index 2c3f9deb6c..b6b251d2fc 100644 --- a/phpBB/adm/index.php +++ b/phpBB/adm/index.php @@ -246,7 +246,7 @@ function h_radio($name, &$input_ary, $input_default = false, $id = false, $key = foreach ($input_ary as $value => $title) { $selected = ($input_default !== false && $value == $input_default) ? ' checked="checked"' : ''; - $html .= ''; + $html .= ' '; $id_assigned = true; } @@ -263,6 +263,12 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars) $tpl = ''; $name = 'config[' . $config_key . ']'; + // Make sure there is no notice printed out for non-existent config options (we simply set them) + if (!isset($new[$config_key])) + { + $new[$config_key] = ''; + } + switch ($tpl_type[0]) { case 'text': @@ -301,7 +307,6 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars) break; case 'select': - case 'select_multiple': case 'custom': $return = ''; @@ -340,21 +345,12 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars) } else { - if ($tpl_type[0] == 'select_multiple') - { - $new[$config_key] = @unserialize(trim($new[$config_key])); - } - $args = array($new[$config_key], $key); } $return = call_user_func_array($call, $args); - if ($tpl_type[0] == 'select_multiple') - { - $tpl = ''; - } - else if ($tpl_type[0] == 'select') + if ($tpl_type[0] == 'select') { $tpl = ''; } diff --git a/phpBB/adm/style/acp_captcha.html b/phpBB/adm/style/acp_captcha.html index 8a067cda66..12f2251ab5 100644 --- a/phpBB/adm/style/acp_captcha.html +++ b/phpBB/adm/style/acp_captcha.html @@ -17,6 +17,10 @@
+
+

{L_REG_LIMIT_EXPLAIN}
+
+

{L_VISUAL_CONFIRM_POST_EXPLAIN}
@@ -25,69 +29,35 @@

{L_VISUAL_CONFIRM_REFRESH_EXPLAIN}
-
+
- -
-

{L_CAPTCHA_GD_EXPLAIN}
-
-
-
-
-

{L_CAPTCHA_GD_FOREGROUND_NOISE_EXPLAIN}
-
-
-
-
-

{L_CAPTCHA_GD_X_GRID_EXPLAIN}
-
-
-
-

{L_CAPTCHA_GD_Y_GRID_EXPLAIN}
-
-
-
-

{L_CAPTCHA_GD_WAVE_EXPLAIN}
-
- -
-
-
-

{L_CAPTCHA_GD_3D_NOISE_EXPLAIN}
-
- -
-
-
-

{L_CAPTCHA_GD_FONTS_EXPLAIN}
-
- - + -
+
+{L_AVAILABLE_CAPTCHAS} +
+

{L_CAPTCHA_SELECT_EXPLAIN}
+
+
+ +
+

{L_CAPTCHA_CONFIGURE_EXPLAIN}
+
-
+ +
{L_PREVIEW} - -
-

{L_WARNING}

-

{L_CAPTCHA_PREVIEW_MSG}

-
- -
-

{L_CAPTCHA_PREVIEW_EXPLAIN}
-
{L_PREVIEW}width="360" height="96" width="320" height="50" id="captcha_preview" />
-
+
+
{L_SUBMIT} -   -   - +   +   {S_FORM_TOKEN}
diff --git a/phpBB/adm/style/acp_forums.html b/phpBB/adm/style/acp_forums.html index 547ac66e3c..937a288cb2 100644 --- a/phpBB/adm/style/acp_forums.html +++ b/phpBB/adm/style/acp_forums.html @@ -217,6 +217,11 @@
+
+

{L_ENABLE_QUICK_REPLY_EXPLAIN}
+
+
+

{L_ENABLE_INDEXING_EXPLAIN}
diff --git a/phpBB/adm/style/acp_forums_copy_perm.html b/phpBB/adm/style/acp_forums_copy_perm.html new file mode 100644 index 0000000000..73d9e70918 --- /dev/null +++ b/phpBB/adm/style/acp_forums_copy_perm.html @@ -0,0 +1,21 @@ + + +
+ +
+

{L_COPY_PERMISSIONS}

+

{L_COPY_PERMISSIONS_EXPLAIN}

+

{L_ACL_LINK}

+
+

{L_COPY_PERMISSIONS_EXPLAIN}
+
+
+
{S_FORM_TOKEN}{S_HIDDEN_FIELDS} +   +
+ +
+ +
+ + diff --git a/phpBB/adm/style/acp_groups.html b/phpBB/adm/style/acp_groups.html index 5df8a16a39..a513e69a8a 100644 --- a/phpBB/adm/style/acp_groups.html +++ b/phpBB/adm/style/acp_groups.html @@ -55,21 +55,29 @@
- {L_GROUP_SETTINGS_SAVE} + {L_GROUP_OPTIONS_SAVE}

{L_GROUP_FOUNDER_MANAGE_EXPLAIN}
-
+
+
+

{L_GROUP_SKIP_AUTH_EXPLAIN}
+
+
-
+

{L_GROUP_RECEIVE_PM_EXPLAIN}
-
+
+
+ +
+ {L_GROUP_SETTINGS_SAVE}

{L_GROUP_MESSAGE_LIMIT_EXPLAIN}
@@ -80,7 +88,7 @@

{L_GROUP_COLOR_EXPLAIN}
-
  [ {L_COLOUR_SWATCH} ]
+
      [ {L_COLOUR_SWATCH} ]
@@ -97,7 +105,7 @@
-
+
@@ -115,7 +123,7 @@
px X px
-
+
@@ -132,7 +140,7 @@
- + @@ -146,11 +154,11 @@
{avatar_row.avatar_column.AVATAR_NAME}
- +
- + @@ -192,7 +200,7 @@ - {leader.USERNAME} + {leader.USERNAME}{leader.USERNAME} {L_YES}{L_NO} {leader.JOINED} {leader.USER_POSTS} @@ -213,7 +221,7 @@ - {member.USERNAME} + {member.USERNAME}{member.USERNAME} {L_YES}{L_NO} {member.JOINED} {member.USER_POSTS} @@ -231,12 +239,12 @@ - +
-

{L_MARK_ALL}{L_UNMARK_ALL}

+

{L_MARK_ALL}{L_UNMARK_ALL}

{L_ADD_USERS}

diff --git a/phpBB/adm/style/acp_icons.html b/phpBB/adm/style/acp_icons.html index 86500ae047..10166fec35 100644 --- a/phpBB/adm/style/acp_icons.html +++ b/phpBB/adm/style/acp_icons.html @@ -243,8 +243,8 @@ {items.EMOTION} - {ICON_MOVE_UP_DISABLED}{ICON_MOVE_UP}  - {ICON_MOVE_DOWN_DISABLED}{ICON_MOVE_DOWN} + {ICON_MOVE_UP_DISABLED}{ICON_MOVE_UP}  + {ICON_MOVE_DOWN_DISABLED}{ICON_MOVE_DOWN}  {ICON_EDIT} {ICON_DELETE} @@ -255,7 +255,7 @@ - +
{PAGINATION}

   

diff --git a/phpBB/adm/style/acp_inactive.html b/phpBB/adm/style/acp_inactive.html index 240cec1643..ca65416421 100644 --- a/phpBB/adm/style/acp_inactive.html +++ b/phpBB/adm/style/acp_inactive.html @@ -12,7 +12,7 @@ @@ -22,8 +22,8 @@ {L_USERNAME} {L_JOINED} {L_INACTIVE_DATE} - {L_INACTIVE_REASON} {L_LAST_VISIT} + {L_INACTIVE_REASON} {L_MARK} @@ -31,11 +31,16 @@ - {inactive.USERNAME} - {inactive.JOINED} - {inactive.INACTIVE_DATE} - {inactive.REASON} - {inactive.LAST_VISIT} + + {inactive.USERNAME_FULL} +
{L_POSTS}: {inactive.POSTS} [{L_SEARCH_USER_POSTS}] + + {inactive.JOINED} + {inactive.INACTIVE_DATE} + {inactive.LAST_VISIT} + + {inactive.REASON} +
{inactive.REMINDED_EXPLAIN}    @@ -46,25 +51,25 @@ -
- {L_DISPLAY_LOG}:  {S_LIMIT_DAYS} {L_SORT_BY}: {S_SORT_KEY} {S_SORT_DIR} - -
-
- +
+ {L_DISPLAY_LOG}:  {S_LIMIT_DAYS} {L_SORT_BY}: {S_SORT_KEY} {S_SORT_DIR} Users per page: + +
+ +
+ + - - -
- - -

{L_MARK_ALL}{L_UNMARK_ALL}

- {S_FORM_TOKEN} -
- + +
+ + +

{L_MARK_ALL}{L_UNMARK_ALL}

+ {S_FORM_TOKEN} +
diff --git a/phpBB/adm/style/acp_logs.html b/phpBB/adm/style/acp_logs.html index 11ab5faa9c..6e93dba940 100644 --- a/phpBB/adm/style/acp_logs.html +++ b/phpBB/adm/style/acp_logs.html @@ -8,12 +8,18 @@
+
+ {L_SEARCH_KEYWORDS}:   +
+ -
+
diff --git a/phpBB/adm/style/install_update.html b/phpBB/adm/style/install_update.html index a5a0f8b5b6..4b89537acb 100644 --- a/phpBB/adm/style/install_update.html +++ b/phpBB/adm/style/install_update.html @@ -219,8 +219,7 @@
{L_FILE_USED}: {new.CUSTOM_ORIGINAL}
- [ {new.L_SHOW_DIFF} - {L_BINARY_FILE} + [{new.L_SHOW_DIFF}]{L_BINARY_FILE}
@@ -243,7 +242,7 @@
{not_modified.DIR_PART}
{not_modified.FILE_PART}

{L_FILE_USED}: {not_modified.CUSTOM_ORIGINAL}
-
[ {not_modified.L_SHOW_DIFF} ]{L_BINARY_FILE}
+
[{not_modified.L_SHOW_DIFF}]{L_BINARY_FILE}
@@ -271,7 +270,7 @@
-
[ {modified.L_SHOW_DIFF} ]{L_BINARY_FILE}
+
[{modified.L_SHOW_DIFF}]{L_BINARY_FILE}
@@ -298,8 +297,7 @@
{L_FILE_USED}: {new_conflict.CUSTOM_ORIGINAL}
- [ {new_conflict.L_SHOW_DIFF} - {L_BINARY_FILE} + [{new_conflict.L_SHOW_DIFF}]{L_BINARY_FILE}
@@ -323,7 +321,7 @@
{L_NUM_CONFLICTS}: {conflict.NUM_CONFLICTS}
- [ {L_DOWNLOAD_CONFLICTS} ]
{L_DOWNLOAD_CONFLICTS_EXPLAIN} + [{L_DOWNLOAD_CONFLICTS}]
{L_DOWNLOAD_CONFLICTS_EXPLAIN} {L_BINARY_FILE}
@@ -396,7 +394,7 @@
{S_HIDDEN_FIELDS} -     +    
@@ -462,7 +460,7 @@
- +
{S_HIDDEN_FIELDS} diff --git a/phpBB/adm/style/install_update_diff.html b/phpBB/adm/style/install_update_diff.html index efbe1d045c..d794c5c516 100644 --- a/phpBB/adm/style/install_update_diff.html +++ b/phpBB/adm/style/install_update_diff.html @@ -28,6 +28,9 @@ function resize_panel() //whatever IE needs to do this } } + +window.onresize = resize_panel; + // ]]> @@ -48,10 +51,7 @@ function resize_panel() div#codepanel { - overflow: auto; width: 100%; - height: 350px; - display: inline-block; } div#codepanel { @@ -59,12 +59,22 @@ div#codepanel { } + +div#diff_content pre { + overflow: auto; + height: 414px; + width: 100% !important; +} + + /** * Unified Diff */ .file { line-height: .7em; + overflow: auto; + height: 414px; } .diff { @@ -203,9 +213,8 @@ table.hrdiff caption span { - - + @@ -220,7 +229,7 @@ table.hrdiff caption span {

{L_SKIP}

-
+
diff --git a/phpBB/adm/style/overall_footer.html b/phpBB/adm/style/overall_footer.html index d5316aae08..8af299ad57 100644 --- a/phpBB/adm/style/overall_footer.html +++ b/phpBB/adm/style/overall_footer.html @@ -2,6 +2,7 @@ +
diff --git a/phpBB/adm/style/overall_header.html b/phpBB/adm/style/overall_header.html index ccf38e49b8..a376884507 100644 --- a/phpBB/adm/style/overall_header.html +++ b/phpBB/adm/style/overall_header.html @@ -194,21 +194,27 @@ function switch_menu() diff --git a/phpBB/adm/style/permission_forum_copy.html b/phpBB/adm/style/permission_forum_copy.html new file mode 100644 index 0000000000..c919310035 --- /dev/null +++ b/phpBB/adm/style/permission_forum_copy.html @@ -0,0 +1,40 @@ + + + + +

{L_ACP_FORUM_PERMISSIONS_COPY}

+ + {L_ACP_FORUM_PERMISSIONS_COPY_EXPLAIN} + + + +
+ {L_LOOK_UP_FORUM} + +
+

{L_COPY_PERMISSIONS_FORUM_FROM_EXPLAIN}
+
+
+
+ +
+ {L_LOOK_UP_FORUM} +

{L_LOOK_UP_FORUMS_EXPLAIN}

+ +
+

{L_COPY_PERMISSIONS_FORUM_TO_EXPLAIN}
+
+
+
+ +
+ {L_SUBMIT} +   + + {S_HIDDEN_FIELDS} + {S_FORM_TOKEN} +
+ + + + diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php index 52c72fc72c..b9017937c8 100644 --- a/phpBB/develop/create_schema_files.php +++ b/phpBB/develop/create_schema_files.php @@ -983,6 +983,7 @@ function get_schema_struct() 'confirm_type' => array('TINT:3', 0), 'code' => array('VCHAR:8', ''), 'seed' => array('UINT:10', 0), + 'attempts' => array('UINT', 0), ), 'PRIMARY_KEY' => array('session_id', 'confirm_id'), 'KEYS' => array( @@ -1072,6 +1073,7 @@ function get_schema_struct() 'forum_last_poster_name'=> array('VCHAR_UNI', ''), 'forum_last_poster_colour'=> array('VCHAR:6', ''), 'forum_flags' => array('TINT:4', 32), + 'forum_options' => array('UINT:20', 0), 'display_subforum_list' => array('BOOL', 1), 'display_on_index' => array('BOOL', 1), 'enable_indexing' => array('BOOL', 1), @@ -1125,6 +1127,7 @@ function get_schema_struct() 'group_id' => array('UINT', NULL, 'auto_increment'), 'group_type' => array('TINT:4', 1), 'group_founder_manage' => array('BOOL', 0), + 'group_skip_auth' => array('BOOL', 0), 'group_name' => array('VCHAR_CI', ''), 'group_desc' => array('TEXT_UNI', ''), 'group_desc_bitfield' => array('VCHAR:255', ''), @@ -1195,6 +1198,7 @@ function get_schema_struct() 'PRIMARY_KEY' => 'log_id', 'KEYS' => array( 'log_type' => array('INDEX', 'log_type'), + 'log_time' => array('INDEX', 'log_time'), 'forum_id' => array('INDEX', 'forum_id'), 'topic_id' => array('INDEX', 'topic_id'), 'reportee_id' => array('INDEX', 'reportee_id'), @@ -1302,6 +1306,7 @@ function get_schema_struct() 'poster_ip' => array('INDEX', 'poster_ip'), 'poster_id' => array('INDEX', 'poster_id'), 'post_approved' => array('INDEX', 'post_approved'), + 'post_username' => array('INDEX', 'post_username'), 'tid_post_time' => array('INDEX', array('topic_id', 'post_time')), ), ); @@ -1329,6 +1334,7 @@ function get_schema_struct() 'message_edit_count' => array('USINT', 0), 'to_address' => array('TEXT_UNI', ''), 'bcc_address' => array('TEXT_UNI', ''), + 'message_reported' => array('BOOL', 0), ), 'PRIMARY_KEY' => 'msg_id', 'KEYS' => array( @@ -1404,6 +1410,7 @@ function get_schema_struct() 'field_validation' => array('VCHAR_UNI:20', ''), 'field_required' => array('BOOL', 0), 'field_show_on_reg' => array('BOOL', 0), + 'field_show_on_vt' => array('BOOL', 0), 'field_show_profile' => array('BOOL', 0), 'field_hide' => array('BOOL', 0), 'field_no_view' => array('BOOL', 0), @@ -1462,6 +1469,7 @@ function get_schema_struct() 'report_id' => array('UINT', NULL, 'auto_increment'), 'reason_id' => array('USINT', 0), 'post_id' => array('UINT', 0), + 'pm_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'user_notify' => array('BOOL', 0), 'report_closed' => array('BOOL', 0), @@ -1469,6 +1477,10 @@ function get_schema_struct() 'report_text' => array('MTEXT_UNI', ''), ), 'PRIMARY_KEY' => 'report_id', + 'KEYS' => array( + 'post_id' => array('INDEX', 'post_id'), + 'pm_id' => array('INDEX', 'pm_id'), + ), ); $schema_data['phpbb_reports_reasons'] = array( @@ -1830,7 +1842,7 @@ function get_schema_struct() 'user_allow_viewonline' => array('BOOL', 1), 'user_allow_viewemail' => array('BOOL', 1), 'user_allow_massemail' => array('BOOL', 1), - 'user_options' => array('UINT:11', 895), + 'user_options' => array('UINT:11', 230271), 'user_avatar' => array('VCHAR', ''), 'user_avatar_type' => array('TINT:2', 0), 'user_avatar_width' => array('USINT', 0), @@ -1850,7 +1862,9 @@ function get_schema_struct() 'user_actkey' => array('VCHAR:32', ''), 'user_newpasswd' => array('VCHAR_UNI:40', ''), 'user_form_salt' => array('VCHAR_UNI:32', ''), - + 'user_new' => array('BOOL', 1), + 'user_reminded' => array('TINT:4', 0), + 'user_reminded_time' => array('TIMESTAMP', 0), ), 'PRIMARY_KEY' => 'user_id', 'KEYS' => array( diff --git a/phpBB/develop/mysql_upgrader.php b/phpBB/develop/mysql_upgrader.php index 77341500e1..034c1c0c20 100644 --- a/phpBB/develop/mysql_upgrader.php +++ b/phpBB/develop/mysql_upgrader.php @@ -40,13 +40,18 @@ $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); -$mysql_indexer = false; +$mysql_indexer = $drop_index = false; if (strtolower($row['Type']) === 'mediumtext') { $mysql_indexer = true; } +if (strtolower($row['Key']) === 'mul') +{ + $drop_index = true; +} + echo "USE $dbname;$newline$newline"; @@ -124,6 +129,13 @@ foreach ($schema_data as $table_name => $table_data) // Create Table statement $generator = $textimage = false; + // Do we need to DROP a fulltext index before we alter the table? + if ($table_name == ($prefix . 'posts') && $drop_index) + { + echo "ALTER TABLE {$table_name}{$newline}"; + echo "DROP INDEX post_text,{$newline}DROP INDEX post_subject,{$newline}DROP INDEX post_content;{$newline}{$newline}"; + } + $line = "ALTER TABLE {$table_name} $newline"; // Table specific so we don't get overlap @@ -236,6 +248,12 @@ foreach ($schema_data as $table_name => $table_data) $line .= "\tDEFAULT CHARSET=utf8 COLLATE=utf8_bin;$newline$newline"; echo $line . "$newline"; + + // Do we now need to re-add the fulltext index? ;) + if ($table_name == ($prefix . 'posts') && $drop_index) + { + echo "ALTER TABLE $table_name ADD FULLTEXT (post_subject), ADD FULLTEXT (post_text), ADD FULLTEXT post_content (post_subject, post_text){$newline}"; + } } /** @@ -455,6 +473,7 @@ function get_schema_struct() 'confirm_type' => array('TINT:3', 0), 'code' => array('VCHAR:8', ''), 'seed' => array('UINT:10', 0), + 'attempts' => array('UINT', 0), ), 'PRIMARY_KEY' => array('session_id', 'confirm_id'), 'KEYS' => array( @@ -544,6 +563,7 @@ function get_schema_struct() 'forum_last_poster_name'=> array('VCHAR_UNI', ''), 'forum_last_poster_colour'=> array('VCHAR:6', ''), 'forum_flags' => array('TINT:4', 32), + 'forum_options' => array('UINT:20', 0), 'display_subforum_list' => array('BOOL', 1), 'display_on_index' => array('BOOL', 1), 'enable_indexing' => array('BOOL', 1), @@ -597,6 +617,7 @@ function get_schema_struct() 'group_id' => array('UINT', NULL, 'auto_increment'), 'group_type' => array('TINT:4', 1), 'group_founder_manage' => array('BOOL', 0), + 'group_skip_auth' => array('BOOL', 0), 'group_name' => array('VCHAR_CI', ''), 'group_desc' => array('TEXT_UNI', ''), 'group_desc_bitfield' => array('VCHAR:255', ''), @@ -667,6 +688,7 @@ function get_schema_struct() 'PRIMARY_KEY' => 'log_id', 'KEYS' => array( 'log_type' => array('INDEX', 'log_type'), + 'log_time' => array('INDEX', 'log_time'), 'forum_id' => array('INDEX', 'forum_id'), 'topic_id' => array('INDEX', 'topic_id'), 'reportee_id' => array('INDEX', 'reportee_id'), @@ -801,6 +823,7 @@ function get_schema_struct() 'message_edit_count' => array('USINT', 0), 'to_address' => array('TEXT_UNI', ''), 'bcc_address' => array('TEXT_UNI', ''), + 'message_reported' => array('BOOL', 0), ), 'PRIMARY_KEY' => 'msg_id', 'KEYS' => array( @@ -876,6 +899,7 @@ function get_schema_struct() 'field_validation' => array('VCHAR_UNI:20', ''), 'field_required' => array('BOOL', 0), 'field_show_on_reg' => array('BOOL', 0), + 'field_show_on_vt' => array('BOOL', 0), 'field_show_profile' => array('BOOL', 0), 'field_hide' => array('BOOL', 0), 'field_no_view' => array('BOOL', 0), @@ -934,6 +958,7 @@ function get_schema_struct() 'report_id' => array('UINT', NULL, 'auto_increment'), 'reason_id' => array('USINT', 0), 'post_id' => array('UINT', 0), + 'pm_id' => array('UINT', 0), 'user_id' => array('UINT', 0), 'user_notify' => array('BOOL', 0), 'report_closed' => array('BOOL', 0), @@ -941,6 +966,10 @@ function get_schema_struct() 'report_text' => array('MTEXT_UNI', ''), ), 'PRIMARY_KEY' => 'report_id', + 'KEYS' => array( + 'post_id' => array('INDEX', 'post_id'), + 'pm_id' => array('INDEX', 'pm_id'), + ), ); $schema_data['phpbb_reports_reasons'] = array( @@ -1302,7 +1331,7 @@ function get_schema_struct() 'user_allow_viewonline' => array('BOOL', 1), 'user_allow_viewemail' => array('BOOL', 1), 'user_allow_massemail' => array('BOOL', 1), - 'user_options' => array('UINT:11', 895), + 'user_options' => array('UINT:11', 230271), 'user_avatar' => array('VCHAR', ''), 'user_avatar_type' => array('TINT:2', 0), 'user_avatar_width' => array('USINT', 0), @@ -1322,7 +1351,9 @@ function get_schema_struct() 'user_actkey' => array('VCHAR:32', ''), 'user_newpasswd' => array('VCHAR_UNI:40', ''), 'user_form_salt' => array('VCHAR_UNI:32', ''), - + 'user_new' => array('BOOL', 1), + 'user_reminded' => array('TINT:4', 0), + 'user_reminded_time' => array('TIMESTAMP', 0), ), 'PRIMARY_KEY' => 'user_id', 'KEYS' => array( diff --git a/phpBB/develop/update_email_hash.php b/phpBB/develop/update_email_hash.php new file mode 100644 index 0000000000..80fd4bbc17 --- /dev/null +++ b/phpBB/develop/update_email_hash.php @@ -0,0 +1,57 @@ +session_begin(); +$auth->acl($user->data); +$user->setup(); + +$start = request_var('start', 0); +$num_items = 1000; + +echo '
Updating user email hashes' . "\n"; + +$sql = 'SELECT user_id, user_email + FROM ' . USERS_TABLE . ' + ORDER BY user_id ASC'; +$result = $db->sql_query($sql); + +$echos = 0; +while ($row = $db->sql_fetchrow($result)) +{ + $echos++; + + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_email_hash = '" . $db->sql_escape(phpbb_email_hash($row['user_email'])) . "' + WHERE user_id = " . (int) $row['user_id']; + $db->sql_query($sql); + + if ($echos == 200) + { + echo '
'; + $echos = 0; + } + + echo '.'; + flush(); +} +$db->sql_freeresult($result); + +echo 'FINISHED'; + +// Done +$db->sql_close(); +?> \ No newline at end of file diff --git a/phpBB/docs/AUTHORS b/phpBB/docs/AUTHORS index 49281e2297..63540ea8a0 100644 --- a/phpBB/docs/AUTHORS +++ b/phpBB/docs/AUTHORS @@ -20,32 +20,39 @@ Please see: http://www.phpbb.com/about/team/ for a list of all the people currently involved in phpBB. -phpBB Lead Developer : Acyd Burn (Meik Sievertsen) +phpBB Lead Developer : Acyd Burn (Meik Sievertsen) -phpBB Developers : APTX (Marek A. R.) - DavidMJ (David M.) - dhn (Dominik Dröscher) - kellanved (Henry Sudhof) - naderman (Nils Adermann) - ToonArmy (Chris Smith) - Vic D'Elfant (Vic D'Elfant) +phpBB Developers : APTX (Marek A. R.) + bantu (Andreas Fischer) + DavidMJ (David M.) + dhn (Dominik Dröscher) + kellanved (Henry Sudhof) + naderman (Nils Adermann) + Terrafrost (Jim Wigginton) + ToonArmy (Chris Smith) + +Contributions by : leviatan21 (Gabriel Vazquez) + nickvergessen (Joas Schilling) + Raimon (Raimon Meuldijk) + rxu (Ruslan Uzdenov) + Xore (Robert Hetzler) -- Previous Contributors -- -phpBB Project Manager : theFinn (James Atkinson) [Founder - 04/2007] - SHS` (Jonathan Stanley) +phpBB Project Manager : theFinn (James Atkinson) [Founder - 04/2007] + SHS` (Jonathan Stanley) -phpBB Lead Developer : psoTFX (Paul S. Owen) [2001 - 09/2005] - -phpBB Developers : Ashe (Ludovic Arnaud) [10/2002 - 11/2003, 06/2006 - 10/2006] - BartVB (Bart van Bragt) [11/2000 - 03/2006] - GrahamJE (Graham Eames) [09/2005 - 11/2006] +phpBB Lead Developer : psoTFX (Paul S. Owen) [2001 - 09/2005] +phpBB Developers : Ashe (Ludovic Arnaud) [10/2002 - 11/2003, 06/2006 - 10/2006] + BartVB (Bart van Bragt) [11/2000 - 03/2006] + GrahamJE (Graham Eames) [09/2005 - 11/2006] + Vic D'Elfant (Vic D'Elfant) [04/2007 - 04/2009] -- Copyrights -- -Visual Confirmation : Xore (Robert Hetzler) +Visual Confirmation : Xore (Robert Hetzler) Original subSilver by subBlue Design, Tom Beddard, (c) 2001 phpBB Group prosilver by subBlue Design, Tom Beddard, (c) 2004 phpBB Group diff --git a/phpBB/docs/CHANGELOG.html b/phpBB/docs/CHANGELOG.html index 60a0b9ddfc..ca791ef155 100644 --- a/phpBB/docs/CHANGELOG.html +++ b/phpBB/docs/CHANGELOG.html @@ -53,6 +53,7 @@
  1. Changelog
      +
    1. Changes since 3.0.5
    2. Changes since 3.0.4
    3. Changes since 3.0.3
    4. Changes since 3.0.2
    5. @@ -84,7 +85,223 @@
      -

      1.i. Changes since 3.0.4

      +

      1.i. Changes since 3.0.5

      + +
        +
      • [Fix] Allow whitespaces in avatar gallery names. (Bug #44955)
      • +
      • [Fix] Sorting by author or subject on viewtopic now preserves the order. (Bug #44875)
      • +
      • [Fix] Correctly determine writable status of files on Windows operating system. (Bug #39035)
      • +
      • [Fix] Show report button in prosilver for guests who are allowed to report posts. (Bug #45695 - Patch by bantu)
      • +
      • [Fix] Correctly show private message history (Bug #46065 - Patch by bantu)
      • +
      • [Fix] Various XHTML mistakes in prosilver, subsilver2 and the ACP. (Bugs #25545 - Patch by bantu, #26315, #38555, #45505 - Patch by Raimon, #45785, #45865, #47085 - Patch by Raimon)
      • +
      • [Fix] Fix some ACP style issues (Bug #45975 - Patch by leviatan21, Bug #16109 - Patch by prototech)
      • +
      • [Fix] Move post bump information markup to the template. (Bug #34295 - Patch by bantu)
      • +
      • [Fix] Show error in the ACP when template folder is not readable. (Bug #45705 - Patch by bantu)
      • +
      • [Fix] Adjust viewonline filename regular expression to be less strict. (Bug #46215 - Patch by bantu)
      • +
      • [Fix] Correctly apply the can change vote permission again. Regression introduced in r9470. (Bug #45895)
      • +
      • [Fix] Also remove data from friend/foe table when deleting user. (Bug #45345 - Patch by nickvergessen)
      • +
      • [Fix] Correctly hide skiplink in prosilver right-to-left mode. (Bug #45765 - Patch by prototech and bantu)
      • +
      • [Fix] Fix dynamic config update routine error if firebird is used (Bug #46315)
      • +
      • [Fix] Allow friends/foes to be added and removed at the same time. (Bug #46255 - Patch by bantu)
      • +
      • [Fix] Only change topic/post icon if icons are enabled and user is allowed to. (Bug #46355 - Patch by bantu)
      • +
      • [Fix] Fix saving custom profile fields in ACP if Oracle is used. (Bug #46015)
      • +
      • [Fix] Make view_log() more resilient to corrupt serialized data. (Bug #46545)
      • +
      • [Fix] Show error if hostname lookup doesn't return a valid IP address when banning. (Bug #45585 - Patch by bantu)
      • +
      • [Fix] Fix incorrect layout when loading private message draft. (Bug #38435 - Patch by nickvergessen)
      • +
      • [Fix] Show proper error message when trying to add bots to friends/foes list. (Bug #40205 - Patch by nickvergessen)
      • +
      • [Fix] Fix Oracle database backup (Bug #46715)
      • +
      • [Fix] Update attachments table when deleting user and retaining his posts. (Bug #40245 - Patch by rxu)
      • +
      • [Fix] Correctly detect files in subfolders when viewing cached template files. (Bug #46145 - Patch by nickvergessen)
      • +
      • [Fix] Display user's Jabber address in popup when Jabber functionality is disabled (Bug #20775 - Patch by nickvergessen)
      • +
      • [Fix] Correctly exclude forums from active topics list. (Bug #19135 - Patch by nickvergessen)
      • +
      • [Fix] Do not display birthdays of banned users (Bug #20625 - Patch by nickvergessen)
      • +
      • [Fix] Fix function to recalculate Nested Sets (Bug #41555 - Patch by EXreaction)
      • +
      • [Fix] Display but also highlight already used rank images when creating new ranks. (Bug #22665 - Patch by nickvergessen)
      • +
      • [Fix] Correctly orientate quoted text image on RTL languages (Bug #33745 - Patch by nickvergessen)
      • +
      • [Fix] Do not display "View user notes" and "Warn user" links in user profile if corresponding MCP modules are disabled. (Bug #10519 - Patch by rxu)
      • +
      • [Fix] Show proper error message when trying to create a private messages folder with an empty name. (Bug #39875 - Patch by nickvergessen)
      • +
      • [Fix] No longer state that it is possible to manage group leaders from the UCP. (Bug #19945 - Patch by nickvergessen)
      • +
      • [Fix] Do not throw an error when PDO is a shared module and not loaded preventing SQLite from being loaded.
      • +
      • [Fix] Fix censoring of unicode words. (Bug #16555 - Patches by rxu)
      • +
      • [Fix] Display coloured usernames in ACP groups management screens
      • +
      • [Fix] Correctly describe founder permissions on trace-information (Bug #37235 - Patch by nickvergessen)
      • +
      • [Fix] Correct the width value for poll_center.gif omitted in imageset.cfg for subsilver2. (Bug #43005 - Patch by rxu)
      • +
      • [Fix] Correctly load complex language variable using acp_language (Bug #45735 - Patch by leviatan21)
      • +
      • [Fix] Fix reapply_sid() to correctly strip session id in certain circumstances (Bug #43125 - Patch by leviatan21)
      • +
      • [Fix] Correctly state why one language pack is marked with an asterisk in the ACP. (Bug #37565 - Patch by bantu)
      • +
      • [Fix] Correctly check if install directory is still present. (Bug #46965 - Patch by rxu)
      • +
      • [Fix] Correct banned user behaviour when "force password change" is enabled (Bug #47145 - Patch by nickvergessen and leviatan21)
      • +
      • [Fix] Correctly display ACP logs options, without permission to clear logs. (Bug #24155 - Patch by leviatan21)
      • +
      • [Fix] Display topic icons in MCP forum view again (only prosilver).
      • +
      • [Fix] Properly display post status messages in topic when post is reported and unapproved (Bug #44455 - Patch by leviatan21)
      • +
      • [Fix] Do not remove recipients when loading private message draft. (Bug #38395 - Patch by nickvergessen)
      • +
      • [Fix] Add author name to moderator log when deleting post/topic. (Bug #46225 - Patch by nickvergessen)
      • +
      • [Fix] Fix broken "Report details" link in the MCP. (Bug #46975 - Patch by nickvergessen)
      • +
      • [Fix] Resolve accesskey conflicts in prosilver. (Bug #44685 - Patch by bantu)
      • +
      • [Fix] Check if template file is empty before trying to read from it. (Bug #47345 - Patch by bantu)
      • +
      • [Fix] Correct descriptions of the permissions to use BBCode, smilies, images and flash to be more relevant. (Bug #36065 - Patch by rxu)
      • +
      • [Fix] Fix style issues in print mode. (Bug #26375 - Patch by leviatan21)
      • +
      • [Fix] Fix minor issue with L_QUOTE language string missing in several PM composing modes. (Bug #39625 - Patch by rxu)
      • +
      • [Fix] Also fetch posts of guests and deleted or deactivated users when searching for author names. (Bug #36565, #47765 - Patch by nickvergessen)
      • +
      • [Fix] Show end of ban in MCP and ACP when user is banned by duration. (Bug #47815 - Patch by Pyramide)
      • +
      • [Fix] Correctly count posts awaiting approval in the MCP. (Bug #47685 - Patch by nickvergessen)
      • +
      • [Fix] Display user's posts count in private message when it is equal to 0 (prosilver). (Bug #40155 - Patch by rxu)
      • +
      • [Fix] Only allow users to disable word censor if globally allowed. (Bug #47575 - Patch by 00mohgta7)
      • +
      • [Fix] Fix database updater and db tools to support multiple column changes/additions/removals with SQLite
      • +
      • [Fix] Correctly detect GZIP status in debug mode. (Bug #24075 - Patch by rxu)
      • +
      • [Fix] Posting smilies in view more smilies now work again in IE (Bug #46025 - Patch by leviatan21)
      • +
      • [Fix] Properly convert and show filesize information. (Bug #47775 - Patch by bantu)
      • +
      • [Fix] Add ability to prune users who never logged in. (Bug #44295 - Patch by rxu)
      • +
      • [Fix] Show smilies and images in topic print view. (Bug #47265 - Patch by nickvergessen)
      • +
      • [Fix] Force full date in private message print view. (Patch by nickvergessen)
      • +
      • [Fix] Fix "Always show a scrollbar for short pages" for IE8 and Firefox 3.5 (Bug #47865 - Patch by stokerpiller)
      • +
      • [Fix] Do not allow setting group as default group for pending users. (Bug #45675 - Patch by nickvergessen)
      • +
      • [Fix] Fail gracefully if store folder is not writable during update. (Bugs #46615, #46945)
      • +
      • [Fix] Hide profile-icon from viewtopic-page if user has no permissions (subsilver2 only) (Bug #37635 - Patch by leviatan21)
      • +
      • [Fix] Correct escaping/unescaping in the LDAP authentication plugin. (Bug #48175)
      • +
      • [Fix] Add hard limit for smilies.
      • +
      • [Fix] Remove redundant SQL query from ucp.php. (Bug #40305)
      • +
      • [Fix] Reorder frame order of animated subsilver2 topic icons to be useful when animation is disabled. (Bug #29385 - Patch by prototech)
      • +
      • [Fix] Ensure user errors are displayed regardless of PHP settings. (Bug #47505)
      • +
      • [Fix] Permit null values for non-required integer custom profile fields and ensure zero complies with the range limits. (Bug #40925)
      • +
      • [Fix] Allow changing forum from select box under certain circumstances. (Bug #37525)
      • +
      • [Fix] Display required fields notice on registration above the custom profile fields. (Bug #39665)
      • +
      • [Fix] Copy poll options properly when copying topic. (Bug #39065)
      • +
      • [Fix] Fix error with disapproval of topics having several queued posts only. (Bug #47705 - Patch by rxu)
      • +
      • [Fix] Preserve newlines in template files (one newline had been always dropped after a template variable due to PHP's handling of closing tags)
      • +
      • [Fix] Be less strict with FTP daemons when getting directory filelists. (Bug #46295)
      • +
      • [Fix] Fix set_custom_template for database-stored styles (Bug #40515 - Patch by nickvergessen)
      • +
      • [Fix] Banning an already banned user states to be successful, but has no effect (Bug #47825 - Patch by Pyramide)
      • +
      • [Fix] Do not add style-parameter to URL again, after admin re-authentification (Bug #18005 - Patch by leviatan21)
      • +
      • [Fix] Do not cut post-message in between HTML-Entities on search.php (Bug #31505 - Patch by leviatan21)
      • +
      • [Fix] Correctly set attachment flag for topics, posts and pms after deleting attachments (Bug #48265 - Patch by MarcoDM and nickvergessen)
      • +
      • [Fix] Display "Locked" button instead of "Reply" one for locked forum in viewtopic (prosilver). (Bug #38055 - Patch by Raimon)
      • +
      • [Fix] Correctly propagate umlauts over search result pages (Bug #33755)
      • +
      • [Fix] Preserve post options when refusing to save the post as a draft. (Bug #39115)
      • +
      • [Fix] Do not send private message back to sender if sender is in the same group the private message was sent to.
      • +
      • [Fix] Correctly add user to a group making it a default one. (Bug #48345 - Patch by rxu)
      • +
      • [Fix] Add log entry when copying forum permissions.
      • +
      • [Fix] Min/max characters per posts no longer affects poll options (Bug #47295 - Patch by nickvergessen)
      • +
      • [Fix] Correctly log action when users request to join a group (Bug #37585 - Patch by nickvergessen)
      • +
      • [Fix] Do not try to create thumbnails for images we cannot open properly. (Bug #48695)
      • +
      • [Fix] Apply locale-independent basename() to attachment filenames. New function added: utf8_basename(). (Bug #43335 - Patch by ocean=Yohsuke)
      • +
      • [Fix] Adjust build_url() to not prepend $phpbb_root_path if path returned from redirect() is an URL. This fixes redirect issues with some installations and bridges. (Bug #47535)
      • +
      • [Fix] Do not mark global announcements as read if all topics in a forum become read (Bug #15729).
      • +
      • [Fix] Fix general error while registration, through undefined variable $config in validate_referer (Bug #49035 - Patch by wjvriend)
      • +
      • [Fix] Correctly extract column default value when exporting PostgreSQL tables. (Bug #48955)
      • +
      • [Fix] Allow updater to work correctly with PHP filename extensions other than ".php". (Bugs #15809, #49215)
      • +
      • [Fix] Update search index if only post subject changed. (Bug #49435)
      • +
      • [Fix] Fix who is online displaying incorrect data. (Bug #49485, thanks Brainy)
      • +
      • [Fix] Fixed incorrect "topic does not exist" when unapproved posts were visited without global moderator permissions. (Bug #47795)
      • +
      • [Fix] Prevent style switcher from blocking the tab key. (Bug #49335)
      • +
      • [Fix] Correctly redirect on MCP main page after posts approval/disapproval from it. (Bug #49625)
      • +
      • [Fix] Do not display topic approval status image for shadow topic if a user is not a moderator in the forum the topic has been moved to. (Bug #43295)
      • +
      • [Fix] Fix email problems on servers with PHP installations not accepting RFC-compliant subject string passed to the the mail()-function. (Bug #46725)
      • +
      • [Fix] Correctly orientate Control-Panel-Navigation background-image on RTL languages. (Bug #49945)
      • +
      • [Fix] Sort private messages by message time and not message id. (Bug #50015)
      • +
      • [Fix] Make sure only logs for existing users are displayed and user-specific logs removed on user deletion. (Bug #49855)
      • +
      • [Fix] Only show "Add friend" and "Add foe" links if the specific module is enabled. (Bug #50475)
      • +
      • [Fix] Correctly display list items in forum description in prosilver and administration. (Bug #48055 - Patch by leviatan21)
      • +
      • [Fix] Fix handling of bookmarks and subscriptions on "split topics", "merge topics" and "merge posts". (Bug #50035)
      • +
      • [Fix] Only embed cron.php if there is no cron lock present to reduce overhead. (Bug #45725 - Patch by TerryE)
      • +
      • [Fix] Add header gradient back into subsilver2 but keep site logo easily replaceable with smaller and bigger ones. (Bug #11142 - Patch by dark/Rain and Raimon)
      • +
      • [Fix] Send activation email when activating user from user settings. (Bug #43145)
      • +
      • [Fix] Do not show resend activation email link when using admin activation. (Bug #44375 - Patch by bbrunnrman)
      • +
      • [Fix] Do not display links to user/post search if search is disabled. (Bug #50685 - Patch by HardStyle)
      • +
      • [Fix] Fix icon alignment for forums with large descriptions in subsilver2. (Bug #50445)
      • +
      • [Fix] Correctly display underlined links placed in last line in viewtopic. (Bug #14811 - Patch by primehalo)
      • +
      • [Change] submit_post() now accepts force_approved_state key passed to $data to indicate new posts being approved (true) or unapproved (false).
      • +
      • [Change] Change the data format of the default file ACM to be more secure from tampering and have better performance.
      • +
      • [Change] Add index on log_time to the log table to prevent slowdown on boards with many log entries. (Bug #44665 - Patch by bantu)
      • +
      • [Change] Template engine now permits to a limited extent variable includes.
      • +
      • [Change] Quote BBCode no longer requires the f_reply permission. (Bug #16079)
      • +
      • [Change] Banning/unbanning users now generates an entry in their user notes (Bug #21825 - Patch by nickvergessen)
      • +
      • [Change] Smilies no longer require the f_bbcode permission. (Bug #26545)
      • +
      • [Change] Ability to define column split in FAQ/BBCode help (Bug #31405)
      • +
      • [Change] Changed behaviour of group_create() function to support specifying additional group columns
      • +
      • [Change] Hide avatar when avatar-type is not allowed (Bug #46785 - Patch by cYbercOsmOnauT and nickvergessen)
      • +
      • [Change] INCLUDEPHP not depending on phpbb_root_path (Bug #45805 - Patch by nickvergessen)
      • +
      • [Change] Ability to fetch moderators with get_moderators() even if load_moderators setting is off. (Bug #35955)
      • +
      • [Change] "Post details" links with image in MCP. (Bug #39845 - Patch by leviatan21)
      • +
      • [Change] PM history now only shows PMs of users you currently reply to. (Bug #39505 - Patch by nickvergessen)
      • +
      • [Change] Show quote button for own PMs in PM history. (Bug #37285 - Patch by nickvergessen)
      • +
      • [Change] Fetch requested cookie variables directly from cookie super global. (Bug #47785)
      • +
      • [Change] Add confirmation for deactivating styles (Bug #14304 - Patch by leviatan21)
      • +
      • [Change] Add confirmation for deactivating language packs (Patch by leviatan21)
      • +
      • [Change] Add confirm-box when deleting permissions (Bug #13673 - Patch by nickvergessen)
      • +
      • [Change] Add pagination for icons and smilies in the ACP and smilies in the smiley popup
      • +
      • [Change] Cache get_username_string() function calls on viewtopic.
      • +
      • [Change] Cache version check.
      • +
      • [Change] When creating a new forum without copying permissions, ask again.
      • +
      • [Change] Parse multiline url title for [url] BBCode tag. (Bug #1309)
      • +
      • [Change] Introduce new parameter to page_header() for forum specific who is online listings.
      • +
      • [Change] Lifted minimum requirement for Firebird DBMS from 2.0+ to 2.1+.
      • +
      • [Change] Unapproved topics can no longer be replied to (Bug #44005, #47675, #23605)
      • +
      • [Change] Require user to be registered and logged in to search for unread posts if topic read tracking is disabled for guests (Bug #49525)
      • +
      • [Change] Allow three-digit hex notation in Color BBcode. (Bug #39965 - Patch by m0rpha)
      • +
      • [Change] Simplified login_box() and redirection after login. S_LOGIN_ACTION can now be used on every page. (Bug #50285)
      • +
      • [Change] Do not take edit post time into account for determining permission to delete last post in topic. (Bug #48615)
      • +
      • [Change] Resize oversized Topic icons (Bug #44415)
      • +
      • [Change] Banned IPs are now sorted (Bug #43045 - Patch by DavidIQ)
      • +
      • [Change] phpBB updater now skips sole whitespace changes. This reduces the chance of conflicts tremendously.
      • +
      • [Feature] Add language selection on the registration terms page (Bug #15085 - Patch by leviatan21)
      • +
      • [Feature] Backported 3.2 captcha plugins. +
          +
        • Classic and GD CAPTCHA
        • +
        • reCaptcha (based on API from recaptcha.net by Mike Crawford and Ben Maurer)
        • +
        • Q&A CAPTCHA
        • +
        • 3D Wave (by Robert "Xore" Hetzler)
        • +
        +
      • +
      • [Feature] Introduced new ACM plugins: + +
      • +
      • [Feature] ATOM Feeds (Idea and diversed from RSS Feed 2.0 MOD (Version 1.0.8/9) by leviatan21)
      • +
      • [Feature] New groups option to excempt group leaders from group permissions
      • +
      • [Feature] New "Newly Registered Users" group for assigning permissions to newly registered users. They will be removed from this group once they reach a defineable amount of posts.
      • +
      • [Feature] Ability to define if the "Newly Registered Users" group will be assigned as the default group to newly registered users.
      • +
      • [Feature] Add new option to disable avatars board-wide (Bug #46785 - Patch by cYbercOsmOnauT and nickvergessen)
      • +
      • [Feature] Enhance obtain_users_online_string to be able to return user-lists for other session-items (Bug #31975 - Patch by nickvergessen)
      • +
      • [Feature] Add unapproved topic icon for moderators on forum list (Bug #46865 - Patch by nickvergessen)
      • +
      • [Feature] Ability to define minimum number of characters for posts/pms
      • +
      • [Feature] Store signature configuration options in database (Bug #45115 - Patch by rxu)
      • +
      • [Feature] Add bare-bones quick-reply editor to viewtopic.
      • +
      • [Feature] Detect when a post has been altered by someone else while editing. (Patch by bantu)
      • +
      • [Feature] Add unread posts quick search option (Bug #46765 - Patch by rxu)
      • +
      • [Feature] Add option to disable avatar uploads from remote locations. (Bug #45375 - Patch by nickvergessen)
      • +
      • [Feature] Ability to delete warnings and keep warnings permanently (Bug #43375 - Patch by nickvergessen)
      • +
      • [Feature] Ability to empty a user's outbox from the user ACP quick tools.
      • +
      • [Feature] Ability to search ACP / MCP logs
      • +
      • [Feature] Users can report PMs to moderators which are then visible in a new MCP module
      • +
      • [Feature] Parse email text files with the template engine.
      • +
      • [Feature] Use email-style quoting when bbcodes are disabled.
      • +
      • [Feature] Added new functionality to inactive users module: +
          +
        • Ability to set users per page.
        • +
        • Ability to sort by posts/number of reminders/last reminded date.
        • +
        • Show number of posts and ability to search posts.
        • +
        • Show number of reminders sent to user.
        • +
        • Show date of last reminder sent to user.
        • +
        +
      • +
      • [Feature] Display version check on ACP main page.
      • +
      • [Feature] Ability to copy permissions from one forum to several other forums.
      • +
      • [Feature] Ability to control the display of custom profile fields on viewtopic (Bug #48985).
      • +
      • [Feature] Fallback options for missing language files. (Bug #38575 - Patch by EXreaction)
      • +
      • [Feature] Separate PM Reply and PM Reply to all in prosilver.
      • +
      • [Feature] Place debug notices during captcha rendering in the error log - useful for debugging output already started errors.
      • +
      • [Feature] Ability to define constant PHPBB_USE_BOARD_URL_PATH to use board url for images/avatars/ranks/imageset...
      • +
      • [Feature] Added function to generate Email hash. (Bug #49195)
      • +
      • [Feature] Style authors are now able to define the default submit button used for form submission on ENTER keypress on forms using more than one. Prosilver uses this for the posting page(s) and registration screen.
      • +
      • [Feature] Ability to specify amount of time user is able to delete his last post in topic.
      • +
      +

      1.ii. Changes since 3.0.4

      • [Fix] Delete user entry from ban list table upon user deletion (Bug #40015 - Patch by TerraFrost)
      • @@ -101,7 +318,7 @@
      • [Fix] Changed the success message when requesting a new password to be more accurate. (Bug #41405)
      • [Fix] Add missing anti-abuse email headers to acp_inactive.php and ucp_resend.php.
      • [Fix] Only remind users in the correct inactive states depending on the board account activation level.
      • -
      • [Fix] Various XHTML mistakes in prosilver, subsilver2 and the ACP. (Bugs #41745, #42265 - Patch by nickvergessen, #38465, #43015)
      • +
      • [Fix] Various XHTML mistakes in prosilver, subsilver2 and the ACP. (Bugs #41745, #42265 - Patch by nickvergessen, #38465, #43015, #46585 - Patch by Raimon)
      • [Fix] Log password changes via password reset function. (Bug #41365)
      • [Fix] Poll, negative durations generate error (Bug #41295 - Patch by TerraFrost)
      • [Fix] Visibility of custom field on registration is incorrectly controlled by setting "display" (Bug #41385 - Patch by Eelke and fade2gray)
      • @@ -173,7 +390,7 @@
      • [Sec] Only use forum id supplied for posting if global announcement detected. (Reported by nickvergessen)
      -

      1.ii. Changes since 3.0.3

      +

      1.iii. Changes since 3.0.3

      • [Fix] Allow mixed-case template directories to be inherited (Bug #36725)
      • @@ -205,7 +422,7 @@
      • [Sec] Ask for forum password if post within passworded forum quoted in private message. (Reported by nickvergessen)
      -

      1.iii. Changes since 3.0.2

      +

      1.iv. Changes since 3.0.2

      • [Fix] Correctly set topic starter if first post in topic removed (Bug #30575 - Patch by blueray2048)
      • @@ -304,7 +521,7 @@
      • [Sec Precaution] Stricter validation of the HTTP_HOST header (Thanks to Techie-Micheal et al for pointing out possible issues in derived code)
      -

      1.iv. Changes since 3.0.1

      +

      1.v. Changes since 3.0.1

      • [Fix] Ability to set permissions on non-mysql dbms (Bug #24955)
      • @@ -352,7 +569,7 @@
      • [Sec] Only allow urls gone through redirect() being used within login_box(). (thanks nookieman)
      -

      1.v. Changes since 3.0.0

      +

      1.vi Changes since 3.0.0

      • [Change] Validate birthdays (Bug #15004)
      • @@ -423,7 +640,7 @@
      • [Fix] Find and display colliding usernames correctly when converting from one database to another (Bug #23925)
      -

      1.vi. Changes since 3.0.RC8

      +

      1.vii. Changes since 3.0.RC8

      • [Fix] Cleaned usernames contain only single spaces, so "a_name" and "a__name" are treated as the same name (Bug #15634)
      • @@ -432,7 +649,7 @@
      • [Fix] Call garbage_collection() within database updater to correctly close connections (affects Oracle for example)
      -

      1.vii. Changes since 3.0.RC7

      +

      1.viii. Changes since 3.0.RC7

      • [Fix] Fixed MSSQL related bug in the update system
      • @@ -467,7 +684,7 @@
      • [Fix] No duplication of active topics (Bug #15474)
      -

      1.viii. Changes since 3.0.RC6

      +

      1.ix. Changes since 3.0.RC6

      • [Fix] Submitting language changes using acp_language (Bug #14736)
      • @@ -477,7 +694,7 @@
      • [Fix] Able to request new password (Bug #14743)
      -

      1.ix. Changes since 3.0.RC5

      +

      1.x. Changes since 3.0.RC5

      • [Feature] Removing constant PHPBB_EMBEDDED in favor of using an exit_handler(); the constant was meant to achive this more or less.
      • @@ -540,7 +757,7 @@
      • [Sec] New password hashing mechanism for storing passwords (#i42)
      -

      1.x. Changes since 3.0.RC4

      +

      1.xi. Changes since 3.0.RC4

      • [Fix] MySQL, PostgreSQL and SQLite related database fixes (Bug #13862)
      • @@ -591,7 +808,7 @@
      • [Fix] odbc_autocommit causing existing result sets to be dropped (Bug #14182)
      -

      1.xi. Changes since 3.0.RC3

      +

      1.xii. Changes since 3.0.RC3

      • [Fix] Fixing some subsilver2 and prosilver style issues
      • @@ -700,7 +917,7 @@
      -

      1.xii. Changes since 3.0.RC2

      +

      1.xiii. Changes since 3.0.RC2

      • [Fix] Re-allow searching within the memberlist
      • @@ -746,7 +963,7 @@
      -

      1.xiii. Changes since 3.0.RC1

      +

      1.xiv. Changes since 3.0.RC1

      • [Fix] (X)HTML issues within the templates (Bug #11255, #11255)
      • @@ -902,4 +1119,4 @@
      - \ No newline at end of file + diff --git a/phpBB/docs/INSTALL.html b/phpBB/docs/INSTALL.html index 4eee4520dc..c297abe267 100644 --- a/phpBB/docs/INSTALL.html +++ b/phpBB/docs/INSTALL.html @@ -139,7 +139,7 @@
    6. MySQL 3.23 or above (MySQLi supported)
    7. PostgreSQL 7.3+
    8. SQLite 2.8.2+
    9. -
    10. Firebird 2.0+
    11. +
    12. Firebird 2.1+
    13. MS SQL Server 2000 or above (directly or via ODBC)
    14. Oracle
    15. @@ -273,7 +273,7 @@

      This package is meant for those wanting to only replace changed files from a previous version to the latest version. This package normally contains the changed files from up to five previous versions.

      -

      This package contains a number of archives, each contains the files changed from a given release to the latest version. You should select the appropriate archive for your current version, e.g. if you currently have 3.0.4 you should select the phpBB-3.0.4_to_3.0.5.zip/tar.gz file.

      +

      This package contains a number of archives, each contains the files changed from a given release to the latest version. You should select the appropriate archive for your current version, e.g. if you currently have 3.0.5 you should select the phpBB-3.0.5_to_3.0.6.zip/tar.gz file.

      The directory structure has been preserved enabling you (if you wish) to simply upload the contents of the archive to the appropriate location on your server, i.e. simply overwrite the existing files with the new versions. Do not forget that if you have installed any MODs these files will overwrite the originals possibly destroying them in the process. You will need to re-add MODs to any affected file before uploading.

      @@ -283,9 +283,9 @@

      The patch file package is for those wanting to update through the patch application, and being comfortable with it.

      -

      The patch file is one solution for those with many Modifications (MODs) or other changes who do not want to re-add them back to all the changed files if they use the method explained above. To use this you will need command line access to a standard UNIX type patch application. If you do not have access to such an application but still want to use this update approach, we strongly recommend the Automatic update package explained below. It is also the preferred update method.

      +

      The patch file is one solution for those with many Modifications (MODs) or other changes who do not want to re-add them back to all the changed files if they use the method explained above. To use this you will need command line access to a standard UNIX type patch application. If you do not have access to such an application but still want to use this update approach, we strongly recommend the Automatic update package explained below. It is also the recommended update method.

      -

      A number of patch files are provided to allow you to update from previous stable releases. Select the correct patch, e.g. if your current version is 3.0.4 you need the phpBB-3.0.4_to_3.0.5.patch file. Place the correct patch in the parent directory containing the phpBB3 core files (i.e. index.php, viewforum.php, etc.). With this done you should run the following command: patch -cl -d [PHPBB DIRECTORY] -p1 < [PATCH NAME] (where PHPBB DIRECTORY is the directory name your phpBB Installation resides in, for example phpBB3, and where PATCH NAME is the relevant filename of the selected patch file). This should complete quickly, hopefully without any HUNK FAILED comments.

      +

      A number of patch files are provided to allow you to update from previous stable releases. Select the correct patch, e.g. if your current version is 3.0.5 you need the phpBB-3.0.5_to_3.0.6.patch file. Place the correct patch in the parent directory containing the phpBB3 core files (i.e. index.php, viewforum.php, etc.). With this done you should run the following command: patch -cl -d [PHPBB DIRECTORY] -p1 < [PATCH NAME] (where PHPBB DIRECTORY is the directory name your phpBB Installation resides in, for example phpBB3, and where PATCH NAME is the relevant filename of the selected patch file). This should complete quickly, hopefully without any HUNK FAILED comments.

      If you do get failures you should look at using the Changed files only package to replace the files which failed to patch, please note that you will need to manually re-add any Modifications (MODs) to these particular files. Alternatively if you know how you can examine the .rej files to determine what failed where and make manual adjustments to the relevant source.

      @@ -293,7 +293,7 @@

      4.iv. Automatic update package

      -

      This update method is the preferred method for updating. This package allows detecting changed files automatically and merges changes if needed.

      +

      This update method is the recommended method for updating. This package allows detecting changed files automatically and merges changes if needed.

      The automatic update package contains - contrary to the others - only the information required to update the previous release version to the latest available version. These packages are meant for use with the automatic update tool.

      diff --git a/phpBB/docs/coding-guidelines.html b/phpBB/docs/coding-guidelines.html index bfd134faac..8ac2e4e89d 100644 --- a/phpBB/docs/coding-guidelines.html +++ b/phpBB/docs/coding-guidelines.html @@ -57,6 +57,7 @@
    16. Editor Settings
    17. File Header
    18. File Locations
    19. +
    20. Special Constants
  2. Code Layout/Guidelines @@ -86,6 +87,12 @@
  3. Writing Style
+
  • VCS Guidelines +
      +
    1. Repository structure
    2. +
    3. Commit messages
    4. +
    +
  • Guidelines Changelog
  • Copyright and disclaimer
  • @@ -217,6 +224,54 @@ class ...
  • styles
    /styles, style.php
    phpBB Styles/Templates/Themes/Imagesets
  • + 1.iv. Special Constants + +

    There are some special constants application developers are able to utilize to bend some of phpBB's internal functionality to suit their needs.

    + +
    +PHPBB_MSG_HANDLER          (overwrite message handler)
    +PHPBB_DB_NEW_LINK          (overwrite new_link parameter for sql_connect)
    +PHPBB_ROOT_PATH            (overwrite $phpbb_root_path)
    +PHPBB_ADMIN_PATH           (overwrite $phpbb_admin_path)
    +PHPBB_USE_BOARD_URL_PATH   (use generate_board_url() for image paths instead of $phpbb_root_path)
    +PHPBB_DISABLE_ACP_EDITOR   (disable ACP style editor for templates)
    +PHPBB_DISABLE_CONFIG_CHECK (disable ACP config.php writeable check)
    +
    +PHPBB_ACM_MEMCACHE_PORT     (overwrite memcached port, default is 11211)
    +PHPBB_ACM_MEMCACHE_COMPRESS (overwrite memcached compress setting, default is disabled)
    +PHPBB_ACM_MEMCACHE_HOST     (overwrite memcached host name, default is localhost)
    +
    +PHPBB_QA                   (Set board to QA-Mode, which means the updater also checks for RC-releases)
    +
    + +

    PHPBB_USE_BOARD_URL_PATH

    + +

    If the PHPBB_USE_BOARD_URL_PATH constant is set to true, phpBB uses generate_board_url() (this will return the boards url with the script path included) on all instances where web-accessible images are loaded. The exact locations are:

    + +
      +
    • /includes/session.php - user::img()
    • +
    • /includes/functions_content.php - smiley_text()
    • +
    + +

    Path locations for the following template variables are affected by this too:

    + +
      +
    • {T_THEME_PATH} - styles/xxx/theme
    • +
    • {T_TEMPLATE_PATH} - styles/xxx/template
    • +
    • {T_SUPER_TEMPLATE_PATH} - styles/xxx/template
    • +
    • {T_IMAGESET_PATH} - styles/xxx/imageset
    • +
    • {T_IMAGESET_LANG_PATH} - styles/xxx/imageset/yy
    • +
    • {T_IMAGES_PATH} - images/
    • +
    • {T_SMILIES_PATH} - $config['smilies_path']/
    • +
    • {T_AVATAR_PATH} - $config['avatar_path']/
    • +
    • {T_AVATAR_GALLERY_PATH} - $config['avatar_gallery_path']/
    • +
    • {T_ICONS_PATH} - $config['icons_path']/
    • +
    • {T_RANKS_PATH} - $config['ranks_path']/
    • +
    • {T_UPLOAD_PATH} - $config['upload_path']/
    • +
    • {T_STYLESHEET_LINK} - styles/xxx/theme/stylesheet.css (or link to style.php if css is parsed dynamically)
    • +
    • New template variable {BOARD_URL} for the board url + script path.
    • +
    + @@ -1110,6 +1165,29 @@ append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;

    You will note in the 3.0 templates the major sources start with <!-- INCLUDE overall_header.html --> or <!-- INCLUDE simple_header.html -->, etc. In 2.0.x control of "which" header to use was defined entirely within the code. In 3.0.x the template designer can output what they like. Note that you can introduce new templates (i.e. other than those in the default set) using this system and include them as you wish ... perhaps useful for a common "menu" bar or some such. No need to modify loads of files as with 2.0.x.

    +

    Added in 3.0.6 is the ability to include a file using a template variable to specify the file, this functionality only works for root variables (i.e. not block variables).

    +
    +<!-- INCLUDE {FILE_VAR} -->
    +
    + +

    Template defined variables can also be utilised. + +

    +<!-- DEFINE $SOME_VAR = 'my_file.html' -->
    +<!-- INCLUDE {$SOME_VAR} -->
    +
    +

    PHP

    A contentious decision has seen the ability to include PHP within the template introduced. This is achieved by enclosing the PHP within relevant tags:

    @@ -2252,12 +2330,71 @@ if (utf8_case_fold_nfc($string1) == utf8_case_fold_nfc($string2))
    -

    7. Guidelines Changelog

    +

    7. VCS Guidelines

    +
    +

    The version control system for phpBB3 is subversion. The repository is available at http://code.phpbb.com/svn/phpbb. + +

    7.i. Repository Structure

    + +
      +
    • trunk
      The latest unstable development version with new features etc. Contains the actual board in /trunk/phpBB
    • +
    • branches
      Development branches of stable phpBB releases. Copied from /trunk at the time of release. +
        +
      • phpBB3.0/branches/phpBB-3_0_0/phpBB
        Development branch of the stable 3.0 line. Bug fixes are applied here.
      • +
      • phpBB2/branches/phpBB-2_0_0/phpBB
        Old phpBB2 development branch.
      • +
      +
    • +
    • tags
      Released versions. Copies of trunk or the respective branch, made at the time of release. +
        +
      • /tags/release_3_0_BX
        Beta release X of the 3.0 line.
      • +
      • /tags/release_3_0_RCX
        Release candidate X of the 3.0 line.
      • +
      • /tags/release_3_0_X-RCY
        Release candidate Y of the stable 3.0.X release.
      • +
      • /tags/release_3_0_X
        Stable 3.0.X release.
      • +
      • /tags/release_2_0_X
        Old stable 2.0.X release.
      • +
      +
    • +
    + +

    7.ii. Commit Messages

    + +

    The commit message should contain a brief explanation of all changes made within the commit. Often identical to the changelog entry. A bug ticket can be referenced by specifying the ticket ID with a hash, e.g. #12345. A reference to another revision should simply be prefixed with r, e.g. r12345.

    + +

    Junior Developers need to have their patches approved by a development team member first. The commit message must end in a line with the following format:

    + +
    +Authorised by: developer1[, developer2[, ...]]
    +	
    + +
    + + + +
    +
    + +
    + +

    8. Guidelines Changelog

    +
    +
    + +
    +

    Revision 10007

    + + + +

    Revision 9817

    + +
      +
    • Added VCS section.
    • +

    Revision 8732

    @@ -2330,7 +2467,7 @@ if (utf8_case_fold_nfc($string1) == utf8_case_fold_nfc($string2))
    -

    8. Copyright and disclaimer

    +

    9. Copyright and disclaimer

    diff --git a/phpBB/docs/hook_system.html b/phpBB/docs/hook_system.html index 565e0096fc..b23ebab869 100644 --- a/phpBB/docs/hook_system.html +++ b/phpBB/docs/hook_system.html @@ -104,14 +104,14 @@ h3 { border-top: 1px solid #ccc; } -code { - color: #006600; - font-weight: normal; - font-family: 'Courier New', monospace; - border-color: #D1D7DC; - border-width: 1px; - border-style: solid; - background-color: #FAFAFA; +code { + color: #006600; + font-weight: normal; + font-family: 'Courier New', monospace; + border-color: #D1D7DC; + border-width: 1px; + border-style: solid; + background-color: #FAFAFA; } #wrap { @@ -387,8 +387,36 @@ PHPBB_MSG_HANDLER (overwrite message handler) PHPBB_DB_NEW_LINK (overwrite new_link parameter for sql_connect) PHPBB_ROOT_PATH (overwrite $phpbb_root_path) PHPBB_ADMIN_PATH (overwrite $phpbb_admin_path) +PHPBB_USE_BOARD_URL_PATH (use generate_board_url() for image paths instead of $phpbb_root_path)
    +

    If the PHPBB_USE_BOARD_URL_PATH constant is set to true, phpBB uses generate_board_url() (this will return the boards url with the script path included) on all instances where web-accessible images are loaded. The exact locations are:

    + +
      +
    • /includes/session.php - user::img()
    • +
    • /includes/functions_content.php - smiley_text()
    • +
    + +

    Path locations for the following template variables are affected by this too:

    + +
      +
    • {T_THEME_PATH} - styles/xxx/theme
    • +
    • {T_TEMPLATE_PATH} - styles/xxx/template
    • +
    • {T_SUPER_TEMPLATE_PATH} - styles/xxx/template
    • +
    • {T_IMAGESET_PATH} - styles/xxx/imageset
    • +
    • {T_IMAGESET_LANG_PATH} - styles/xxx/imageset/yy
    • +
    • {T_IMAGES_PATH} - images/
    • +
    • {T_SMILIES_PATH} - $config['smilies_path']/
    • +
    • {T_AVATAR_PATH} - $config['avatar_path']/
    • +
    • {T_AVATAR_GALLERY_PATH} - $config['avatar_gallery_path']/
    • +
    • {T_ICONS_PATH} - $config['icons_path']/
    • +
    • {T_RANKS_PATH} - $config['ranks_path']/
    • +
    • {T_UPLOAD_PATH} - $config['upload_path']/
    • +
    • {T_STYLESHEET_LINK} - styles/xxx/theme/stylesheet.css (or link to style.php if css is parsed dynamically)
    • +
    • New template variable {BOARD_URL} for the board url + script path.
    • +
    + +
    @@ -616,7 +644,7 @@ echo $second_object->hook_me('first', 'second') . '<br />';
     not hooked
    -hooked 
    +hooked
     

    A different possibility would be using a function variable (which could be left out on passing the function variables to the hook):

    @@ -670,7 +698,7 @@ echo $second_object->hook_me('first', 'second') . '<br />';
     not hooked
    -hooked 
    +hooked
     		
    diff --git a/phpBB/download/file.php b/phpBB/download/file.php index 32b5f87950..c6106fc09f 100644 --- a/phpBB/download/file.php +++ b/phpBB/download/file.php @@ -249,7 +249,7 @@ if (!$attachment) trigger_error('ERROR_NO_ATTACHMENT'); } -$attachment['physical_filename'] = basename($attachment['physical_filename']); +$attachment['physical_filename'] = utf8_basename($attachment['physical_filename']); $display_cat = $extensions[$attachment['extension']]['display_cat']; if (($display_cat == ATTACHMENT_CATEGORY_IMAGE || $display_cat == ATTACHMENT_CATEGORY_THUMB) && !$user->optionget('viewimg')) diff --git a/phpBB/faq.php b/phpBB/faq.php index da064e4452..0a04bad8eb 100644 --- a/phpBB/faq.php +++ b/phpBB/faq.php @@ -38,15 +38,28 @@ switch ($mode) } // Pull the array data from the lang pack +$switch_column = $found_switch = false; $help_blocks = array(); foreach ($user->help as $help_ary) { if ($help_ary[0] == '--') { - $template->assign_block_vars('faq_block', array( - 'BLOCK_TITLE' => $help_ary[1]) - ); + if ($help_ary[1] == '--') + { + $switch_column = true; + $found_switch = true; + continue; + } + $template->assign_block_vars('faq_block', array( + 'BLOCK_TITLE' => $help_ary[1], + 'SWITCH_COLUMN' => $switch_column, + )); + + if ($switch_column) + { + $switch_column = false; + } continue; } @@ -58,11 +71,13 @@ foreach ($user->help as $help_ary) // Lets build a page ... $template->assign_vars(array( - 'L_FAQ_TITLE' => $l_title, - 'L_BACK_TO_TOP' => $user->lang['BACK_TO_TOP']) -); + 'L_FAQ_TITLE' => $l_title, + 'L_BACK_TO_TOP' => $user->lang['BACK_TO_TOP'], -page_header($l_title); + 'SWITCH_COLUMN_MANUALLY' => (!$found_switch) ? true : false, +)); + +page_header($l_title, false); $template->set_filenames(array( 'body' => 'faq_body.html') diff --git a/phpBB/feed.php b/phpBB/feed.php new file mode 100644 index 0000000000..9603b27301 --- /dev/null +++ b/phpBB/feed.php @@ -0,0 +1,1064 @@ +session_begin(); +$auth->acl($user->data); +$user->setup(); + +// Initial var setup +$forum_id = request_var('f', 0); +$topic_id = request_var('t', 0); +$mode = request_var('mode', ''); + +// Feed date format for PHP > 5 and PHP4 +$feed_date_format = (PHP_VERSION >= 5) ? 'c' : "Y-m-d\TH:i:sO"; +$params = false; + +// We do not use a template, therefore we simply define the global template variables here +$global_vars = $item_vars = array(); + +// Generate params array for use in append_sid() to correctly link back to this page +if ($forum_id || $topic_id || $mode) +{ + $params = array( + 'f' => ($forum_id) ? $forum_id : NULL, + 't' => ($topic_id) ? $topic_id : NULL, + 'mode' => ($mode) ? $mode : NULL, + ); +} + +// This boards URL +$board_url = generate_board_url(); + +// Get correct feed object +$feed = phpbb_feed_factory::init($mode, $forum_id, $topic_id); + +// No feed found +if ($feed === false) +{ + trigger_error('NO_FEED'); +} + +// Open Feed +$feed->open(); + +// Some default assignments +// FEED_IMAGE is not used (atom) +$global_vars = array( + 'FEED_IMAGE' => ($user->img('site_logo', '', false, '', 'src')) ? $board_url . '/' . substr($user->img('site_logo', '', false, '', 'src'), strlen($phpbb_root_path)) : '', + 'SELF_LINK' => feed_append_sid('/feed.' . $phpEx, $params), + 'FEED_LINK' => $board_url . '/index.' . $phpEx, + 'FEED_TITLE' => $config['sitename'], + 'FEED_SUBTITLE' => $config['site_desc'], + 'FEED_UPDATED' => $user->format_date(time(), $feed_date_format, true), + 'FEED_LANG' => $user->lang['USER_LANG'], + 'FEED_AUTHOR' => $config['sitename'], +); + +// Iterate through items +while ($row = $feed->get_item()) +{ + // BBCode options to correctly disable urls, smilies, bbcode... + if ($feed->get('options') === NULL) + { + // Allow all combinations + $options = 7; + + if ($feed->get('enable_bbcode') !== NULL && $feed->get('enable_smilies') !== NULL && $feed->get('enable_magic_url') !== NULL) + { + $options = (($row[$feed->get('enable_bbcode')]) ? OPTION_FLAG_BBCODE : 0) + (($row[$feed->get('enable_smilies')]) ? OPTION_FLAG_SMILIES : 0) + (($row[$feed->get('enable_magic_url')]) ? OPTION_FLAG_LINKS : 0); + } + } + else + { + $options = $row[$feed->get('options')]; + } + + $title = ($row[$feed->get('title')]) ? $row[$feed->get('title')] : ((isset($row[$feed->get('title2')])) ? $row[$feed->get('title2')] : ''); + $title = censor_text($title); + + $item_row = array( + 'author' => ($feed->get('creator') !== NULL) ? $row[$feed->get('creator')] : '', + 'pubdate' => $user->format_date($row[$feed->get('date')], $feed_date_format, true), + 'link' => '', + 'title' => censor_text($title), + 'category' => ($config['feed_item_statistics']) ? $board_url . '/viewforum.' . $phpEx . '?f=' . $row['forum_id'] : '', + 'category_name' => ($config['feed_item_statistics']) ? utf8_htmlspecialchars($row['forum_name']) : '', + 'description' => censor_text(feed_generate_content($row[$feed->get('text')], $row[$feed->get('bbcode_uid')], $row[$feed->get('bitfield')], $options)), + 'statistics' => '', + ); + + // Adjust items, fill link, etc. + $feed->adjust_item($item_row, $row); + + $item_vars[] = $item_row; +} + +$feed->close(); + +// Output page + +// gzip_compression +if ($config['gzip_compress']) +{ + if (@extension_loaded('zlib') && !headers_sent()) + { + ob_start('ob_gzhandler'); + } +} + +// IF debug extra is enabled and admin want to "explain" the page we need to set other headers... +if (!defined('DEBUG_EXTRA') || !request_var('explain', 0) || !$auth->acl_get('a_')) +{ + header("Content-Type: application/atom+xml; charset=UTF-8"); + header("Last-Modified: " . gmdate('D, d M Y H:i:s', time()) . ' GMT'); +} +else +{ + header('Content-type: text/html; charset=UTF-8'); + header('Cache-Control: private, no-cache="set-cookie"'); + header('Expires: 0'); + header('Pragma: no-cache'); + + $mtime = explode(' ', microtime()); + $totaltime = $mtime[0] + $mtime[1] - $starttime; + + if (method_exists($db, 'sql_report')) + { + $db->sql_report('display'); + } + + garbage_collection(); + exit_handler(); +} + +echo '' . "\n"; +echo '' . "\n"; +echo '' . "\n\n"; + +echo (!empty($global_vars['FEED_TITLE'])) ? '' . $global_vars['FEED_TITLE'] . '' . "\n" : ''; +echo (!empty($global_vars['FEED_SUBTITLE'])) ? '' . $global_vars['FEED_SUBTITLE'] . '' . "\n" : ''; +echo (!empty($global_vars['FEED_LINK'])) ? '' . "\n" : ''; +echo '' . $global_vars['FEED_UPDATED'] . '' . "\n\n"; + +echo '' . "\n"; +echo '' . $global_vars['SELF_LINK'] . '' . "\n"; + +foreach ($item_vars as $row) +{ + echo '' . "\n"; + + if (!empty($row['author'])) + { + echo '' . "\n"; + } + + echo '' . $row['pubdate'] . '' . "\n"; + echo '' . $row['link'] . '' . "\n"; + echo '' . "\n"; + echo '<![CDATA[' . $row['title'] . ']]>' . "\n\n"; + + if (!empty($row['category'])) + { + echo '' . "\n"; + } + + echo '' . $user->lang['STATISTICS'] . ': ' . $row['statistics'] . '

    '; + } + + echo '
    ' . "\n" . ']]>' . "\n"; + echo '' . "\n"; +} + +echo ''; + +garbage_collection(); +exit_handler(); + +/** +* Run links through append_sid(), prepend generate_board_url() and remove session id +**/ +function feed_append_sid($url, $params) +{ + global $board_url; + + $link = append_sid($board_url . $url, $params); + + // Remove added sid - not as easy as it sounds. ;) + $link = (strpos($link, 'sid=') !== false) ? trim(preg_replace('/(&|&|\?)sid=[a-z0-9]+(&|&)?/', '\1', $link), '?& ') : $link; + + // Now the only thing remaining could be an empty & + $link = (substr($link, -5) === '&') ? substr($link, 0, -5) : $link; + // And &#xxx + $link = str_replace('&#', '#', $link); + + return $link; +} + +/** +* Generate text content +**/ +function feed_generate_content($content, $uid, $bitfield, $options) +{ + global $user, $config, $phpbb_root_path, $phpEx, $board_url; + + if (empty($content)) + { + return ''; + } + + // Prepare some bbcodes for better parsing + $content = preg_replace("#\[quote(=".*?")?:$uid\]\s*(.*?)\s*\[/quote:$uid\]#si", "[quote$1:$uid]
    $2
    [/quote:$uid]", $content); + + $content = generate_text_for_display($content, $uid, $bitfield, $options); + + // Add newlines + $content = str_replace('
    ', '
    ' . "\n", $content); + + // Relative Path to Absolute path, Windows style + $content = str_replace('./', $board_url . '/', $content); + + // Remove "Select all" link and mouse events + $content = str_replace('' .$user->lang['SELECT_ALL_CODE'] . '', '', $content); + $content = preg_replace('#(onkeypress|onclick)="(.*?)"#si', '', $content); + + // Firefox does not support CSS for feeds, though + + // Remove font sizes +// $content = preg_replace('#([^>]+)#iU', '\1', $content); + + // Make text strong :P +// $content = preg_replace('#(.*?)#iU', '\1', $content); + + // Italic +// $content = preg_replace('#([^<]+)#iU', '\1', $content); + + // Underline +// $content = preg_replace('#([^<]+)#iU', '\1', $content); + + // Remove embed Windows Media Streams + $content = preg_replace( '#<\!--\[if \!IE\]>-->([^[]+)<\!--#si', '', $content); + + // Do not use < and >, because we want to retain code contained in [code][/code] + + // Remove embed and objects + $content = preg_replace( '#<(object|embed)(.*?) (value|src)=(.*?) ([^[]+)(object|embed)>#si',' $1 ',$content); + + // Remove some specials html tag, because somewhere there are a mod to allow html tags ;) + $content = preg_replace( '#<(script|iframe)([^[]+)\1>#siU', ' $1 ', $content); + + // Remove Comments from inline attachments [ia] + $content = preg_replace('#
    (.*?)(.*?)(.*?)
    #si','$4',$content); + + // Replace some entities with their unicode counterpart + $entities = array( + ' ' => "\xC2\xA0", + '•' => "\xE2\x80\xA2", + '·' => "\xC2\xB7", + '©' => "\xC2\xA9", + ); + + $content = str_replace(array_keys($entities), array_values($entities), $content); + + // Remove CDATA blocks. ;) + $content = preg_replace('#\<\!\[CDATA\[(.*?)\]\]\>#s', '', $content); + + // Other control characters + // $content = preg_replace('#(?:[\x00-\x1F\x7F]+|(?:\xC2[\x80-\x9F])+)#', '', $content); + + return $content; +} + +/** +* Factory class to return correct object +* @package phpBB3 +*/ +class phpbb_feed_factory +{ + /** + * Return correct object for specified mode + * + * @param string $mode The feeds mode. + * @param int $forum_id Forum id specified by the script if forum feed provided. + * @param int $topic_id Topic id specified by the script if topic feed provided. + * + * @return object Returns correct feeds object for specified mode. + */ + function init($mode, $forum_id, $topic_id) + { + global $config; + + switch ($mode) + { + case 'forums': + if (!$config['feed_overall_forums']) + { + return false; + } + + return new phpbb_feed_forums(); + break; + + case 'topics': + if (!$config['feed_overall_topics']) + { + return false; + } + + return new phpbb_feed_topics(); + break; + + case 'news': + global $db; + + // Get at least one news forum + $sql = 'SELECT forum_id + FROM ' . FORUMS_TABLE . ' + WHERE ' . $db->sql_bit_and('forum_options', FORUM_OPTION_FEED_NEWS, '<> 0'); + $result = $db->sql_query_limit($sql, 1, 0, 600); + $s_feed_news = (int) $db->sql_fetchfield('forum_id'); + $db->sql_freeresult($result); + + if (!$s_feed_news) + { + return false; + } + + return new phpbb_feed_news(); + break; + + default: + // Forum and/or topic specified? + if ($topic_id && !$config['feed_topic']) + { + return false; + } + + if ($forum_id && !$topic_id && !$config['feed_forum']) + { + return false; + } + + return new phpbb_feed($forum_id, $topic_id); + break; + } + } +} + +/** +* Base/default Feed class if no mode is specified. +* This can be the overall site feed or a forum/topic feed. +* @package phpBB3 +*/ +class phpbb_feed +{ + /** + * Forum id specified for forum feed. + */ + var $forum_id = 0; + + /** + * Topic id specified for topic feed. + */ + var $topic_id = 0; + + /** + * SQL Query to be executed to get feed items + */ + var $sql; + + /** + * Keys specified for retrieval of title, content, etc. + */ + var $keys = array(); + + /** + * An array of excluded forum ids. + */ + var $excluded_forums_ary = NULL; + + /** + * Number of items to fetch + */ + var $num_items; + + /** + * boolean to determine if items array is filled or not + */ + var $items_filled = false; + + /** + * array holding items + */ + var $items = array(); + + /** + * Default setting for last x days + */ + var $sort_days = 30; + + /** + * Default cache time of entries in seconds + */ + var $cache_time = 300; + + /** + * Separator for title elements to separate items (for example forum / topic) + */ + var $separator = "\xE2\x80\xA2"; // • + + /** + * Constructor. Set standard keys. + */ + function phpbb_feed($forum_id = 0, $topic_id = 0) + { + global $config; + + $this->forum_id = $forum_id; + $this->topic_id = $topic_id; + + $this->sql = array(); + + // Set some values for pagination + $this->num_items = $config['feed_limit']; + $this->set_keys(); + } + + function set_keys() + { + // Set keys for items... + $this->set('title', 'post_subject'); + $this->set('title2', 'topic_title'); + $this->set('author_id', 'user_id'); + $this->set('creator', 'username'); + $this->set('text', 'post_text'); + $this->set('bitfield', 'bbcode_bitfield'); + $this->set('bbcode_uid','bbcode_uid'); + $this->set('date', 'post_time'); + + $this->set('enable_bbcode', 'enable_bbcode'); + $this->set('enable_smilies', 'enable_smilies'); + $this->set('enable_magic_url', 'enable_magic_url'); + } + + function open() + { + if (!$this->forum_id && !$this->topic_id) + { + return; + } + else if ($this->forum_id && !$this->topic_id) + { + global $db, $user, $global_vars; + + $sql = 'SELECT forum_name + FROM ' . FORUMS_TABLE . ' + WHERE forum_id = ' . $this->forum_id; + $result = $db->sql_query($sql); + + $global_vars['FEED_MODE'] = $user->lang['FORUM'] . ': ' . $db->sql_fetchfield('forum_name'); + + $db->sql_freeresult($result); + } + else if ($this->topic_id) + { + global $db, $user, $global_vars; + + $sql = 'SELECT topic_title + FROM ' . TOPICS_TABLE . ' + WHERE topic_id = ' . $this->topic_id; + $result = $db->sql_query($sql); + + $global_vars['FEED_MODE'] = $user->lang['TOPIC'] . ': ' . $db->sql_fetchfield('topic_title'); + + $db->sql_freeresult($result); + } + } + + function close() + { + if (!empty($this->result)) + { + global $db; + + $db->sql_freeresult($this->result); + } + } + + /** + * Set key + */ + function set($key, $value) + { + $this->keys[$key] = $value; + } + + /** + * Get key + */ + function get($key) + { + return (isset($this->keys[$key])) ? $this->keys[$key] : NULL; + } + + /** + * Return array of excluded forums + */ + function excluded_forums() + { + if ($this->excluded_forums_ary !== NULL) + { + return $this->excluded_forums_ary; + } + + global $auth, $db, $config, $phpbb_root_path, $phpEx, $user; + + // Which forums should not be searched ? + $exclude_forums = array(); + + $sql = 'SELECT forum_id + FROM ' . FORUMS_TABLE . ' + WHERE ' . $db->sql_bit_and('forum_options', FORUM_OPTION_FEED_EXCLUDE, '<> 0'); + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $exclude_forums[] = (int) $row['forum_id']; + } + $db->sql_freeresult($result); + + // Exclude forums the user is not able to read + $this->excluded_forums_ary = array_keys($auth->acl_getf('!f_read', true)); + $this->excluded_forums_ary = (sizeof($exclude_forums)) ? array_merge($exclude_forums, $this->excluded_forums_ary) : $this->excluded_forums_ary; + + $not_in_fid = (sizeof($this->excluded_forums_ary)) ? 'WHERE (' . $db->sql_in_set('f.forum_id', $this->excluded_forums_ary, true) . ' AND ' . $db->sql_in_set('f.parent_id', $this->excluded_forums_ary, true) . ") OR (f.forum_password <> '' AND fa.user_id <> " . (int) $user->data['user_id'] . ')' : ''; + + $sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.right_id, f.forum_password, fa.user_id + FROM ' . FORUMS_TABLE . ' f + LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa ON (fa.forum_id = f.forum_id + AND fa.session_id = '" . $db->sql_escape($user->session_id) . "') + $not_in_fid + ORDER BY f.left_id"; + $result = $db->sql_query($sql); + + $right_id = 0; + while ($row = $db->sql_fetchrow($result)) + { + // Exclude passworded forum completely + if ($row['forum_password'] && $row['user_id'] != $user->data['user_id']) + { + $this->excluded_forums_ary[] = (int) $row['forum_id']; + continue; + } + + if ($row['right_id'] > $right_id) + { + $right_id = (int) $row['right_id']; + } + else if ($row['right_id'] < $right_id) + { + continue; + } + } + $db->sql_freeresult($result); + + return $this->excluded_forums_ary; + } + + /** + * Get SQL query for fetching items + */ + function get_sql() + { + global $db; + + $post_ids = array(); + + // Search for topics in last X days + $last_post_time_sql = ($this->sort_days) ? ' AND t.topic_last_post_time > ' . (time() - ($this->sort_days * 24 * 3600)) : ''; + + // Fetch latest post, grouped by topic... + if (!$this->forum_id && !$this->topic_id) + { + // First of all, the post ids... + $not_in_fid = (sizeof($this->excluded_forums())) ? ' AND ' . $db->sql_in_set('t.forum_id', $this->excluded_forums(), true) : ''; + + $sql = 'SELECT t.topic_last_post_id + FROM ' . TOPICS_TABLE . ' t + WHERE t.topic_approved = 1 + AND t.topic_moved_id = 0' . + $not_in_fid . + $last_post_time_sql . ' + ORDER BY t.topic_last_post_time DESC'; + $result = $db->sql_query_limit($sql, $this->num_items); + + while ($row = $db->sql_fetchrow($result)) + { + $post_ids[] = (int) $row['topic_last_post_id']; + } + $db->sql_freeresult($result); + } + // Fetch latest posts from forum + else if (!$this->topic_id && $this->forum_id) + { + // Make sure the forum is not listed within the forbidden ones. ;) + if (in_array($this->forum_id, $this->excluded_forums())) + { + return false; + } + + // Determine which forums to fetch + $not_in_fid = (sizeof($this->excluded_forums())) ? ' AND ' . $db->sql_in_set('f1.forum_id', $this->excluded_forums(), true) : ''; + + // Determine forum childs... + $sql = 'SELECT f2.forum_id + FROM ' . FORUMS_TABLE . ' f1, ' . FORUMS_TABLE . ' f2 + WHERE f1.forum_id = ' . $this->forum_id . ' + AND (f2.left_id BETWEEN f1.left_id AND f1.right_id' . $not_in_fid . ')'; + $result = $db->sql_query($sql); + + $forum_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $forum_ids[] = (int) $row['forum_id']; + } + $db->sql_freeresult($result); + + // Now select from forums... + $sql = 'SELECT t.topic_last_post_id + FROM ' . TOPICS_TABLE . ' t + WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . ' + AND t.topic_approved = 1 + AND t.topic_moved_id = 0' . + $last_post_time_sql . ' + ORDER BY t.topic_last_post_time DESC'; + $result = $db->sql_query_limit($sql, $this->num_items); + + while ($row = $db->sql_fetchrow($result)) + { + $post_ids[] = (int) $row['topic_last_post_id']; + } + $db->sql_freeresult($result); + } + // Fetch last posts from specified topic... + else if ($this->topic_id) + { + // First of all, determine the forum... + $sql = 'SELECT forum_id + FROM ' . TOPICS_TABLE . ' + WHERE topic_id = ' . $this->topic_id; + $result = $db->sql_query_limit($sql, 1); + $this->forum_id = (int) $db->sql_fetchfield('forum_id'); + $db->sql_freeresult($result); + + // non-global announcement + if ($this->forum_id && in_array($this->forum_id, $this->excluded_forums())) + { + return false; + } + + $sql = 'SELECT post_id + FROM ' . POSTS_TABLE . ' + WHERE topic_id = ' . $this->topic_id . ' + AND post_approved = 1 + ORDER BY post_time DESC'; + $result = $db->sql_query_limit($sql, $this->num_items); + + while ($row = $db->sql_fetchrow($result)) + { + $post_ids[] = (int) $row['post_id']; + } + $db->sql_freeresult($result); + } + + if (!sizeof($post_ids)) + { + return false; + } + + // Now build sql query for obtaining items + $this->sql = array( + 'SELECT' => 'f.forum_id, f.forum_name, f.forum_desc_options, ' . + 't.topic_last_post_time, t.topic_id, t.topic_title, t.topic_time, t.topic_replies, t.topic_views, ' . + 'p.post_id, p.post_time, p.post_subject, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, ' . + 'u.username, u.user_id, u.user_email, u.user_colour', + 'FROM' => array( + POSTS_TABLE => 'p', + TOPICS_TABLE => 't', + FORUMS_TABLE => 'f', + USERS_TABLE => 'u', + ), + 'WHERE' => $db->sql_in_set('p.post_id', $post_ids) . ' + AND f.forum_id = p.forum_id + AND t.topic_id = p.topic_id + AND u.user_id = p.poster_id', + 'ORDER_BY' => 'p.post_time DESC', + ); + + return true; + } + + function get_item() + { + global $db, $cache; + + // Disable cache if it is not a guest or a bot but a registered user + if ($this->cache_time) + { + global $user; + + // We check this here because we call get_item() quite often + if (!empty($user) && $user->data['is_registered']) + { + $this->cache_time = 0; + } + } + + if (!$this->cache_time) + { + if (empty($this->result)) + { + if (!$this->get_sql()) + { + return false; + } + + // Query database + $sql = $db->sql_build_query('SELECT', $this->sql); + $this->result = $db->sql_query_limit($sql, $this->num_items); + } + + return $db->sql_fetchrow($this->result); + } + else + { + if (empty($this->items_filled)) + { + // Try to load result set... + $cache_filename = substr(get_class($this), strlen('phpbb_')); + + if (($this->items = $cache->get('_' . $cache_filename)) === false) + { + $this->items = array(); + + if ($this->get_sql()) + { + // Query database + $sql = $db->sql_build_query('SELECT', $this->sql); + $result = $db->sql_query_limit($sql, $this->num_items); + + while ($row = $db->sql_fetchrow($result)) + { + $this->items[] = $row; + } + $db->sql_freeresult($result); + } + + $cache->put('_' . $cache_filename, $this->items, $this->cache_time); + } + + $this->items_filled = true; + } + + $row = array_shift($this->items); + return (!$row) ? false : $row; + } + } + + function adjust_item(&$item_row, &$row) + { + global $phpEx, $config; + + $item_row['title'] = (!$this->topic_id) ? $row['forum_name'] . ' ' . $this->separator . ' ' . $item_row['title'] : $item_row['title']; + $item_row['link'] = feed_append_sid('/viewtopic.' . $phpEx, "t={$row['topic_id']}&p={$row['post_id']}#p{$row['post_id']}"); + + if ($config['feed_item_statistics']) + { + global $user; + + $user_link = '' . $row['username'] . ''; + + $time = ($this->topic_id) ? $row['post_time'] : $row['topic_time']; + + $item_row['statistics'] = $user->lang['POSTED'] . ' ' . $user->lang['POST_BY_AUTHOR'] . ' ' . $user_link . ' - ' . $user->format_date($time). ' - ' . $user->lang['REPLIES'] . ' ' . $row['topic_replies'] . ' - ' . $user->lang['VIEWS'] . ' ' . $row['topic_views']; + } + } +} + +class phpbb_feed_forums extends phpbb_feed +{ + function set_keys() + { + global $config; + + $this->set('title', 'forum_name'); + $this->set('text', 'forum_desc'); + $this->set('bitfield', 'forum_desc_bitfield'); + $this->set('bbcode_uid','forum_desc_uid'); + $this->set('date', 'forum_last_post_time'); + $this->set('options', 'forum_desc_options'); + + $this->num_items = $config['feed_overall_forums_limit']; + } + + function open() + { + global $user, $global_vars; + + $global_vars['FEED_MODE'] = $user->lang['FORUMS']; + } + + function get_sql() + { + global $db; + + $not_in_fid = (sizeof($this->excluded_forums())) ? ' AND ' . $db->sql_in_set('f.forum_id', $this->excluded_forums(), true) : ''; + + // Build SQL Query + $this->sql = array( + 'SELECT' => 'f.*', + 'FROM' => array(FORUMS_TABLE => 'f'), + 'WHERE' => 'f.forum_type = ' . FORUM_POST . ' + AND (f.forum_last_post_id > 0' . $not_in_fid . ')', + 'ORDER_BY' => 'f.left_id', + ); + + return true; + } + + function adjust_item(&$item_row, &$row) + { + global $phpEx, $config; + + $item_row['link'] = feed_append_sid('/viewforum.' . $phpEx, 'f=' . $row['forum_id']); + + if ($config['feed_item_statistics']) + { + global $user; + + $item_row['statistics'] = sprintf($user->lang['TOTAL_TOPICS_OTHER'], $row['forum_topics']) . ' - ' . sprintf($user->lang['TOTAL_POSTS_OTHER'], $row['forum_posts']); + } + } +} + +class phpbb_feed_news extends phpbb_feed +{ + function set_keys() + { + global $config; + + $this->set('title', 'topic_title'); + $this->set('title2', 'forum_name'); + $this->set('author_id', 'topic_poster'); + $this->set('creator', 'topic_first_poster_name'); + $this->set('text', 'post_text'); + $this->set('bitfield', 'bbcode_bitfield'); + $this->set('bbcode_uid','bbcode_uid'); + $this->set('date', 'topic_time'); + + $this->set('enable_bbcode', 'enable_bbcode'); + $this->set('enable_smilies', 'enable_smilies'); + $this->set('enable_magic_url', 'enable_magic_url'); + + $this->num_items = (int) $config['feed_overall_forums_limit']; + } + + function open() + { + global $user, $global_vars; + + $global_vars['FEED_MODE'] = $user->lang['FEED_NEWS']; + } + + function get_sql() + { + global $db, $config; + + // Get news forums... + $sql = 'SELECT forum_id + FROM ' . FORUMS_TABLE . ' + WHERE ' . $db->sql_bit_and('forum_options', FORUM_OPTION_FEED_NEWS, '<> 0'); + $result = $db->sql_query($sql); + + $in_fid_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $in_fid_ary[] = (int) $row['forum_id']; + } + $db->sql_freeresult($result); + + if (!sizeof($in_fid_ary)) + { + return false; + } + + // Build SQL Query + $this->sql = array( + 'SELECT' => 'f.forum_id, f.forum_password, f.forum_name, f.forum_topics, f.forum_posts, f.parent_id, f.left_id, f.right_id, + t.topic_id, t.topic_title, t.topic_poster, t.topic_first_poster_name, t.topic_replies, t.topic_views, t.topic_time, + p.post_id, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, + u.username, u.user_id, u.user_email, u.user_colour', + 'FROM' => array( + TOPICS_TABLE => 't', + FORUMS_TABLE => 'f', + POSTS_TABLE => 'p', + USERS_TABLE => 'u', + ), + 'WHERE' => $db->sql_in_set('t.forum_id', $in_fid_ary) . ' + AND f.forum_id = t.forum_id + AND p.post_id = t.topic_first_post_id + AND t.topic_poster = u.user_id + AND t.topic_moved_id = 0', + 'ORDER_BY' => 't.topic_time DESC', + ); + + return true; + } + + function adjust_item(&$item_row, &$row) + { + global $phpEx, $config; + + $item_row['link'] = feed_append_sid('/viewtopic.' . $phpEx, 't=' . $row['topic_id'] . '&p=' . $row['post_id'] . '#p' . $row['post_id']); + + if ($config['feed_item_statistics']) + { + global $user; + + $user_link = '' . $row[$this->get('creator')] . ''; + + $item_row['statistics'] = $user->lang['POSTED'] . ' ' . $user->lang['POST_BY_AUTHOR'] . ' ' . $user_link . ' - ' . $user->format_date($row['topic_time']). ' - ' . $user->lang['REPLIES'] . ' ' . $row['topic_replies'] . ' - ' . $user->lang['VIEWS'] . ' ' . $row['topic_views']; + } + } +} + +class phpbb_feed_topics extends phpbb_feed +{ + function set_keys() + { + global $config; + + $this->set('title', 'topic_title'); + $this->set('title2', 'forum_name'); + $this->set('author_id', 'topic_poster'); + $this->set('creator', 'topic_first_poster_name'); + $this->set('text', 'post_text'); + $this->set('bitfield', 'bbcode_bitfield'); + $this->set('bbcode_uid','bbcode_uid'); + $this->set('date', 'topic_time'); + + $this->set('enable_bbcode', 'enable_bbcode'); + $this->set('enable_smilies', 'enable_smilies'); + $this->set('enable_magic_url', 'enable_magic_url'); + + $this->num_items = (int) $config['feed_overall_topics_limit']; + } + + function open() + { + global $user, $global_vars; + + $global_vars['FEED_MODE'] = $user->lang['TOPICS']; + } + + function get_sql() + { + global $db, $config; + + $post_ids = array(); + $not_in_fid = (sizeof($this->excluded_forums())) ? ' AND ' . $db->sql_in_set('t.forum_id', $this->excluded_forums(), true) : ''; + + // Search for topics in last x days + $last_post_time_sql = ($this->sort_days) ? ' AND t.topic_last_post_time > ' . (time() - ($this->sort_days * 24 * 3600)) : ''; + + // Last x topics from all forums, with first post from topic... + $sql = 'SELECT t.topic_first_post_id + FROM ' . TOPICS_TABLE . ' t + WHERE t.topic_approved = 1 + AND t.topic_moved_id = 0' . + $not_in_fid . + $last_post_time_sql . ' + ORDER BY t.topic_last_post_time DESC'; + $result = $db->sql_query_limit($sql, $this->num_items); + + while ($row = $db->sql_fetchrow($result)) + { + $post_ids[] = (int) $row['topic_first_post_id']; + } + $db->sql_freeresult($result); + + if (!sizeof($post_ids)) + { + return false; + } + + $this->sql = array( + 'SELECT' => 'f.forum_id, f.forum_password, f.forum_name, f.forum_topics, f.forum_posts, f.parent_id, f.left_id, f.right_id, + t.topic_id, t.topic_title, t.topic_poster, t.topic_first_poster_name, t.topic_replies, t.topic_views, t.topic_time, + p.post_id, p.post_text, p.bbcode_bitfield, p.bbcode_uid, p.enable_bbcode, p.enable_smilies, p.enable_magic_url, + u.username, u.user_id, u.user_email, u.user_colour', + 'FROM' => array( + TOPICS_TABLE => 't', + FORUMS_TABLE => 'f', + POSTS_TABLE => 'p', + USERS_TABLE => 'u', + ), + 'WHERE' => $db->sql_in_set('p.post_id', $post_ids) . ' + AND f.forum_id = p.forum_id + AND t.topic_id = p.topic_id + AND u.user_id = p.poster_id', + 'ORDER_BY' => 't.topic_last_post_time DESC', + ); + + return true; + } + + function adjust_item(&$item_row, &$row) + { + global $phpEx, $config; + + $item_row['link'] = feed_append_sid('/viewtopic.' . $phpEx, 't=' . $row['topic_id'] . '&p=' . $row['post_id'] . '#p' . $row['post_id']); + + if ($config['feed_item_statistics']) + { + global $user; + + $user_link = '' . $row[$this->get('creator')] . ''; + + $item_row['statistics'] = $user->lang['POSTED'] . ' ' . $user->lang['POST_BY_AUTHOR'] . ' ' . $user_link . ' - ' . $user->format_date($row['topic_time']). ' - ' . $user->lang['REPLIES'] . ' ' . $row['topic_replies'] . ' - ' . $user->lang['VIEWS'] . ' ' . $row['topic_views']; + } + } +} + + +?> \ No newline at end of file diff --git a/phpBB/includes/acm/acm_apc.php b/phpBB/includes/acm/acm_apc.php new file mode 100644 index 0000000000..1a487f94ad --- /dev/null +++ b/phpBB/includes/acm/acm_apc.php @@ -0,0 +1,84 @@ +key_prefix . $var); + } + + /** + * Store data in the cache + * + * @access protected + * @param string $var Cache key + * @param mixed $data Data to store + * @param int $ttl Time-to-live of cached data + * @return bool True if the operation succeeded + */ + function _write($var, $data, $ttl = 2592000) + { + return apc_store($this->key_prefix . $var, $data, $ttl); + } + + /** + * Remove an item from the cache + * + * @access protected + * @param string $var Cache key + * @return bool True if the operation succeeded + */ + function _delete($var) + { + return apc_delete($this->key_prefix . $var); + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/acm/acm_eaccelerator.php b/phpBB/includes/acm/acm_eaccelerator.php new file mode 100644 index 0000000000..1a3cf3c0f7 --- /dev/null +++ b/phpBB/includes/acm/acm_eaccelerator.php @@ -0,0 +1,120 @@ +key_prefix + eaccelerator_rm(substr($var['name'], 1)); + } + + parent::purge(); + } + + /** + * Perform cache garbage collection + * + * @return void + */ + function tidy() + { + eaccelerator_gc(); + + set_config('cache_last_gc', time(), true); + } + + /** + * Fetch an item from the cache + * + * @access protected + * @param string $var Cache key + * @return mixed Cached data + */ + function _read($var) + { + $result = eaccelerator_get($this->key_prefix . $var); + + if ($result === null) + { + return false; + } + + // Handle serialized objects + if (is_string($result) && strpos($result, $this->serialize_header . 'O:') === 0) + { + $result = unserialize(substr($result, strlen($this->serialize_header))); + } + + return $result; + } + + /** + * Store data in the cache + * + * @access protected + * @param string $var Cache key + * @param mixed $data Data to store + * @param int $ttl Time-to-live of cached data + * @return bool True if the operation succeeded + */ + function _write($var, $data, $ttl = 2592000) + { + // Serialize objects and make them easy to detect + $data = (is_object($data)) ? $this->serialize_header . serialize($data) : $data; + + return eaccelerator_put($this->key_prefix . $var, $data, $ttl); + } + + /** + * Remove an item from the cache + * + * @access protected + * @param string $var Cache key + * @return bool True if the operation succeeded + */ + function _delete($var) + { + return eaccelerator_rm($this->key_prefix . $var); + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/acm/acm_file.php b/phpBB/includes/acm/acm_file.php index f9ff92e19d..234be5c5d1 100644 --- a/phpBB/includes/acm/acm_file.php +++ b/phpBB/includes/acm/acm_file.php @@ -3,7 +3,7 @@ * * @package acm * @version $Id$ -* @copyright (c) 2005 phpBB Group +* @copyright (c) 2005, 2009 phpBB Group * @license http://opensource.org/licenses/gpl-license.php GNU Public License * */ @@ -44,17 +44,7 @@ class acm */ function load() { - global $phpEx; - if (file_exists($this->cache_dir . 'data_global.' . $phpEx)) - { - @include($this->cache_dir . 'data_global.' . $phpEx); - } - else - { - return false; - } - - return true; + return $this->_read('data_global'); } /** @@ -86,22 +76,7 @@ class acm global $phpEx; - if ($fp = @fopen($this->cache_dir . 'data_global.' . $phpEx, 'wb')) - { - @flock($fp, LOCK_EX); - fwrite($fp, "vars = " . var_export($this->vars, true) . ";\n\n\$this->var_expires = " . var_export($this->var_expires, true) . "\n?>"); - @flock($fp, LOCK_UN); - fclose($fp); - - if (!function_exists('phpbb_chmod')) - { - global $phpbb_root_path; - include($phpbb_root_path . 'includes/functions.' . $phpEx); - } - - phpbb_chmod($this->cache_dir . 'data_global.' . $phpEx, CHMOD_READ | CHMOD_WRITE); - } - else + if (!$this->_write('data_global')) { // Now, this occurred how often? ... phew, just tell the user then... if (!@is_writable($this->cache_dir)) @@ -132,6 +107,8 @@ class acm return; } + $time = time(); + while (($entry = readdir($dir)) !== false) { if (!preg_match('/^(sql_|data_(?!global))/', $entry)) @@ -139,9 +116,20 @@ class acm continue; } - $expired = true; - @include($this->cache_dir . $entry); - if ($expired) + if (!($handle = @fopen($this->cache_dir . $entry, 'rb'))) + { + continue; + } + + // Skip the PHP header + fgets($handle); + + // Skip expiration + $expires = (int) fgets($handle); + + fclose($handle); + + if ($time >= $expires) { $this->remove_file($this->cache_dir . $entry); } @@ -157,7 +145,7 @@ class acm foreach ($this->var_expires as $var_name => $expires) { - if (time() > $expires) + if ($time >= $expires) { $this->destroy($var_name); } @@ -181,8 +169,7 @@ class acm return false; } - @include($this->cache_dir . "data{$var_name}.$phpEx"); - return (isset($data)) ? $data : false; + return $this->_read('data' . $var_name); } else { @@ -197,23 +184,7 @@ class acm { if ($var_name[0] == '_') { - global $phpEx; - - if ($fp = @fopen($this->cache_dir . "data{$var_name}.$phpEx", 'wb')) - { - @flock($fp, LOCK_EX); - fwrite($fp, " " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n\n\$data = " . (sizeof($var) ? "unserialize(" . var_export(serialize($var), true) . ");" : 'array();') . "\n\n?>"); - @flock($fp, LOCK_UN); - fclose($fp); - - if (!function_exists('phpbb_chmod')) - { - global $phpbb_root_path; - include($phpbb_root_path . 'includes/functions.' . $phpEx); - } - - phpbb_chmod($this->cache_dir . "data{$var_name}.$phpEx", CHMOD_READ | CHMOD_WRITE); - } + $this->_write('data' . $var_name, $var, time() + $ttl); } else { @@ -288,32 +259,31 @@ class acm continue; } - // The following method is more failproof than simply assuming the query is on line 3 (which it should be) - $check_line = @file_get_contents($this->cache_dir . $entry); - - if (empty($check_line)) + if (!($handle = @fopen($this->cache_dir . $entry, 'rb'))) { continue; } - // Now get the contents between /* and */ - $check_line = substr($check_line, strpos($check_line, '/* ') + 3, strpos($check_line, ' */') - strpos($check_line, '/* ') - 3); + // Skip the PHP header + fgets($handle); + + // Skip expiration + fgets($handle); + + // Grab the query, remove the LF + $query = substr(fgets($handle), 0, -1); + + fclose($handle); - $found = false; foreach ($table as $check_table) { // Better catch partial table names than no table names. ;) - if (strpos($check_line, $check_table) !== false) + if (strpos($query, $check_table) !== false) { - $found = true; + $this->remove_file($this->cache_dir . $entry); break; } } - - if ($found) - { - $this->remove_file($this->cache_dir . $entry); - } } closedir($dir); @@ -371,29 +341,16 @@ class acm */ function sql_load($query) { - global $phpEx; - // Remove extra spaces and tabs $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); + + if (($rowset = $this->_read('sql_' . md5($query))) === false) + { + return false; + } + $query_id = sizeof($this->sql_rowset); - - if (!file_exists($this->cache_dir . 'sql_' . md5($query) . ".$phpEx")) - { - return false; - } - - @include($this->cache_dir . 'sql_' . md5($query) . ".$phpEx"); - - if (!isset($expired)) - { - return false; - } - else if ($expired) - { - $this->remove_file($this->cache_dir . 'sql_' . md5($query) . ".$phpEx", true); - return false; - } - + $this->sql_rowset[$query_id] = $rowset; $this->sql_row_pointer[$query_id] = 0; return $query_id; @@ -404,41 +361,23 @@ class acm */ function sql_save($query, &$query_result, $ttl) { - global $db, $phpEx; + global $db; // Remove extra spaces and tabs $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); - $filename = $this->cache_dir . 'sql_' . md5($query) . '.' . $phpEx; - if ($fp = @fopen($filename, 'wb')) + $query_id = sizeof($this->sql_rowset); + $this->sql_rowset[$query_id] = array(); + $this->sql_row_pointer[$query_id] = 0; + + while ($row = $db->sql_fetchrow($query_result)) { - @flock($fp, LOCK_EX); - - $query_id = sizeof($this->sql_rowset); - $this->sql_rowset[$query_id] = array(); - $this->sql_row_pointer[$query_id] = 0; - - while ($row = $db->sql_fetchrow($query_result)) - { - $this->sql_rowset[$query_id][] = $row; - } - $db->sql_freeresult($query_result); - - $file = " " . (time() + $ttl) . ") ? true : false;\nif (\$expired) { return; }\n"; - - fwrite($fp, $file . "\n\$this->sql_rowset[\$query_id] = " . (sizeof($this->sql_rowset[$query_id]) ? "unserialize(" . var_export(serialize($this->sql_rowset[$query_id]), true) . ");" : 'array();') . "\n\n?>"); - @flock($fp, LOCK_UN); - fclose($fp); - - if (!function_exists('phpbb_chmod')) - { - global $phpbb_root_path; - include($phpbb_root_path . 'includes/functions.' . $phpEx); - } - - phpbb_chmod($filename, CHMOD_READ | CHMOD_WRITE); + $this->sql_rowset[$query_id][] = $row; + } + $db->sql_freeresult($query_result); + if ($this->_write('sql_' . md5($query), $this->sql_rowset[$query_id], $ttl + time(), $query)) + { $query_result = $query_id; } } @@ -507,6 +446,262 @@ class acm return true; } + /** + * Read cached data from a specified file + * + * @access private + * @param string $filename Filename to write + * @return mixed False if an error was encountered, otherwise the data type of the cached data + */ + function _read($filename) + { + global $phpEx; + + $file = "{$this->cache_dir}$filename.$phpEx"; + + $type = substr($filename, 0, strpos($filename, '_')); + + if (!file_exists($file)) + { + return false; + } + + if (!($handle = @fopen($file, 'rb'))) + { + return false; + } + + // Skip the PHP header + fgets($handle); + + if ($filename == 'data_global') + { + $this->vars = $this->var_expires = array(); + + $time = time(); + + while (($expires = (int) fgets($handle)) && !feof($handle)) + { + // Number of bytes of data + $bytes = substr(fgets($handle), 0, -1); + + if (!is_numeric($bytes) || ($bytes = (int) $bytes) === 0) + { + // We cannot process the file without a valid number of bytes + // so we discard it + fclose($handle); + + $this->vars = $this->var_expires = array(); + $this->is_modified = false; + + $this->remove_file($file); + + return false; + } + + if ($time >= $expires) + { + fseek($handle, $bytes, SEEK_CUR); + + continue; + } + + $var_name = substr(fgets($handle), 0, -1); + + // Read the length of bytes that consists of data. + $data = fread($handle, $bytes - strlen($var_name)); + $data = @unserialize($data); + + // Don't use the data if it was invalid + if ($data !== false) + { + $this->vars[$var_name] = $data; + $this->var_expires[$var_name] = $expires; + } + + // Absorb the LF + fgets($handle); + } + + fclose($handle); + + $this->is_modified = false; + + return true; + } + else + { + $data = false; + $line = 0; + + while (($buffer = fgets($handle)) && !feof($handle)) + { + $buffer = substr($buffer, 0, -1); // Remove the LF + + // $buffer is only used to read integers + // if it is non numeric we have an invalid + // cache file, which we will now remove. + if (!is_numeric($buffer)) + { + break; + } + + if ($line == 0) + { + $expires = (int) $buffer; + + if (time() >= $expires) + { + break; + } + + if ($type == 'sql') + { + // Skip the query + fgets($handle); + } + } + else if ($line == 1) + { + $bytes = (int) $buffer; + + // Never should have 0 bytes + if (!$bytes) + { + break; + } + + // Grab the serialized data + $data = fread($handle, $bytes); + + // Read 1 byte, to trigger EOF + fread($handle, 1); + + if (!feof($handle)) + { + // Somebody tampered with our data + $data = false; + } + break; + } + else + { + // Something went wrong + break; + } + $line++; + } + fclose($handle); + + // unserialize if we got some data + $data = ($data !== false) ? @unserialize($data) : $data; + + if ($data === false) + { + $this->remove_file($file); + return false; + } + + return $data; + } + } + + /** + * Write cache data to a specified file + * + * 'data_global' is a special case and the generated format is different for this file: + * + * + * (expiration) + * (length of var and serialised data) + * (var) + * (serialised data) + * ... (repeat) + * + * + * The other files have a similar format: + * + * + * (expiration) + * (query) [SQL files only] + * (length of serialised data) + * (serialised data) + * + * + * @access private + * @param string $filename Filename to write + * @param mixed $data Data to store + * @param int $expires Timestamp when the data expires + * @param string $query Query when caching SQL queries + * @return bool True if the file was successfully created, otherwise false + */ + function _write($filename, $data = null, $expires = 0, $query = '') + { + global $phpEx; + + $file = "{$this->cache_dir}$filename.$phpEx"; + + if ($handle = @fopen($file, 'wb')) + { + @flock($handle, LOCK_EX); + + // File header + fwrite($handle, '<' . '?php exit; ?' . '>'); + + if ($filename == 'data_global') + { + // Global data is a different format + foreach ($this->vars as $var => $data) + { + if (strpos($var, "\r") !== false || strpos($var, "\n") !== false) + { + // CR/LF would cause fgets() to read the cache file incorrectly + // do not cache test entries, they probably won't be read back + // the cache keys should really be alphanumeric with a few symbols. + continue; + } + $data = serialize($data); + + // Write out the expiration time + fwrite($handle, "\n" . $this->var_expires[$var] . "\n"); + + // Length of the remaining data for this var (ignoring two LF's) + fwrite($handle, strlen($data . $var) . "\n"); + fwrite($handle, $var . "\n"); + fwrite($handle, $data); + } + } + else + { + fwrite($handle, "\n" . $expires . "\n"); + + if (strpos($filename, 'sql_') === 0) + { + fwrite($handle, $query . "\n"); + } + $data = serialize($data); + + fwrite($handle, strlen($data) . "\n"); + fwrite($handle, $data); + } + + @flock($handle, LOCK_UN); + fclose($handle); + + if (!function_exists('phpbb_chmod')) + { + global $phpbb_root_path; + include($phpbb_root_path . 'includes/functions.' . $phpEx); + } + + phpbb_chmod($file, CHMOD_READ | CHMOD_WRITE); + + return true; + } + + return false; + } + /** * Removes/unlinks file */ diff --git a/phpBB/includes/acm/acm_memcache.php b/phpBB/includes/acm/acm_memcache.php new file mode 100644 index 0000000000..3077ee9615 --- /dev/null +++ b/phpBB/includes/acm/acm_memcache.php @@ -0,0 +1,124 @@ +memcache = new Memcache; + $this->memcache->connect(PHPBB_ACM_MEMCACHE_HOST, PHPBB_ACM_MEMCACHE_PORT); + $this->flags = (PHPBB_ACM_MEMCACHE_COMPRESS) ? MEMCACHE_COMPRESSED : 0; + } + + /** + * Unload the cache resources + * + * @return void + */ + function unload() + { + parent::unload(); + + $this->memcache->close(); + } + + /** + * Purge cache data + * + * @return void + */ + function purge() + { + $this->memcache->flush(); + + parent::purge(); + } + + /** + * Fetch an item from the cache + * + * @access protected + * @param string $var Cache key + * @return mixed Cached data + */ + function _read($var) + { + return $this->memcache->get($this->key_prefix . $var); + } + + /** + * Store data in the cache + * + * @access protected + * @param string $var Cache key + * @param mixed $data Data to store + * @param int $ttl Time-to-live of cached data + * @return bool True if the operation succeeded + */ + function _write($var, $data, $ttl = 2592000) + { + return $this->memcache->set($this->key_prefix . $var, $data, $this->flags, $ttl); + } + + /** + * Remove an item from the cache + * + * @access protected + * @param string $var Cache key + * @return bool True if the operation succeeded + */ + function _delete($var) + { + return $this->memcache->delete($this->key_prefix . $var); + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/acm/acm_memory.php b/phpBB/includes/acm/acm_memory.php new file mode 100644 index 0000000000..1ed4fb0d55 --- /dev/null +++ b/phpBB/includes/acm/acm_memory.php @@ -0,0 +1,426 @@ +cache_dir = $phpbb_root_path . 'cache/'; + $this->key_prefix = substr(md5($dbname . $table_prefix), 0, 8) . '_'; + + if (!isset($this->extension) || !extension_loaded($this->extension)) + { + global $acm_type; + + trigger_error("Could not find required extension [{$this->extension}] for the ACM module $acm_type.", E_USER_ERROR); + } + } + + /** + * Load global cache + */ + function load() + { + // grab the global cache + $this->vars = $this->_read('global'); + + if ($this->vars !== false) + { + return true; + } + + return false; + } + + /** + * Unload cache object + */ + function unload() + { + $this->save(); + unset($this->vars); + unset($this->sql_rowset); + unset($this->sql_row_pointer); + + $this->vars = array(); + $this->sql_rowset = array(); + $this->sql_row_pointer = array(); + } + + /** + * Save modified objects + */ + function save() + { + if (!$this->is_modified) + { + return; + } + + $this->_write('global', $this->vars, 2592000); + + $this->is_modified = false; + } + + /** + * Tidy cache + */ + function tidy() + { + // cache has auto GC, no need to have any code here :) + + set_config('cache_last_gc', time(), true); + } + + /** + * Get saved cache object + */ + function get($var_name) + { + if ($var_name[0] == '_') + { + if (!$this->_exists($var_name)) + { + return false; + } + + return $this->_read($var_name); + } + else + { + return ($this->_exists($var_name)) ? $this->vars[$var_name] : false; + } + } + + /** + * Put data into cache + */ + function put($var_name, $var, $ttl = 2592000) + { + if ($var_name[0] == '_') + { + $this->_write($var_name, $var, $ttl); + } + else + { + $this->vars[$var_name] = $var; + $this->is_modified = true; + } + } + + /** + * Purge cache data + */ + function purge() + { + // Purge all phpbb cache files + $dir = @opendir($this->cache_dir); + + if (!$dir) + { + return; + } + + while (($entry = readdir($dir)) !== false) + { + if (strpos($entry, 'sql_') !== 0 && strpos($entry, 'data_') !== 0 && strpos($entry, 'ctpl_') !== 0 && strpos($entry, 'tpl_') !== 0) + { + continue; + } + + $this->remove_file($this->cache_dir . $entry); + } + closedir($dir); + + unset($this->vars); + unset($this->sql_rowset); + unset($this->sql_row_pointer); + + $this->vars = array(); + $this->sql_rowset = array(); + $this->sql_row_pointer = array(); + + $this->is_modified = false; + } + + + /** + * Destroy cache data + */ + function destroy($var_name, $table = '') + { + if ($var_name == 'sql' && !empty($table)) + { + if (!is_array($table)) + { + $table = array($table); + } + + foreach ($table as $table_name) + { + // gives us the md5s that we want + $temp = $this->_read('sql_' . $table_name); + + if ($temp === false) + { + continue; + } + + // delete each query ref + foreach ($temp as $md5_id => $void) + { + $this->_delete('sql_' . $md5_id); + } + + // delete the table ref + $this->_delete('sql_' . $table_name); + } + + return; + } + + if (!$this->_exists($var_name)) + { + return; + } + + if ($var_name[0] == '_') + { + $this->_delete($var_name); + } + else if (isset($this->vars[$var_name])) + { + $this->is_modified = true; + unset($this->vars[$var_name]); + + // We save here to let the following cache hits succeed + $this->save(); + } + } + + /** + * Check if a given cache entry exist + */ + function _exists($var_name) + { + if ($var_name[0] == '_') + { + return $this->_isset($var_name); + } + else + { + if (!sizeof($this->vars)) + { + $this->load(); + } + + return isset($this->vars[$var_name]); + } + } + + /** + * Load cached sql query + */ + function sql_load($query) + { + // Remove extra spaces and tabs + $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); + $query_id = sizeof($this->sql_rowset); + + if (($result = $this->_read('sql_' . md5($query))) === false) + { + return false; + } + + $this->sql_rowset[$query_id] = $result; + $this->sql_row_pointer[$query_id] = 0; + + return $query_id; + } + + /** + * Save sql query + */ + function sql_save($query, &$query_result, $ttl) + { + global $db; + + // Remove extra spaces and tabs + $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); + $hash = md5($query); + + // determine which tables this query belongs to + // Some queries use backticks, namely the get_database_size() query + // don't check for conformity, the SQL would error and not reach here. + if (!preg_match('/FROM \\(?(`?\\w+`?(?: \\w+)?(?:, ?`?\\w+`?(?: \\w+)?)*)\\)?/', $query, $regs)) + { + // Bail out if the match fails. + return; + } + $tables = array_map('trim', explode(',', $regs[1])); + + foreach ($tables as $table_name) + { + // Remove backticks + $table_name = ($table_name[0] == '`') ? substr($table_name, 1, -1) : $table_name; + + if (($pos = strpos($table_name, ' ')) !== false) + { + $table_name = substr($table_name, 0, $pos); + } + + $temp = $this->_read('sql_' . $table_name); + + if ($temp === false) + { + $temp = array(); + } + + $temp[$hash] = true; + + // This must never expire + $this->_write('sql_' . $table_name, $temp, 0); + } + + // store them in the right place + $query_id = sizeof($this->sql_rowset); + $this->sql_rowset[$query_id] = array(); + $this->sql_row_pointer[$query_id] = 0; + + while ($row = $db->sql_fetchrow($query_result)) + { + $this->sql_rowset[$query_id][] = $row; + } + $db->sql_freeresult($query_result); + + $this->_write('sql_' . $hash, $this->sql_rowset[$query_id], $ttl); + + $query_result = $query_id; + } + + /** + * Ceck if a given sql query exist in cache + */ + function sql_exists($query_id) + { + return isset($this->sql_rowset[$query_id]); + } + + /** + * Fetch row from cache (database) + */ + function sql_fetchrow($query_id) + { + if ($this->sql_row_pointer[$query_id] < sizeof($this->sql_rowset[$query_id])) + { + return $this->sql_rowset[$query_id][$this->sql_row_pointer[$query_id]++]; + } + + return false; + } + + /** + * Fetch a field from the current row of a cached database result (database) + */ + function sql_fetchfield($query_id, $field) + { + 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 false; + } + + /** + * Seek a specific row in an a cached database result (database) + */ + function sql_rowseek($rownum, $query_id) + { + if ($rownum >= sizeof($this->sql_rowset[$query_id])) + { + return false; + } + + $this->sql_row_pointer[$query_id] = $rownum; + return true; + } + + /** + * Free memory used for a cached database result (database) + */ + function sql_freeresult($query_id) + { + if (!isset($this->sql_rowset[$query_id])) + { + return false; + } + + unset($this->sql_rowset[$query_id]); + unset($this->sql_row_pointer[$query_id]); + + return true; + } + + /** + * Removes/unlinks file + */ + function remove_file($filename, $check = false) + { + if ($check && !@is_writable($this->cache_dir)) + { + // E_USER_ERROR - not using language entry - intended. + trigger_error('Unable to remove files within ' . $this->cache_dir . '. Please check directory permissions.', E_USER_ERROR); + } + + return @unlink($filename); + } + + /** + * Check if a cache var exists + * + * @access protected + * @param string $var Cache key + * @return bool True if it exists, otherwise false + */ + function _isset($var) + { + // Most caches don't need to check + return true; + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/acm/acm_null.php b/phpBB/includes/acm/acm_null.php new file mode 100644 index 0000000000..fca67115a7 --- /dev/null +++ b/phpBB/includes/acm/acm_null.php @@ -0,0 +1,156 @@ + \ No newline at end of file diff --git a/phpBB/includes/acm/acm_xcache.php b/phpBB/includes/acm/acm_xcache.php new file mode 100644 index 0000000000..d0a614660c --- /dev/null +++ b/phpBB/includes/acm/acm_xcache.php @@ -0,0 +1,121 @@ + 0 +* - xcache.admin.enable_auth = off (or xcache.admin.user and xcache.admin.password set) +* +*/ +class acm extends acm_memory +{ + var $extension = 'XCache'; + + function acm() + { + parent::acm_memory(); + + if (!function_exists('ini_get') || (int) ini_get('xcache.var_size') <= 0) + { + trigger_error('Increase xcache.var_size setting above 0 or enable ini_get() to use this ACM module.', E_USER_ERROR); + } + } + + /** + * Purge cache data + * + * @return void + */ + function purge() + { + // Run before for XCache, if admin functions are disabled it will terminate execution + parent::purge(); + + // If the admin authentication is enabled but not set up, this will cause a nasty error. + // Not much we can do about it though. + $n = xcache_count(XC_TYPE_VAR); + + for ($i = 0; $i < $n; $i++) + { + xcache_clear_cache(XC_TYPE_VAR, $i); + } + } + + /** + * Fetch an item from the cache + * + * @access protected + * @param string $var Cache key + * @return mixed Cached data + */ + function _read($var) + { + $result = xcache_get($this->key_prefix . $var); + + return ($result !== null) ? $result : false; + } + + /** + * Store data in the cache + * + * @access protected + * @param string $var Cache key + * @param mixed $data Data to store + * @param int $ttl Time-to-live of cached data + * @return bool True if the operation succeeded + */ + function _write($var, $data, $ttl = 2592000) + { + return xcache_set($this->key_prefix . $var, $data, $ttl); + } + + /** + * Remove an item from the cache + * + * @access protected + * @param string $var Cache key + * @return bool True if the operation succeeded + */ + function _delete($var) + { + return xcache_unset($this->key_prefix . $var); + } + + /** + * Check if a cache var exists + * + * @access protected + * @param string $var Cache key + * @return bool True if it exists, otherwise false + */ + function _isset($var) + { + return xcache_isset($this->key_prefix . $var); + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/acp/acp_attachments.php b/phpBB/includes/acp/acp_attachments.php index ef20b48cec..849c076f0e 100644 --- a/phpBB/includes/acp/acp_attachments.php +++ b/phpBB/includes/acp/acp_attachments.php @@ -684,8 +684,9 @@ class acp_attachments $ext_group_row['max_filesize'] = (int) $config['max_filesize']; } - $size_format = ($ext_group_row['max_filesize'] >= 1048576) ? 'mb' : (($ext_group_row['max_filesize'] >= 1024) ? 'kb' : 'b'); - $ext_group_row['max_filesize'] = get_formatted_filesize($ext_group_row['max_filesize'], false); + $max_filesize = get_formatted_filesize($ext_group_row['max_filesize'], false, array('mb', 'kb', 'b')); + $size_format = $max_filesize['si_identifier']; + $ext_group_row['max_filesize'] = $max_filesize['value']; $img_path = $config['upload_icons_path']; @@ -694,7 +695,7 @@ class acp_attachments $imglist = filelist($phpbb_root_path . $img_path); - if (sizeof($imglist)) + if (!empty($imglist[''])) { $imglist = array_values($imglist); $imglist = $imglist[0]; @@ -1026,8 +1027,8 @@ class acp_attachments $template->assign_block_vars('orphan', array( 'FILESIZE' => get_formatted_filesize($row['filesize']), 'FILETIME' => $user->format_date($row['filetime']), - 'REAL_FILENAME' => basename($row['real_filename']), - 'PHYSICAL_FILENAME' => basename($row['physical_filename']), + 'REAL_FILENAME' => utf8_basename($row['real_filename']), + 'PHYSICAL_FILENAME' => utf8_basename($row['physical_filename']), 'ATTACH_ID' => $row['attach_id'], 'POST_IDS' => (!empty($post_ids[$row['attach_id']])) ? $post_ids[$row['attach_id']] : '', 'U_FILE' => append_sid($phpbb_root_path . 'download/file.' . $phpEx, 'mode=view&id=' . $row['attach_id'])) @@ -1429,8 +1430,9 @@ class acp_attachments function max_filesize($value, $key = '') { // Determine size var and adjust the value accordingly - $size_var = ($value >= 1048576) ? 'mb' : (($value >= 1024) ? 'kb' : 'b'); - $value = get_formatted_filesize($value, false); + $filesize = get_formatted_filesize($value, false, array('mb', 'kb', 'b')); + $size_var = $filesize['si_identifier']; + $value = $filesize['value']; return ' '; } diff --git a/phpBB/includes/acp/acp_ban.php b/phpBB/includes/acp/acp_ban.php index 77fb44dda9..3198376584 100644 --- a/phpBB/includes/acp/acp_ban.php +++ b/phpBB/includes/acp/acp_ban.php @@ -156,7 +156,8 @@ class acp_ban FROM ' . BANLIST_TABLE . ' WHERE (ban_end >= ' . time() . " OR ban_end = 0) - AND ban_ip <> ''"; + AND ban_ip <> '' + ORDER BY ban_ip"; break; case 'email': @@ -168,7 +169,8 @@ class acp_ban FROM ' . BANLIST_TABLE . ' WHERE (ban_end >= ' . time() . " OR ban_end = 0) - AND ban_email <> ''"; + AND ban_email <> '' + ORDER BY ban_email"; break; } $result = $db->sql_query($sql); @@ -181,7 +183,22 @@ class acp_ban $banned_options .= '' . $row[$field] . ''; $time_length = ($row['ban_end']) ? ($row['ban_end'] - $row['ban_start']) / 60 : 0; - $ban_length[$row['ban_id']] = (isset($ban_end_text[$time_length])) ? $ban_end_text[$time_length] : $user->lang['UNTIL'] . ' -> ' . $user->format_date($row['ban_end']); + + if ($time_length == 0) + { + // Banned permanently + $ban_length[$row['ban_id']] = $user->lang['PERMANENT']; + } + else if (isset($ban_end_text[$time_length])) + { + // Banned for a given duration + $ban_length[$row['ban_id']] = sprintf($user->lang['BANNED_UNTIL_DURATION'], $ban_end_text[$time_length], $user->format_date($row['ban_end'], false, true)); + } + else + { + // Banned until given date + $ban_length[$row['ban_id']] = sprintf($user->lang['BANNED_UNTIL_DATE'], $user->format_date($row['ban_end'], false, true)); + } $ban_reasons[$row['ban_id']] = $row['ban_reason']; $ban_give_reasons[$row['ban_id']] = $row['ban_give_reason']; diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php index bce35ee68f..9f0bcf210f 100644 --- a/phpBB/includes/acp/acp_board.php +++ b/phpBB/includes/acp/acp_board.php @@ -64,6 +64,8 @@ class acp_board 'legend2' => 'WARNINGS', 'warnings_expire_days' => array('lang' => 'WARNINGS_EXPIRE', 'validate' => 'int', 'type' => 'text:3:4', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']), + + 'legend3' => 'ACP_SUBMIT_CHANGES', ) ); break; @@ -79,12 +81,14 @@ class acp_board 'allow_namechange' => array('lang' => 'ALLOW_NAME_CHANGE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'allow_attachments' => array('lang' => 'ALLOW_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'allow_pm_attach' => array('lang' => 'ALLOW_PM_ATTACHMENTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_pm_report' => array('lang' => 'ALLOW_PM_REPORT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'allow_bbcode' => array('lang' => 'ALLOW_BBCODE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'allow_smilies' => array('lang' => 'ALLOW_SMILIES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'allow_sig' => array('lang' => 'ALLOW_SIG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), '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), 'legend2' => 'ACP_LOAD_SETTINGS', 'load_birthdays' => array('lang' => 'YES_BIRTHDAYS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), @@ -93,6 +97,8 @@ class acp_board 'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + + 'legend3' => 'ACP_SUBMIT_CHANGES', ) ); break; @@ -108,9 +114,11 @@ class acp_board 'avatar_max_width' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), 'avatar_max_height' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false,), + 'allow_avatar' => array('lang' => 'ALLOW_AVATARS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'allow_avatar_local' => array('lang' => 'ALLOW_LOCAL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'allow_avatar_remote' => array('lang' => 'ALLOW_REMOTE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'allow_avatar_upload' => array('lang' => 'ALLOW_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + 'allow_avatar_remote_upload'=> array('lang' => 'ALLOW_REMOTE_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'avatar_filesize' => array('lang' => 'MAX_FILESIZE', 'validate' => 'int:0', 'type' => 'text:4:10', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']), 'avatar_min' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), 'avatar_max' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), @@ -143,7 +151,9 @@ class acp_board 'forward_pm' => array('lang' => 'ALLOW_FORWARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'auth_img_pm' => array('lang' => 'ALLOW_IMG_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'auth_flash_pm' => array('lang' => 'ALLOW_FLASH_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'enable_pm_icons' => array('lang' => 'ENABLE_PM_ICONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false) + 'enable_pm_icons' => array('lang' => 'ENABLE_PM_ICONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + + 'legend3' => 'ACP_SUBMIT_CHANGES', ) ); break; @@ -162,26 +172,30 @@ 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), 'legend2' => 'POSTING', - 'enable_queue_trigger' => array('lang' => 'ENABLE_QUEUE_TRIGGER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), - 'queue_trigger_posts' => array('lang' => 'QUEUE_TRIGGER_POSTS', 'validate' => 'int:0:250', 'type' => 'text:4:4', 'explain' => true), 'bump_type' => false, 'edit_time' => array('lang' => 'EDIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), + 'delete_time' => array('lang' => 'DELETE_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']), 'display_last_edited' => array('lang' => 'DISPLAY_LAST_EDITED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'flood_interval' => array('lang' => 'FLOOD_INTERVAL', 'validate' => 'int:0', 'type' => 'text:3:10', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']), 'bump_interval' => array('lang' => 'BUMP_INTERVAL', 'validate' => 'int:0', 'type' => 'custom', 'method' => 'bump_interval', 'explain' => true), 'topics_per_page' => array('lang' => 'TOPICS_PER_PAGE', 'validate' => 'int:1', 'type' => 'text:3:4', 'explain' => false), 'posts_per_page' => array('lang' => 'POSTS_PER_PAGE', 'validate' => 'int:1', 'type' => 'text:3:4', 'explain' => false), + 'smilies_per_page' => array('lang' => 'SMILIES_PER_PAGE', 'validate' => 'int:1', 'type' => 'text:3:4', 'explain' => false), 'hot_threshold' => array('lang' => 'HOT_THRESHOLD', 'validate' => 'int:0', 'type' => 'text:3:4', 'explain' => true), 'max_poll_options' => array('lang' => 'MAX_POLL_OPTIONS', 'validate' => 'int:2:127', 'type' => 'text:4:4', 'explain' => false), 'max_post_chars' => array('lang' => 'CHAR_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:6', 'explain' => true), + 'min_post_chars' => array('lang' => 'MIN_CHAR_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:6', 'explain' => true), 'max_post_smilies' => array('lang' => 'SMILIES_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true), 'max_post_urls' => array('lang' => 'MAX_POST_URLS', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true), 'max_post_font_size' => array('lang' => 'MAX_POST_FONT_SIZE', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' %'), 'max_quote_depth' => array('lang' => 'QUOTE_DEPTH_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true), 'max_post_img_width' => array('lang' => 'MAX_POST_IMG_WIDTH', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), 'max_post_img_height' => array('lang' => 'MAX_POST_IMG_HEIGHT', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), + + 'legend3' => 'ACP_SUBMIT_CHANGES', ) ); break; @@ -205,6 +219,8 @@ class acp_board 'max_sig_smilies' => array('lang' => 'MAX_SIG_SMILIES', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true), 'max_sig_img_width' => array('lang' => 'MAX_SIG_IMG_WIDTH', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), 'max_sig_img_height' => array('lang' => 'MAX_SIG_IMG_HEIGHT', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']), + + 'legend3' => 'ACP_SUBMIT_CHANGES', ) ); break; @@ -218,6 +234,8 @@ class acp_board 'max_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:8:255', 'type' => false, 'method' => false, 'explain' => false,), 'require_activation' => array('lang' => 'ACC_ACTIVATION', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_acc_activation', 'explain' => true), + 'new_member_post_limit' => array('lang' => 'NEW_MEMBER_POST_LIMIT', 'validate' => 'int:0:255', 'type' => 'text:4:4', 'explain' => true, 'append' => ' ' . $user->lang['POSTS']), + 'new_member_group_default'=> array('lang' => 'NEW_MEMBER_GROUP_DEFAULT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'min_name_chars' => array('lang' => 'USERNAME_LENGTH', 'validate' => 'int:1', 'type' => 'custom:5:180', 'method' => 'username_length', 'explain' => true), 'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:1', 'type' => 'custom', 'method' => 'password_length', 'explain' => true), 'allow_name_chars' => array('lang' => 'USERNAME_CHARS', 'validate' => 'string', 'type' => 'select', 'method' => 'select_username_chars', 'explain' => true), @@ -235,6 +253,28 @@ class acp_board 'coppa_enable' => array('lang' => 'ENABLE_COPPA', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true), 'coppa_mail' => array('lang' => 'COPPA_MAIL', 'validate' => 'string', 'type' => 'textarea:5:40', 'explain' => true), 'coppa_fax' => array('lang' => 'COPPA_FAX', 'validate' => 'string', 'type' => 'text:25:100', 'explain' => false), + + 'legend4' => 'ACP_SUBMIT_CHANGES', + ) + ); + break; + + case 'feed': + $display_vars = array( + 'title' => 'ACP_FEED_MANAGEMENT', + 'vars' => array( + '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_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 ), + 'feed_news_id' => array('lang' => 'ACP_FEED_NEWS', 'validate' => 'string', 'type' => 'custom', 'method' => 'select_news_forums', 'explain' => true), + 'feed_exclude_id' => array('lang' => 'ACP_FEED_EXCLUDE_ID', 'validate' => 'string', 'type' => 'custom', 'method' => 'select_exclude_forums', 'explain' => true), ) ); break; @@ -279,6 +319,8 @@ class acp_board 'load_cpf_memberlist' => array('lang' => 'LOAD_CPF_MEMBERLIST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_viewprofile' => array('lang' => 'LOAD_CPF_VIEWPROFILE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), 'load_cpf_viewtopic' => array('lang' => 'LOAD_CPF_VIEWTOPIC', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false), + + 'legend4' => 'ACP_SUBMIT_CHANGES', ) ); break; @@ -312,6 +354,8 @@ class acp_board 'server_name' => array('lang' => 'SERVER_NAME', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true), 'server_port' => array('lang' => 'SERVER_PORT', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true), 'script_path' => array('lang' => 'SCRIPT_PATH', 'validate' => 'script_path', 'type' => 'text::255', 'explain' => true), + + 'legend4' => 'ACP_SUBMIT_CHANGES', ) ); break; @@ -360,7 +404,9 @@ class acp_board 'smtp_port' => array('lang' => 'SMTP_PORT', 'validate' => 'int:0', 'type' => 'text:4:5', 'explain' => true), 'smtp_auth_method' => array('lang' => 'SMTP_AUTH_METHOD', 'validate' => 'string', 'type' => 'select', 'method' => 'mail_auth_select', 'explain' => true), 'smtp_username' => array('lang' => 'SMTP_USERNAME', 'validate' => 'string', 'type' => 'text:25:255', 'explain' => true), - 'smtp_password' => array('lang' => 'SMTP_PASSWORD', 'validate' => 'string', 'type' => 'password:25:255', 'explain' => true) + 'smtp_password' => array('lang' => 'SMTP_PASSWORD', 'validate' => 'string', 'type' => 'password:25:255', 'explain' => true), + + 'legend3' => 'ACP_SUBMIT_CHANGES', ) ); break; @@ -400,7 +446,7 @@ class acp_board continue; } - if ($config_name == 'auth_method') + if ($config_name == 'auth_method' || $config_name == 'feed_news_id' || $config_name == 'feed_exclude_id') { continue; } @@ -420,6 +466,13 @@ class acp_board } } + // Store news and exclude ids + if ($mode == 'feed' && $submit) + { + $this->store_feed_forums(FORUM_OPTION_FEED_NEWS, 'feed_news_id'); + $this->store_feed_forums(FORUM_OPTION_FEED_EXCLUDE, 'feed_exclude_id'); + } + if ($mode == 'auth') { // Retrieve a list of auth plugins and check their config values @@ -830,6 +883,75 @@ class acp_board return " "; } + + /** + * Select multiple forums + */ + function select_news_forums($value, $key) + { + global $user, $config; + + $forum_list = make_forum_select(false, false, true, true, true, false, true); + + // Build forum options + $s_forum_options = ''; + + return $s_forum_options; + } + + function select_exclude_forums($value, $key) + { + global $user, $config; + + $forum_list = make_forum_select(false, false, true, false, false, false, true); + + // Build forum options + $s_forum_options = ''; + + return $s_forum_options; + } + + function store_feed_forums($option, $key) + { + global $db, $cache; + + // Get key + $values = request_var($key, array(0 => 0)); + + // Empty option bit for all forums + $sql = 'UPDATE ' . FORUMS_TABLE . ' + SET forum_options = forum_options - ' . (1 << $option) . ' + WHERE ' . $db->sql_bit_and('forum_options', $option, '<> 0'); + $db->sql_query($sql); + + // Already emptied for all... + if (sizeof($values)) + { + // Set for selected forums + $sql = 'UPDATE ' . FORUMS_TABLE . ' + SET forum_options = forum_options + ' . (1 << $option) . ' + WHERE ' . $db->sql_in_set('forum_id', $values); + $db->sql_query($sql); + } + + // Empty sql cache for forums table because options changed + $cache->destroy('sql', FORUMS_TABLE); + } + } ?> \ No newline at end of file diff --git a/phpBB/includes/acp/acp_captcha.php b/phpBB/includes/acp/acp_captcha.php index 93505e1590..6e86f412fb 100644 --- a/phpBB/includes/acp/acp_captcha.php +++ b/phpBB/includes/acp/acp_captcha.php @@ -28,108 +28,120 @@ class acp_captcha global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; $user->add_lang('acp/board'); - $captcha_vars = array( - 'captcha_gd_x_grid' => 'CAPTCHA_GD_X_GRID', - 'captcha_gd_y_grid' => 'CAPTCHA_GD_Y_GRID', - 'captcha_gd_foreground_noise' => 'CAPTCHA_GD_FOREGROUND_NOISE', - 'captcha_gd' => 'CAPTCHA_GD_PREVIEWED', - 'captcha_gd_wave' => 'CAPTCHA_GD_WAVE', - 'captcha_gd_3d_noise' => 'CAPTCHA_GD_3D_NOISE', - 'captcha_gd_fonts' => 'CAPTCHA_GD_FONTS', - ); + include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); - if (isset($_GET['demo'])) + $selected = request_var('select_captcha', $config['captcha_plugin']); + $configure = request_var('configure', false); + + // Oh, they are just here for the view + if (isset($_GET['captcha_demo'])) { - $captcha_vars = array_keys($captcha_vars); - - foreach ($captcha_vars as $captcha_var) - { - $config[$captcha_var] = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, 0) : $config[$captcha_var]; - } - - if ($config['captcha_gd']) - { - include($phpbb_root_path . 'includes/captcha/captcha_gd.' . $phpEx); - } - else - { - include($phpbb_root_path . 'includes/captcha/captcha_non_gd.' . $phpEx); - } - - $captcha = new captcha(); - $captcha->execute(gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)), time()); - exit; + $this->deliver_demo($selected); } - $config_vars = array( - 'enable_confirm' => 'REG_ENABLE', - 'enable_post_confirm' => 'POST_ENABLE', - 'confirm_refresh' => 'CONFIRM_REFRESH', - 'captcha_gd' => 'CAPTCHA_GD', - ); - - $this->tpl_name = 'acp_captcha'; - $this->page_title = 'ACP_VC_SETTINGS'; - $form_key = 'acp_captcha'; - add_form_key($form_key); - - $submit = request_var('submit', ''); - - if ($submit && check_form_key($form_key)) + // Delegate + if ($configure) { - $config_vars = array_keys($config_vars); - - foreach ($config_vars as $config_var) - { - set_config($config_var, request_var($config_var, '')); - } - - $captcha_vars = array_keys($captcha_vars); - - foreach ($captcha_vars as $captcha_var) - { - $value = request_var($captcha_var, 0); - if ($value >= 0) - { - set_config($captcha_var, $value); - } - } - + $config_captcha =& phpbb_captcha_factory::get_instance($selected); + $config_captcha->acp_page($id, $this); add_log('admin', 'LOG_CONFIG_VISUAL'); - trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); - } - else if ($submit) - { - trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action)); } else { - $preview_image_src = append_sid(append_sid("{$phpbb_admin_path}index.$phpEx", "i=$id&demo=demo")); + $captchas = phpbb_captcha_factory::get_captcha_types(); - if (@extension_loaded('gd')) + $config_vars = array( + 'enable_confirm' => array('tpl' => 'REG_ENABLE', 'default' => false), + '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), + ); + + $this->tpl_name = 'acp_captcha'; + $this->page_title = 'ACP_VC_SETTINGS'; + $form_key = 'acp_captcha'; + add_form_key($form_key); + + $submit = request_var('main_submit', false); + + if ($submit && check_form_key($form_key)) { - $template->assign_var('GD', true); - } + foreach ($config_vars as $config_var => $options) + { + set_config($config_var, request_var($config_var, $options['default'])); + } - foreach ($config_vars as $config_var => $template_var) + if ($selected !== $config['captcha_plugin']) + { + // sanity check + if (isset($captchas['available'][$selected])) + { + $old_captcha =& phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $old_captcha->uninstall(); + + set_config('captcha_plugin', $selected); + $new_captcha =& phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $new_captcha->install(); + + add_log('admin', 'LOG_CONFIG_VISUAL'); + } + else + { + trigger_error($user->lang['CAPTCHA_UNAVAILABLE'] . adm_back_link($this->u_action)); + } + } + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action)); + } + else if ($submit) { - $template->assign_var($template_var, (isset($_REQUEST[$config_var])) ? request_var($config_var, '') : $config[$config_var]) ; + trigger_error($user->lang['FORM_INVALID'] . adm_back_link()); } - - foreach ($captcha_vars as $captcha_var => $template_var) + else { - $var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, 0) : $config[$captcha_var]; - $template->assign_var($template_var, $var); - $preview_image_src .= "&$captcha_var=" . $var; - } + $captcha_select = ''; + foreach ($captchas['available'] as $value => $title) + { + $current = ($selected !== false && $value == $selected) ? ' selected="selected"' : ''; + $captcha_select .= ''; + } - $template->assign_vars(array( - 'CAPTCHA_PREVIEW' => $preview_image_src, - 'PREVIEW' => isset($_POST['preview']), - )); + foreach ($captchas['unavailable'] as $value => $title) + { + $current = ($selected !== false && $value == $selected) ? ' selected="selected"' : ''; + $captcha_select .= ''; + } + + $demo_captcha =& phpbb_captcha_factory::get_instance($selected); + + foreach ($config_vars as $config_var => $options) + { + $template->assign_var($options['tpl'], (isset($_POST[$config_var])) ? request_var($config_var, $options['default']) : $config[$config_var]) ; + } + + $template->assign_vars(array( + 'CAPTCHA_PREVIEW_TPL' => $demo_captcha->get_demo_template($id), + 'S_CAPTCHA_HAS_CONFIG' => $demo_captcha->has_config(), + 'CAPTCHA_SELECT' => $captcha_select, + )); + } } } + + /** + * Entry point for delivering image CAPTCHAs in the ACP. + */ + function deliver_demo($selected) + { + global $db, $user, $config; + + $captcha =& phpbb_captcha_factory::get_instance($selected); + $captcha->init(CONFIRM_REG); + $captcha->execute_demo(); + + garbage_collection(); + exit_handler(); + } } ?> \ No newline at end of file diff --git a/phpBB/includes/acp/acp_database.php b/phpBB/includes/acp/acp_database.php index 856b867c9a..b25518e1c4 100644 --- a/phpBB/includes/acp/acp_database.php +++ b/phpBB/includes/acp/acp_database.php @@ -548,7 +548,7 @@ class base_extractor if (!$this->fp) { - trigger_error('Unable to write temporary file to storage folder', E_USER_ERROR); + trigger_error('FILE_WRITE_FAIL', E_USER_ERROR); } } } @@ -1157,16 +1157,17 @@ class postgres_extractor extends base_extractor AND (c.oid = d.adrelid) AND d.adnum = " . $row['attnum']; $def_res = $db->sql_query($sql_get_default); + $def_row = $db->sql_fetchrow($def_res); + $db->sql_freeresult($def_res); - if (!$def_res) + if (empty($def_row)) { unset($row['rowdefault']); } else { - $row['rowdefault'] = $db->sql_fetchfield('rowdefault', false, $def_res); + $row['rowdefault'] = $def_row['rowdefault']; } - $db->sql_freeresult($def_res); if ($row['type'] == 'bpchar') { @@ -1854,7 +1855,8 @@ class oracle_extractor extends base_extractor // Build the SQL statement to recreate the data. for ($i = 0; $i < $i_num_fields; $i++) { - $str_val = $row[$ary_name[$i]]; + // Oracle uses uppercase - we use lowercase + $str_val = $row[strtolower($ary_name[$i])]; if (preg_match('#char|text|bool|raw#i', $ary_type[$i])) { @@ -1885,7 +1887,7 @@ class oracle_extractor extends base_extractor } $schema_vals[$i] = $str_quote . $str_val . $str_quote; - $schema_fields[$i] = '"' . $ary_name[$i] . "'"; + $schema_fields[$i] = '"' . $ary_name[$i] . '"'; } // Take the ordered fields and their associated data and build it diff --git a/phpBB/includes/acp/acp_forums.php b/phpBB/includes/acp/acp_forums.php index bf5242ace6..045d8a2e8e 100644 --- a/phpBB/includes/acp/acp_forums.php +++ b/phpBB/includes/acp/acp_forums.php @@ -75,6 +75,13 @@ class acp_forums trigger_error($user->lang['NO_PERMISSION_FORUM_ADD'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); } + case 'copy_perm': + + if (!(($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth')))) + { + trigger_error($user->lang['NO_PERMISSION_COPY'] . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), E_USER_WARNING); + } + break; } @@ -118,6 +125,7 @@ class acp_forums 'type_action' => request_var('type_action', ''), 'forum_status' => request_var('forum_status', ITEM_UNLOCKED), 'forum_parents' => '', + 'forum_options' => 0, 'forum_name' => utf8_normalize_nfc(request_var('forum_name', '', true)), 'forum_link' => request_var('forum_link', ''), 'forum_link_track' => request_var('forum_link_track', false), @@ -139,6 +147,7 @@ class acp_forums 'enable_icons' => request_var('enable_icons', false), 'enable_prune' => request_var('enable_prune', false), 'enable_post_review' => request_var('enable_post_review', true), + 'enable_quick_reply' => request_var('enable_quick_reply', false), 'prune_days' => request_var('prune_days', 7), 'prune_viewed' => request_var('prune_viewed', 7), 'prune_freq' => request_var('prune_freq', 1), @@ -181,73 +190,22 @@ class acp_forums if (!sizeof($errors)) { $forum_perm_from = request_var('forum_perm_from', 0); + $cache->destroy('sql', FORUMS_TABLE); // Copy permissions? if (!empty($forum_perm_from) && $forum_perm_from != $forum_data['forum_id'] && (($action != 'edit') || empty($forum_id) || ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth')))) { - // if we edit a forum delete current permissions first - if ($action == 'edit') - { - $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' - WHERE forum_id = ' . (int) $forum_data['forum_id']; - $db->sql_query($sql); - - $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' - WHERE forum_id = ' . (int) $forum_data['forum_id']; - $db->sql_query($sql); - } - - // From the mysql documentation: - // Prior to MySQL 4.0.14, the target table of the INSERT statement cannot appear in the FROM clause of the SELECT part of the query. This limitation is lifted in 4.0.14. - // Due to this we stay on the safe side if we do the insertion "the manual way" - - // Copy permisisons from/to the acl users table (only forum_id gets changed) - $sql = 'SELECT user_id, auth_option_id, auth_role_id, auth_setting - FROM ' . ACL_USERS_TABLE . ' - WHERE forum_id = ' . $forum_perm_from; - $result = $db->sql_query($sql); - - $users_sql_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $users_sql_ary[] = array( - 'user_id' => (int) $row['user_id'], - 'forum_id' => (int) $forum_data['forum_id'], - 'auth_option_id' => (int) $row['auth_option_id'], - 'auth_role_id' => (int) $row['auth_role_id'], - 'auth_setting' => (int) $row['auth_setting'] - ); - } - $db->sql_freeresult($result); - - // Copy permisisons from/to the acl groups table (only forum_id gets changed) - $sql = 'SELECT group_id, auth_option_id, auth_role_id, auth_setting - FROM ' . ACL_GROUPS_TABLE . ' - WHERE forum_id = ' . $forum_perm_from; - $result = $db->sql_query($sql); - - $groups_sql_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $groups_sql_ary[] = array( - 'group_id' => (int) $row['group_id'], - 'forum_id' => (int) $forum_data['forum_id'], - 'auth_option_id' => (int) $row['auth_option_id'], - 'auth_role_id' => (int) $row['auth_role_id'], - 'auth_setting' => (int) $row['auth_setting'] - ); - } - $db->sql_freeresult($result); - - // Now insert the data - $db->sql_multi_insert(ACL_USERS_TABLE, $users_sql_ary); - $db->sql_multi_insert(ACL_GROUPS_TABLE, $groups_sql_ary); + copy_forum_permissions($forum_perm_from, $forum_data['forum_id'], ($action == 'edit') ? true : false); cache_moderators(); } + else if (($action != 'edit') && $auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth')) + { + $this->copy_permission_page($forum_data); + return; + } $auth->acl_clear_prefetch(); - $cache->destroy('sql', FORUMS_TABLE); $acl_url = '&mode=setting_forum_local&forum_id[]=' . $forum_data['forum_id']; @@ -423,6 +381,7 @@ class acp_forums $forum_data['forum_flags'] += (request_var('prune_sticky', false)) ? FORUM_FLAG_PRUNE_STICKY : 0; $forum_data['forum_flags'] += ($forum_data['show_active']) ? FORUM_FLAG_ACTIVE_TOPICS : 0; $forum_data['forum_flags'] += (request_var('enable_post_review', true)) ? FORUM_FLAG_POST_REVIEW : 0; + $forum_data['forum_flags'] += (request_var('enable_quick_reply', false)) ? FORUM_FLAG_QUICK_REPLY : 0; } // Show form to create/modify a forum @@ -485,6 +444,7 @@ class acp_forums 'prune_viewed' => 7, 'prune_freq' => 1, 'forum_flags' => FORUM_FLAG_POST_REVIEW, + 'forum_options' => 0, 'forum_password' => '', 'forum_password_confirm'=> '', ); @@ -682,6 +642,7 @@ class acp_forums 'S_PRUNE_STICKY' => ($forum_data['forum_flags'] & FORUM_FLAG_PRUNE_STICKY) ? true : false, 'S_DISPLAY_ACTIVE_TOPICS' => ($forum_data['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) ? true : false, 'S_ENABLE_POST_REVIEW' => ($forum_data['forum_flags'] & FORUM_FLAG_POST_REVIEW) ? true : false, + 'S_ENABLE_QUICK_REPLY' => ($forum_data['forum_flags'] & FORUM_FLAG_QUICK_REPLY) ? true : false, 'S_CAN_COPY_PERMISSIONS' => ($action != 'edit' || empty($forum_id) || ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth'))) ? true : false, )); @@ -740,6 +701,32 @@ class acp_forums return; break; + + case 'copy_perm': + $forum_perm_from = request_var('forum_perm_from', 0); + + // Copy permissions? + if (!empty($forum_perm_from) && $forum_perm_from != $forum_id) + { + copy_forum_permissions($forum_perm_from, $forum_id, true); + cache_moderators(); + $auth->acl_clear_prefetch(); + $cache->destroy('sql', FORUMS_TABLE); + + $acl_url = '&mode=setting_forum_local&forum_id[]=' . $forum_id; + + $message = $user->lang['FORUM_UPDATED']; + + // Redirect to permissions + if ($auth->acl_get('a_fauth')) + { + $message .= '

    ' . sprintf($user->lang['REDIRECT_ACL'], '', ''); + } + + trigger_error($message . adm_back_link($this->u_action . '&parent_id=' . $this->parent_id)); + } + + break; } // Default management page @@ -941,6 +928,7 @@ class acp_forums $forum_data['forum_flags'] += ($forum_data['prune_sticky']) ? FORUM_FLAG_PRUNE_STICKY : 0; $forum_data['forum_flags'] += ($forum_data['show_active']) ? FORUM_FLAG_ACTIVE_TOPICS : 0; $forum_data['forum_flags'] += ($forum_data['enable_post_review']) ? FORUM_FLAG_POST_REVIEW : 0; + $forum_data['forum_flags'] += ($forum_data['enable_quick_reply']) ? FORUM_FLAG_QUICK_REPLY : 0; // Unset data that are not database fields $forum_data_sql = $forum_data; @@ -951,6 +939,7 @@ class acp_forums unset($forum_data_sql['prune_sticky']); unset($forum_data_sql['show_active']); unset($forum_data_sql['enable_post_review']); + unset($forum_data_sql['enable_quick_reply']); unset($forum_data_sql['forum_password_confirm']); // What are we going to do tonight Brain? The same thing we do everynight, @@ -1927,6 +1916,30 @@ class acp_forums adm_page_footer(); } + + /** + * Display copy permission page + */ + function copy_permission_page($forum_data) + { + global $phpEx, $phpbb_admin_path, $template, $user; + + $acl_url = '&mode=setting_forum_local&forum_id[]=' . $forum_data['forum_id']; + $action = append_sid($this->u_action . "&parent_id={$this->parent_id}&f={$forum_data['forum_id']}&action=copy_perm"); + + $l_acl = sprintf($user->lang['COPY_TO_ACL'], '', ''); + + $this->tpl_name = 'acp_forums_copy_perm'; + + $template->assign_vars(array( + 'U_ACL' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=permissions' . $acl_url), + 'L_ACL_LINK' => $l_acl, + 'L_BACK_LINK' => adm_back_link($this->u_action . '&parent_id=' . $this->parent_id), + 'S_COPY_ACTION' => $action, + 'S_FORUM_OPTIONS' => make_forum_select($forum_data['parent_id'], $forum_data['forum_id'], false, false, false), + )); + } + } ?> \ No newline at end of file diff --git a/phpBB/includes/acp/acp_groups.php b/phpBB/includes/acp/acp_groups.php index 2ee5ded01d..3df61ff4e2 100644 --- a/phpBB/includes/acp/acp_groups.php +++ b/phpBB/includes/acp/acp_groups.php @@ -309,6 +309,7 @@ class acp_groups 'message_limit' => request_var('group_message_limit', 0), 'max_recipients' => request_var('group_max_recipients', 0), 'founder_manage' => 0, + 'skip_auth' => request_var('group_skip_auth', 0), ); if ($user->data['user_type'] == USER_FOUNDER) @@ -400,11 +401,26 @@ class acp_groups // were made. $group_attributes = array(); - $test_variables = array('rank', 'colour', 'avatar', 'avatar_type', 'avatar_width', 'avatar_height', 'receive_pm', 'legend', 'message_limit', 'max_recipients', 'founder_manage'); - foreach ($test_variables as $test) + $test_variables = array( + 'rank' => 'int', + 'colour' => 'string', + 'avatar' => 'string', + 'avatar_type' => 'int', + 'avatar_width' => 'int', + 'avatar_height' => 'int', + 'receive_pm' => 'int', + 'legend' => 'int', + 'message_limit' => 'int', + 'max_recipients'=> 'int', + 'founder_manage'=> 'int', + 'skip_auth' => 'int', + ); + + foreach ($test_variables as $test => $type) { if (isset($submit_ary[$test]) && ($action == 'add' || $group_row['group_' . $test] != $submit_ary[$test])) { + settype($submit_ary[$test], $type); $group_attributes['group_' . $test] = $group_row['group_' . $test] = $submit_ary[$test]; } } @@ -562,7 +578,7 @@ class acp_groups 'GROUP_MESSAGE_LIMIT' => (isset($group_row['group_message_limit'])) ? $group_row['group_message_limit'] : 0, 'GROUP_MAX_RECIPIENTS' => (isset($group_row['group_max_recipients'])) ? $group_row['group_max_recipients'] : 0, 'GROUP_COLOUR' => (isset($group_row['group_colour'])) ? $group_row['group_colour'] : '', - + 'GROUP_SKIP_AUTH' => (!empty($group_row['group_skip_auth'])) ? ' checked="checked"' : '', 'S_DESC_BBCODE_CHECKED' => $group_desc_data['allow_bbcode'], 'S_DESC_URLS_CHECKED' => $group_desc_data['allow_urls'], @@ -591,8 +607,7 @@ class acp_groups 'U_SWATCH' => append_sid("{$phpbb_admin_path}swatch.$phpEx", 'form=settings&name=group_colour'), 'U_ACTION' => "{$this->u_action}&action=$action&g=$group_id", 'L_AVATAR_EXPLAIN' => sprintf($user->lang['AVATAR_EXPLAIN'], $config['avatar_max_width'], $config['avatar_max_height'], round($config['avatar_filesize'] / 1024)), - ) - ); + )); return; break; @@ -607,7 +622,7 @@ class acp_groups $this->page_title = 'GROUP_MEMBERS'; // Grab the leaders - always, on every page... - $sql = 'SELECT u.user_id, u.username, u.username_clean, u.user_regdate, u.user_posts, u.group_id, ug.group_leader, ug.user_pending + $sql = 'SELECT u.user_id, u.username, u.username_clean, u.user_regdate, u.user_colour, u.user_posts, u.group_id, ug.group_leader, ug.user_pending FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . " ug WHERE ug.group_id = $group_id AND u.user_id = ug.user_id @@ -621,11 +636,12 @@ class acp_groups 'U_USER_EDIT' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=users&action=edit&u={$row['user_id']}"), 'USERNAME' => $row['username'], + 'USERNAME_COLOUR' => $row['user_colour'], 'S_GROUP_DEFAULT' => ($row['group_id'] == $group_id) ? true : false, 'JOINED' => ($row['user_regdate']) ? $user->format_date($row['user_regdate']) : ' - ', 'USER_POSTS' => $row['user_posts'], - 'USER_ID' => $row['user_id']) - ); + 'USER_ID' => $row['user_id'], + )); } $db->sql_freeresult($result); @@ -662,7 +678,7 @@ class acp_groups )); // Grab the members - $sql = 'SELECT u.user_id, u.username, u.username_clean, u.user_regdate, u.user_posts, u.group_id, ug.group_leader, ug.user_pending + $sql = 'SELECT u.user_id, u.username, u.username_clean, u.user_colour, u.user_regdate, u.user_posts, u.group_id, ug.group_leader, ug.user_pending FROM ' . USERS_TABLE . ' u, ' . USER_GROUP_TABLE . " ug WHERE ug.group_id = $group_id AND u.user_id = ug.user_id @@ -687,6 +703,7 @@ class acp_groups 'U_USER_EDIT' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=users&action=edit&u={$row['user_id']}"), 'USERNAME' => $row['username'], + 'USERNAME_COLOUR' => $row['user_colour'], 'S_GROUP_DEFAULT' => ($row['group_id'] == $group_id) ? true : false, 'JOINED' => ($row['user_regdate']) ? $user->format_date($row['user_regdate']) : ' - ', 'USER_POSTS' => $row['user_posts'], @@ -763,8 +780,7 @@ class acp_groups 'GROUP_NAME' => $group_name, 'TOTAL_MEMBERS' => $row['total_members'], - ) - ); + )); } } } diff --git a/phpBB/includes/acp/acp_icons.php b/phpBB/includes/acp/acp_icons.php index a88090cb25..8213c55ccb 100644 --- a/phpBB/includes/acp/acp_icons.php +++ b/phpBB/includes/acp/acp_icons.php @@ -89,6 +89,18 @@ class acp_icons continue; } + // adjust the width and height to be lower than 128px while perserving the aspect ratio + if ($img_size[0] > 127 && $img_size[0] > $img_size[1]) + { + $img_size[1] = (int) ($img_size[1] * (127 / $img_size[0])); + $img_size[0] = 127; + } + else if ($img_size[1] > 127) + { + $img_size[0] = (int) ($img_size[0] * (127 / $img_size[1])); + $img_size[1] = 127; + } + $_images[$path . $img]['file'] = $path . $img; $_images[$path . $img]['width'] = $img_size[0]; $_images[$path . $img]['height'] = $img_size[1]; @@ -168,19 +180,19 @@ class acp_icons } } } - + $sql = "SELECT * FROM $table ORDER BY {$fields}_order " . (($icon_id || $action == 'add') ? 'DESC' : 'ASC'); $result = $db->sql_query($sql); - + $data = array(); $after = false; $display = 0; $order_lists = array('', ''); $add_order_lists = array('', ''); $display_count = 0; - + while ($row = $db->sql_fetchrow($result)) { if ($action == 'add') @@ -231,15 +243,15 @@ class acp_icons $data = $_images; } - $colspan = (($mode == 'smilies') ? '7' : '5'); + $colspan = (($mode == 'smilies') ? 7 : 5); $colspan += ($icon_id) ? 1 : 0; $colspan += ($action == 'add') ? 2 : 0; - + $template->assign_vars(array( 'S_EDIT' => true, 'S_SMILIES' => ($mode == 'smilies') ? true : false, 'S_ADD' => ($action == 'add') ? true : false, - + 'S_ORDER_LIST_DISPLAY' => $order_list . $order_lists[1], 'S_ORDER_LIST_UNDISPLAY' => $order_list . $order_lists[0], 'S_ORDER_LIST_DISPLAY_COUNT' => $display_count + 1, @@ -286,10 +298,10 @@ class acp_icons 'S_ADD_CODE' => true, 'S_IMG_OPTIONS' => $smiley_options, - + 'S_ADD_ORDER_LIST_DISPLAY' => $add_order_list . $add_order_lists[1], 'S_ADD_ORDER_LIST_UNDISPLAY' => $add_order_list . $add_order_lists[0], - + 'IMG_SRC' => $phpbb_root_path . $img_path . '/' . $default_row['smiley_url'], 'IMG_PATH' => $img_path, 'PHPBB_ROOT_PATH' => $phpbb_root_path, @@ -303,7 +315,7 @@ class acp_icons } return; - + break; case 'create': @@ -311,7 +323,7 @@ class acp_icons // Get items to create/modify $images = (isset($_POST['image'])) ? array_keys(request_var('image', array('' => 0))) : array(); - + // Now really get the items $image_id = (isset($_POST['id'])) ? request_var('id', array('' => 0)) : array(); $image_order = (isset($_POST['order'])) ? request_var('order', array('' => 0)) : array(); @@ -348,6 +360,25 @@ class acp_icons } } + if ($mode == 'smilies' && $action == 'create') + { + $smiley_count = $this->item_count($table); + + $addable_smileys_count = sizeof($images); + foreach ($images as $image) + { + if (!isset($image_add[$image])) + { + --$addable_smileys_count; + } + } + + if ($smiley_count + $addable_smileys_count > SMILEY_LIMIT) + { + trigger_error(sprintf($user->lang['TOO_MANY_SMILIES'], SMILEY_LIMIT) . adm_back_link($this->u_action), E_USER_WARNING); + } + } + $icons_updated = 0; $errors = array(); foreach ($images as $image) @@ -369,6 +400,17 @@ class acp_icons $image_height[$image] = $img_size[1]; } + if ($image_width[$image] > 127 && $image_width[$image] > $image_height[$image]) + { + $image_height[$image] = (int) ($image_height[$image] * (127 / $image_width[$image])); + $image_width[$image] = 127; + } + else if ($image_height[$image] > 127) + { + $image_width[$image] = (int) ($image_width[$image] * (127 / $image_height[$image])); + $image_height[$image] = 127; + } + $img_sql = array( $fields . '_url' => $image, $fields . '_width' => $image_width[$image], @@ -426,13 +468,13 @@ class acp_icons $db->sql_query($sql); $icons_updated++; } - + } } - + $cache->destroy('_icons'); $cache->destroy('sql', $table); - + $level = E_USER_NOTICE; switch ($icons_updated) { @@ -440,11 +482,11 @@ class acp_icons $suc_lang = "{$lang}_NONE"; $level = E_USER_WARNING; break; - + case 1: $suc_lang = "{$lang}_ONE"; break; - + default: $suc_lang = $lang; } @@ -495,7 +537,6 @@ class acp_icons } } - // The user has already selected a smilies_pak file if ($current == 'delete') { @@ -541,6 +582,15 @@ class acp_icons $db->sql_freeresult($result); } + if ($mode == 'smilies') + { + $smiley_count = $this->item_count($table); + if ($smiley_count + sizeof($pak_ary) > SMILEY_LIMIT) + { + trigger_error(sprintf($user->lang['TOO_MANY_SMILIES'], SMILEY_LIMIT) . adm_back_link($this->u_action), E_USER_WARNING); + } + } + foreach ($pak_ary as $pak_entry) { $data = array(); @@ -835,11 +885,14 @@ class acp_icons ); $spacer = false; + $pagination_start = request_var('start', 0); + + $item_count = $this->item_count($table); $sql = "SELECT * FROM $table ORDER BY {$fields}_order ASC"; - $result = $db->sql_query($sql); + $result = $db->sql_query_limit($sql, $config['smilies_per_page'], $pagination_start); while ($row = $db->sql_fetchrow($result)) { @@ -855,9 +908,9 @@ class acp_icons 'EMOTION' => (isset($row['emotion'])) ? $row['emotion'] : '', 'U_EDIT' => $this->u_action . '&action=edit&id=' . $row[$fields . '_id'], 'U_DELETE' => $this->u_action . '&action=delete&id=' . $row[$fields . '_id'], - 'U_MOVE_UP' => $this->u_action . '&action=move_up&id=' . $row[$fields . '_id'], - 'U_MOVE_DOWN' => $this->u_action . '&action=move_down&id=' . $row[$fields . '_id']) - ); + 'U_MOVE_UP' => $this->u_action . '&action=move_up&id=' . $row[$fields . '_id'] . '&start=' . $pagination_start, + 'U_MOVE_DOWN' => $this->u_action . '&action=move_down&id=' . $row[$fields . '_id'] . '&start=' . $pagination_start, + )); if (!$spacer && !$row['display_on_posting']) { @@ -865,6 +918,28 @@ class acp_icons } } $db->sql_freeresult($result); + + $template->assign_var('PAGINATION', + generate_pagination($this->u_action, $item_count, $config['smilies_per_page'], $pagination_start, true) + ); + } + + /** + * Returns the count of smilies or icons in the database + * + * @param string $table The table of items to count. + * @return int number of items + */ + /* private */ function item_count($table) + { + global $db; + + $sql = "SELECT COUNT(*) AS count + FROM $table"; + $result = $db->sql_query($sql); + $item_count = (int) $db->sql_fetchfield('count'); + $db->sql_freeresult($result); + return $item_count; } } diff --git a/phpBB/includes/acp/acp_inactive.php b/phpBB/includes/acp/acp_inactive.php index a38b47a704..3d0c0a2780 100644 --- a/phpBB/includes/acp/acp_inactive.php +++ b/phpBB/includes/acp/acp_inactive.php @@ -51,6 +51,19 @@ class acp_inactive $form_key = 'acp_inactive'; add_form_key($form_key); + // We build the sort key and per page settings here, because they may be needed later + + // Number of entries to display + $per_page = request_var('users_per_page', (int) $config['topics_per_page']); + + // Sorting + $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); + $sort_by_text = array('i' => $user->lang['SORT_INACTIVE'], 'j' => $user->lang['SORT_REG_DATE'], 'l' => $user->lang['SORT_LAST_VISIT'], 'd' => $user->lang['SORT_LAST_REMINDER'], 'r' => $user->lang['SORT_REASON'], 'u' => $user->lang['SORT_USERNAME'], 'p' => $user->lang['SORT_POSTS'], 'e' => $user->lang['SORT_REMINDER']); + $sort_by_sql = array('i' => 'user_inactive_time', 'j' => 'user_regdate', 'l' => 'user_lastvisit', 'd' => 'user_reminded_time', 'r' => 'user_inactive_reason', 'u' => 'username_clean', 'p' => 'user_posts', 'e' => 'user_reminded'); + + $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; + gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); + if ($submit && sizeof($mark)) { if ($action !== 'delete' && !check_form_key($form_key)) @@ -67,7 +80,7 @@ class acp_inactive FROM ' . USERS_TABLE . ' WHERE ' . $db->sql_in_set('user_id', $mark); $result = $db->sql_query($sql); - + $user_affected = array(); while ($row = $db->sql_fetchrow($result)) { @@ -100,7 +113,7 @@ class acp_inactive { include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); - $messenger = new messenger(); + $messenger = new messenger(false); foreach ($inactive_users as $row) { @@ -122,6 +135,12 @@ class acp_inactive $messenger->save_queue(); } + + // For activate we really need to redirect, else a refresh can result in users being deactivated again + $u_action = $this->u_action . "&$u_sort_param&start=$start"; + $u_action .= ($per_page != $config['topics_per_page']) ? "&users_per_page=$per_page" : ''; + + redirect($u_action); } else if ($action == 'delete') { @@ -175,7 +194,7 @@ class acp_inactive include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); $messenger = new messenger(); - $usernames = array(); + $usernames = $user_ids = array(); do { @@ -198,28 +217,34 @@ class acp_inactive $messenger->send($row['user_notify_type']); $usernames[] = $row['username']; + $user_ids[] = (int) $row['user_id']; } while ($row = $db->sql_fetchrow($result)); $messenger->save_queue(); + // Add the remind state to the database + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_reminded = user_reminded + 1, + user_reminded_time = ' . time() . ' + WHERE ' . $db->sql_in_set('user_id', $user_ids); + $db->sql_query($sql); + add_log('admin', 'LOG_INACTIVE_REMIND', implode(', ', $usernames)); unset($usernames); } $db->sql_freeresult($result); - + + // For remind we really need to redirect, else a refresh can result in more than one reminder + $u_action = $this->u_action . "&$u_sort_param&start=$start"; + $u_action .= ($per_page != $config['topics_per_page']) ? "&users_per_page=$per_page" : ''; + + redirect($u_action); + break; } } - // Sorting - $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); - $sort_by_text = array('i' => $user->lang['SORT_INACTIVE'], 'j' => $user->lang['SORT_REG_DATE'], 'l' => $user->lang['SORT_LAST_VISIT'], 'r' => $user->lang['SORT_REASON'], 'u' => $user->lang['SORT_USERNAME']); - $sort_by_sql = array('i' => 'user_inactive_time', 'j' => 'user_regdate', 'l' => 'user_lastvisit', 'r' => 'user_inactive_reason', 'u' => 'username_clean'); - - $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; - gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); - // Define where and sort sql for use in displaying logs $sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0; $sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); @@ -227,19 +252,30 @@ class acp_inactive $inactive = array(); $inactive_count = 0; - $start = view_inactive_users($inactive, $inactive_count, $config['topics_per_page'], $start, $sql_where, $sql_sort); + $start = view_inactive_users($inactive, $inactive_count, $per_page, $start, $sql_where, $sql_sort); foreach ($inactive as $row) { $template->assign_block_vars('inactive', array( 'INACTIVE_DATE' => $user->format_date($row['user_inactive_time']), + 'REMINDED_DATE' => $user->format_date($row['user_reminded_time']), 'JOINED' => $user->format_date($row['user_regdate']), 'LAST_VISIT' => (!$row['user_lastvisit']) ? ' - ' : $user->format_date($row['user_lastvisit']), + 'REASON' => $row['inactive_reason'], 'USER_ID' => $row['user_id'], - 'USERNAME' => $row['username'], - 'U_USER_ADMIN' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=users&mode=overview&u={$row['user_id']}")) - ); + 'POSTS' => ($row['user_posts']) ? $row['user_posts'] : 0, + 'REMINDED' => $row['user_reminded'], + + 'REMINDED_EXPLAIN' => $user->lang('USER_LAST_REMINDED', (int) $row['user_reminded'], $user->format_date($row['user_reminded_time'])), + + 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&mode=overview')), + 'USERNAME' => get_username_string('username', $row['user_id'], $row['username'], $row['user_colour']), + 'USER_COLOR' => get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour']), + + 'U_USER_ADMIN' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=users&mode=overview&u={$row['user_id']}"), + 'U_SEARCH_USER' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id={$row['user_id']}&sr=posts") : '', + )); } $option_ary = array('activate' => 'ACTIVATE', 'delete' => 'DELETE'); @@ -255,9 +291,10 @@ class acp_inactive 'S_LIMIT_DAYS' => $s_limit_days, 'S_SORT_KEY' => $s_sort_key, 'S_SORT_DIR' => $s_sort_dir, - 'S_ON_PAGE' => on_page($inactive_count, $config['topics_per_page'], $start), - 'PAGINATION' => generate_pagination($this->u_action . "&$u_sort_param", $inactive_count, $config['topics_per_page'], $start, true), - + 'S_ON_PAGE' => on_page($inactive_count, $per_page, $start), + 'PAGINATION' => generate_pagination($this->u_action . "&$u_sort_param&users_per_page=$per_page", $inactive_count, $per_page, $start, true), + 'USERS_PER_PAGE' => $per_page, + 'U_ACTION' => $this->u_action . '&start=' . $start, )); diff --git a/phpBB/includes/acp/acp_language.php b/phpBB/includes/acp/acp_language.php index 71970b4b50..8ca45a27f6 100644 --- a/phpBB/includes/acp/acp_language.php +++ b/phpBB/includes/acp/acp_language.php @@ -766,28 +766,41 @@ class acp_language trigger_error($user->lang['NO_REMOVE_DEFAULT_LANG'] . adm_back_link($this->u_action), E_USER_WARNING); } - $db->sql_query('DELETE FROM ' . LANG_TABLE . ' WHERE lang_id = ' . $lang_id); + if (confirm_box(true)) + { + $db->sql_query('DELETE FROM ' . LANG_TABLE . ' WHERE lang_id = ' . $lang_id); - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_lang = '" . $db->sql_escape($config['default_lang']) . "' - WHERE user_lang = '" . $db->sql_escape($row['lang_iso']) . "'"; - $db->sql_query($sql); + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_lang = '" . $db->sql_escape($config['default_lang']) . "' + WHERE user_lang = '" . $db->sql_escape($row['lang_iso']) . "'"; + $db->sql_query($sql); - // We also need to remove the translated entries for custom profile fields - we want clean tables, don't we? - $sql = 'DELETE FROM ' . PROFILE_LANG_TABLE . ' WHERE lang_id = ' . $lang_id; - $db->sql_query($sql); + // We also need to remove the translated entries for custom profile fields - we want clean tables, don't we? + $sql = 'DELETE FROM ' . PROFILE_LANG_TABLE . ' WHERE lang_id = ' . $lang_id; + $db->sql_query($sql); - $sql = 'DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . ' WHERE lang_id = ' . $lang_id; - $db->sql_query($sql); + $sql = 'DELETE FROM ' . PROFILE_FIELDS_LANG_TABLE . ' WHERE lang_id = ' . $lang_id; + $db->sql_query($sql); - $sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . " WHERE image_lang = '" . $db->sql_escape($row['lang_iso']) . "'"; - $result = $db->sql_query($sql); + $sql = 'DELETE FROM ' . STYLES_IMAGESET_DATA_TABLE . " WHERE image_lang = '" . $db->sql_escape($row['lang_iso']) . "'"; + $result = $db->sql_query($sql); - $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE); + $cache->destroy('sql', STYLES_IMAGESET_DATA_TABLE); - add_log('admin', 'LOG_LANGUAGE_PACK_DELETED', $row['lang_english_name']); + add_log('admin', 'LOG_LANGUAGE_PACK_DELETED', $row['lang_english_name']); - trigger_error(sprintf($user->lang['LANGUAGE_PACK_DELETED'], $row['lang_english_name']) . adm_back_link($this->u_action)); + trigger_error(sprintf($user->lang['LANGUAGE_PACK_DELETED'], $row['lang_english_name']) . adm_back_link($this->u_action)); + } + else + { + $s_hidden_fields = array( + 'i' => $id, + 'mode' => $mode, + 'action' => $action, + 'id' => $lang_id, + ); + confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields)); + } break; case 'install': @@ -1254,7 +1267,7 @@ $lang = array_merge($lang, array( $keys = func_get_args(); $non_static = array_shift($keys); - $value = array_shift($keys); + $value = utf8_normalize_nfc(array_shift($keys)); if (!$non_static) { diff --git a/phpBB/includes/acp/acp_logs.php b/phpBB/includes/acp/acp_logs.php index 12953173f1..0f4f78fcdd 100644 --- a/phpBB/includes/acp/acp_logs.php +++ b/phpBB/includes/acp/acp_logs.php @@ -33,6 +33,7 @@ class acp_logs // Set up general vars $action = request_var('action', ''); $forum_id = request_var('f', 0); + $topic_id = request_var('t', 0); $start = request_var('start', 0); $deletemark = (!empty($_POST['delmarked'])) ? true : false; $deleteall = (!empty($_POST['delall'])) ? true : false; @@ -104,6 +105,9 @@ class acp_logs $sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0; $sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); + $keywords = utf8_normalize_nfc(request_var('keywords', '', true)); + $keywords_param = !empty($keywords) ? '&keywords=' . urlencode(htmlspecialchars_decode($keywords)) : ''; + $l_title = $user->lang['ACP_' . strtoupper($mode) . '_LOGS']; $l_title_explain = $user->lang['ACP_' . strtoupper($mode) . '_LOGS_EXPLAIN']; @@ -123,7 +127,7 @@ class acp_logs // Grab log data $log_data = array(); $log_count = 0; - view_log($mode, $log_data, $log_count, $config['topics_per_page'], $start, $forum_id, 0, 0, $sql_where, $sql_sort); + view_log($mode, $log_data, $log_count, $config['topics_per_page'], $start, $forum_id, 0, 0, $sql_where, $sql_sort, $keywords); $template->assign_vars(array( 'L_TITLE' => $l_title, @@ -131,12 +135,13 @@ class acp_logs 'U_ACTION' => $this->u_action, 'S_ON_PAGE' => on_page($log_count, $config['topics_per_page'], $start), - 'PAGINATION' => generate_pagination($this->u_action . "&$u_sort_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, true), 'S_LIMIT_DAYS' => $s_limit_days, 'S_SORT_KEY' => $s_sort_key, 'S_SORT_DIR' => $s_sort_dir, 'S_CLEARLOGS' => $auth->acl_get('a_clearlogs'), + 'S_KEYWORDS' => $keywords, ) ); diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php index 8a92c06e04..cd83c52e01 100644 --- a/phpBB/includes/acp/acp_main.php +++ b/phpBB/includes/acp/acp_main.php @@ -97,6 +97,10 @@ class acp_main $confirm = true; $confirm_lang = 'PURGE_CACHE_CONFIRM'; break; + case 'purge_sessions': + $confirm = true; + $confirm_lang = 'PURGE_SESSIONS_CONFIRM'; + break; default: $confirm = true; @@ -341,10 +345,76 @@ class acp_main add_log('admin', 'LOG_PURGE_CACHE'); break; + + case 'purge_sessions': + if ((int) $user->data['user_type'] !== USER_FOUNDER) + { + trigger_error($user->lang['NO_AUTH_OPERATION'] . adm_back_link($this->u_action), E_USER_WARNING); + } + + $tables = array(CONFIRM_TABLE, SESSIONS_TABLE); + + foreach ($tables as $table) + { + switch ($db->sql_layer) + { + case 'sqlite': + case 'firebird': + $db->sql_query("DELETE FROM $table"); + break; + + default: + $db->sql_query("TRUNCATE TABLE $table"); + break; + } + } + + // let's restore the admin session + $reinsert_ary = array( + 'session_id' => (string) $user->session_id, + 'session_page' => (string) substr($user->page['page'], 0, 199), + 'session_forum_id' => $user->page['forum'], + 'session_user_id' => (int) $user->data['user_id'], + 'session_start' => (int) $user->data['session_start'], + 'session_last_visit' => (int) $user->data['session_last_visit'], + 'session_time' => (int) $user->time_now, + 'session_browser' => (string) trim(substr($user->browser, 0, 149)), + 'session_forwarded_for' => (string) $user->forwarded_for, + 'session_ip' => (string) $user->ip, + 'session_autologin' => (int) $user->data['session_autologin'], + 'session_admin' => 1, + 'session_viewonline' => (int) $user->data['session_viewonline'], + ); + + $sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $reinsert_ary); + $db->sql_query($sql); + + add_log('admin', 'LOG_PURGE_SESSIONS'); + break; } } } + // Version check + $user->add_lang('install'); + + $latest_version_info = false; + if (($latest_version_info = obtain_latest_version_info(request_var('versioncheck_force', false))) === false) + { + $template->assign_var('S_VERSIONCHECK_FAIL', true); + } + else + { + $latest_version_info = explode("\n", $latest_version_info); + + $latest_version = str_replace('rc', 'RC', strtolower(trim($latest_version_info[0]))); + $current_version = str_replace('rc', 'RC', strtolower($config['version'])); + + $template->assign_vars(array( + 'S_VERSION_UP_TO_DATE' => version_compare($current_version, $latest_version, '<') ? false : true, + )); + } + // Get forum statistics $total_posts = $config['num_posts']; $total_topics = $config['num_topics']; @@ -435,13 +505,15 @@ class acp_main 'UPLOAD_DIR_SIZE' => $upload_dir_size, 'TOTAL_ORPHAN' => $total_orphan, 'S_TOTAL_ORPHAN' => ($total_orphan === false) ? false : true, - 'GZIP_COMPRESSION' => ($config['gzip_compress']) ? $user->lang['ON'] : $user->lang['OFF'], + 'GZIP_COMPRESSION' => ($config['gzip_compress'] && @extension_loaded('zlib')) ? $user->lang['ON'] : $user->lang['OFF'], 'DATABASE_INFO' => $db->sql_server_info(), 'BOARD_VERSION' => $config['version'], 'U_ACTION' => $this->u_action, 'U_ADMIN_LOG' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=logs&mode=admin'), 'U_INACTIVE_USERS' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=inactive&mode=list'), + 'U_VERSIONCHECK' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=update&mode=version_check'), + 'U_VERSIONCHECK_FORCE' => append_sid("{$phpbb_admin_path}index.$phpEx", 'i=1&versioncheck_force=1'), 'S_ACTION_OPTIONS' => ($auth->acl_get('a_board')) ? true : false, 'S_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false, @@ -468,6 +540,8 @@ class acp_main if ($auth->acl_get('a_user')) { + $user->add_lang('memberlist'); + $inactive = array(); $inactive_count = 0; @@ -477,13 +551,24 @@ class acp_main { $template->assign_block_vars('inactive', array( 'INACTIVE_DATE' => $user->format_date($row['user_inactive_time']), + 'REMINDED_DATE' => $user->format_date($row['user_reminded_time']), 'JOINED' => $user->format_date($row['user_regdate']), 'LAST_VISIT' => (!$row['user_lastvisit']) ? ' - ' : $user->format_date($row['user_lastvisit']), + 'REASON' => $row['inactive_reason'], 'USER_ID' => $row['user_id'], - 'USERNAME' => $row['username'], - 'U_USER_ADMIN' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=users&mode=overview&u={$row['user_id']}")) - ); + 'POSTS' => ($row['user_posts']) ? $row['user_posts'] : 0, + 'REMINDED' => $row['user_reminded'], + + 'REMINDED_EXPLAIN' => $user->lang('USER_LAST_REMINDED', (int) $row['user_reminded'], $user->format_date($row['user_reminded_time'])), + + 'USERNAME_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&mode=overview')), + 'USERNAME' => get_username_string('username', $row['user_id'], $row['username'], $row['user_colour']), + 'USER_COLOR' => get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour']), + + 'U_USER_ADMIN' => append_sid("{$phpbb_admin_path}index.$phpEx", "i=users&mode=overview&u={$row['user_id']}"), + 'U_SEARCH_USER' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id={$row['user_id']}&sr=posts") : '', + )); } $option_ary = array('activate' => 'ACTIVATE', 'delete' => 'DELETE'); @@ -499,12 +584,12 @@ class acp_main } // Warn if install is still present - if (file_exists($phpbb_root_path . 'install')) + if (file_exists($phpbb_root_path . 'install') && !is_file($phpbb_root_path . 'install')) { $template->assign_var('S_REMOVE_INSTALL', true); } - if (!defined('PHPBB_DISABLE_CONFIG_CHECK') && file_exists($phpbb_root_path . 'config.' . $phpEx) && is_writable($phpbb_root_path . 'config.' . $phpEx)) + if (!defined('PHPBB_DISABLE_CONFIG_CHECK') && file_exists($phpbb_root_path . 'config.' . $phpEx) && phpbb_is_writable($phpbb_root_path . 'config.' . $phpEx)) { // World-Writable? (000x) $template->assign_var('S_WRITABLE_CONFIG', (bool) (@fileperms($phpbb_root_path . 'config.' . $phpEx) & 0x0002)); diff --git a/phpBB/includes/acp/acp_permissions.php b/phpBB/includes/acp/acp_permissions.php index 164970b5d5..e9f0af5071 100644 --- a/phpBB/includes/acp/acp_permissions.php +++ b/phpBB/includes/acp/acp_permissions.php @@ -57,6 +57,21 @@ class acp_permissions trigger_error('NO_MODE', E_USER_ERROR); } + // Copy forum permissions + if ($mode == 'setting_forum_copy') + { + $this->tpl_name = 'permission_forum_copy'; + + if ($auth->acl_get('a_fauth') && $auth->acl_get('a_authusers') && $auth->acl_get('a_authgroups') && $auth->acl_get('a_mauth')) + { + $this->page_title = 'ACP_FORUM_PERMISSIONS_COPY'; + $this->copy_forum_permissions(); + return; + } + + trigger_error('NO_MODE', E_USER_ERROR); + } + // Set some vars $action = request_var('action', array('' => 0)); $action = key($action); @@ -217,43 +232,71 @@ class acp_permissions trigger_error($user->lang['WRONG_PERMISSION_TYPE'] . adm_back_link($this->u_action), E_USER_WARNING); } - // Handle actions if (strpos($mode, 'setting_') === 0 && $action) { switch ($action) { case 'delete': - - if (!check_form_key($form_name)) + if (confirm_box(true)) { - trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING); - } - // All users/groups selected? - $all_users = (isset($_POST['all_users'])) ? true : false; - $all_groups = (isset($_POST['all_groups'])) ? true : false; + // All users/groups selected? + $all_users = (isset($_POST['all_users'])) ? true : false; + $all_groups = (isset($_POST['all_groups'])) ? true : false; - if ($all_users || $all_groups) - { - $items = $this->retrieve_defined_user_groups($permission_scope, $forum_id, $permission_type); - - if ($all_users && sizeof($items['user_ids'])) + if ($all_users || $all_groups) { - $user_id = $items['user_ids']; - } - else if ($all_groups && sizeof($items['group_ids'])) - { - $group_id = $items['group_ids']; - } - } + $items = $this->retrieve_defined_user_groups($permission_scope, $forum_id, $permission_type); - if (sizeof($user_id) || sizeof($group_id)) - { - $this->remove_permissions($mode, $permission_type, $auth_admin, $user_id, $group_id, $forum_id); + if ($all_users && sizeof($items['user_ids'])) + { + $user_id = $items['user_ids']; + } + else if ($all_groups && sizeof($items['group_ids'])) + { + $group_id = $items['group_ids']; + } + } + + if (sizeof($user_id) || sizeof($group_id)) + { + $this->remove_permissions($mode, $permission_type, $auth_admin, $user_id, $group_id, $forum_id); + } + else + { + trigger_error($user->lang['NO_USER_GROUP_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); + } } else { - trigger_error($user->lang['NO_USER_GROUP_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING); + if (isset($_POST['cancel'])) + { + $u_redirect = $this->u_action . '&type=' . $permission_type; + foreach ($forum_id as $fid) + { + $u_redirect .= '&forum_id[]=' . $fid; + } + redirect($u_redirect); + } + + $s_hidden_fields = array( + 'i' => $id, + 'mode' => $mode, + 'action' => array($action => 1), + 'user_id' => $user_id, + 'group_id' => $group_id, + 'forum_id' => $forum_id, + 'type' => $permission_type, + ); + if (isset($_POST['all_users'])) + { + $s_hidden_fields['all_users'] = 1; + } + if (isset($_POST['all_groups'])) + { + $s_hidden_fields['all_groups'] = 1; + } + confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields)); } break; @@ -963,6 +1006,7 @@ class acp_permissions LEFT JOIN ' . USER_GROUP_TABLE . ' ug ON (ug.group_id = g.group_id) WHERE ug.user_id = ' . $user_id . ' AND ug.user_pending = 0 + AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) ORDER BY g.group_type DESC, g.group_id DESC'; $result = $db->sql_query($sql); @@ -1123,6 +1167,57 @@ class acp_permissions )); } + /** + * Handles copying permissions from one forum to others + */ + function copy_forum_permissions() + { + global $auth, $cache, $template, $user; + + $user->add_lang('acp/forums'); + + $submit = isset($_POST['submit']) ? true : false; + + if ($submit) + { + $src = request_var('src_forum_id', 0); + $dest = request_var('dest_forum_ids', array(0)); + + if (confirm_box(true)) + { + if (copy_forum_permissions($src, $dest)) + { + cache_moderators(); + + $auth->acl_clear_prefetch(); + $cache->destroy('sql', FORUMS_TABLE); + + trigger_error($user->lang['AUTH_UPDATED'] . adm_back_link($this->u_action)); + } + else + { + trigger_error($user->lang['SELECTED_FORUM_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING); + } + } + else + { + $s_hidden_fields = array( + 'submit' => $submit, + 'src_forum_id' => $src, + 'dest_forum_ids' => $dest, + ); + + $s_hidden_fields = build_hidden_fields($s_hidden_fields); + + confirm_box(false, $user->lang['COPY_PERMISSIONS_CONFIRM'], $s_hidden_fields); + } + } + + $template->assign_vars(array( + 'S_FORUM_OPTIONS' => make_forum_select(false, false, false, false, false), + )); + } + /** * Get already assigned users/groups */ diff --git a/phpBB/includes/acp/acp_profile.php b/phpBB/includes/acp/acp_profile.php index bbe36af9be..1b0ec4b5d5 100644 --- a/phpBB/includes/acp/acp_profile.php +++ b/phpBB/includes/acp/acp_profile.php @@ -369,6 +369,7 @@ class acp_profile 'field_show_profile'=> 0, 'field_no_view' => 0, 'field_show_on_reg' => 0, + 'field_show_on_vt' => 0, 'lang_name' => utf8_normalize_nfc(request_var('field_ident', '', true)), 'lang_explain' => '', 'lang_default_value'=> '') @@ -379,7 +380,7 @@ class acp_profile // $exclude contains the data we gather in each step $exclude = array( - 1 => array('field_ident', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', 'field_required', 'field_hide', 'field_show_profile', 'field_no_view'), + 1 => array('field_ident', 'lang_name', 'lang_explain', 'field_option_none', 'field_show_on_reg', 'field_show_on_vt', 'field_required', 'field_hide', 'field_show_profile', 'field_no_view'), 2 => array('field_length', 'field_maxlen', 'field_minlen', 'field_validation', 'field_novalue', 'field_default_value'), 3 => array('l_lang_name', 'l_lang_explain', 'l_lang_default_value', 'l_lang_options') ); @@ -405,6 +406,7 @@ class acp_profile $visibility_ary = array( 'field_required', 'field_show_on_reg', + 'field_show_on_vt', 'field_show_profile', 'field_hide', ); @@ -721,6 +723,7 @@ class acp_profile 'S_STEP_ONE' => true, 'S_FIELD_REQUIRED' => ($cp->vars['field_required']) ? true : false, 'S_SHOW_ON_REG' => ($cp->vars['field_show_on_reg']) ? true : false, + 'S_SHOW_ON_VT' => ($cp->vars['field_show_on_vt']) ? true : false, 'S_FIELD_HIDE' => ($cp->vars['field_hide']) ? true : false, 'S_SHOW_PROFILE' => ($cp->vars['field_show_profile']) ? true : false, 'S_FIELD_NO_VIEW' => ($cp->vars['field_no_view']) ? true : false, @@ -1036,6 +1039,7 @@ class acp_profile 'field_validation' => $cp->vars['field_validation'], 'field_required' => $cp->vars['field_required'], 'field_show_on_reg' => $cp->vars['field_show_on_reg'], + 'field_show_on_vt' => $cp->vars['field_show_on_vt'], 'field_hide' => $cp->vars['field_hide'], 'field_show_profile' => $cp->vars['field_show_profile'], 'field_no_view' => $cp->vars['field_no_view'] diff --git a/phpBB/includes/acp/acp_prune.php b/phpBB/includes/acp/acp_prune.php index a82a438db7..7eeb37133f 100644 --- a/phpBB/includes/acp/acp_prune.php +++ b/phpBB/includes/acp/acp_prune.php @@ -406,7 +406,12 @@ class acp_prune $where_sql .= (sizeof($joined)) ? " AND user_regdate " . $key_match[$joined_select] . ' ' . gmmktime(0, 0, 0, (int) $joined[1], (int) $joined[2], (int) $joined[0]) : ''; $where_sql .= ($count !== '') ? " AND user_posts " . $key_match[$count_select] . ' ' . (int) $count . ' ' : ''; - if (sizeof($active) && $active_select != 'lt') + // First handle pruning of users who never logged in, last active date is 0000-00-00 + if (sizeof($active) && (int) $active[0] == 0 && (int) $active[1] == 0 && (int) $active[2] == 0) + { + $where_sql .= ' AND user_lastvisit = 0'; + } + else if (sizeof($active) && $active_select != 'lt') { $where_sql .= ' AND user_lastvisit ' . $key_match[$active_select] . ' ' . gmmktime(0, 0, 0, (int) $active[1], (int) $active[2], (int) $active[0]); } diff --git a/phpBB/includes/acp/acp_ranks.php b/phpBB/includes/acp/acp_ranks.php index 41ed5b0fba..fcfef2a61e 100644 --- a/phpBB/includes/acp/acp_ranks.php +++ b/phpBB/includes/acp/acp_ranks.php @@ -39,7 +39,7 @@ class acp_ranks $this->tpl_name = 'acp_ranks'; $this->page_title = 'ACP_MANAGE_RANKS'; - $form_name = 'acp_prune'; + $form_name = 'acp_ranks'; add_form_key($form_name); switch ($action) @@ -168,25 +168,22 @@ class acp_ranks { $img = $path . $img; - if (!in_array($img, $existing_imgs) || $action == 'edit') + if ($ranks && $img == $ranks['rank_image']) { - if ($ranks && $img == $ranks['rank_image']) - { - $selected = ' selected="selected"'; - $edit_img = $img; - } - else - { - $selected = ''; - } - - if (strlen($img) > 255) - { - continue; - } - - $filename_list .= ''; + $selected = ' selected="selected"'; + $edit_img = $img; } + else + { + $selected = ''; + } + + if (strlen($img) > 255) + { + continue; + } + + $filename_list .= ''; } } diff --git a/phpBB/includes/acp/acp_send_statistics.php b/phpBB/includes/acp/acp_send_statistics.php new file mode 100644 index 0000000000..b3baf54983 --- /dev/null +++ b/phpBB/includes/acp/acp_send_statistics.php @@ -0,0 +1,90 @@ +tpl_name = 'acp_send_statistics'; + $this->page_title = 'ACP_SEND_STATISTICS'; + + // generate a unique id if necessary + if (!isset($config['questionnaire_unique_id'])) + { + $install_id = unique_id(); + set_config('questionnaire_unique_id', $install_id); + } + else + { + $install_id = $config['questionnaire_unique_id']; + } + + $collector = new phpbb_questionnaire_data_collector($install_id); + + // Add data provider + $collector->add_data_provider(new phpbb_questionnaire_php_data_provider()); + $collector->add_data_provider(new phpbb_questionnaire_system_data_provider()); + $collector->add_data_provider(new phpbb_questionnaire_phpbb_data_provider($config)); + + $template->assign_vars(array( + 'U_COLLECT_STATS' => $collect_url, + 'RAW_DATA' => $collector->get_data_for_form(), + 'U_ACP_MAIN' => append_sid("{$phpbb_admin_path}index.$phpEx"), + )); + + $raw = $collector->get_data_raw(); + + foreach ($raw as $provider => $data) + { + if ($provider == 'install_id') + { + $data = array($provider => $data); + } + + $template->assign_block_vars('providers', array( + 'NAME' => htmlspecialchars($provider), + )); + + foreach ($data as $key => $value) + { + if (is_array($value)) + { + $value = utf8_wordwrap(serialize($value), 75, "\n", true); + } + + $template->assign_block_vars('providers.values', array( + 'KEY' => utf8_htmlspecialchars($key), + 'VALUE' => utf8_htmlspecialchars($value), + )); + } + } + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php index 184c40f218..fbf3eadcb2 100644 --- a/phpBB/includes/acp/acp_styles.php +++ b/phpBB/includes/acp/acp_styles.php @@ -210,23 +210,36 @@ parse_css_file = {PARSE_CSS_FILE} trigger_error($user->lang['DEACTIVATE_DEFAULT'] . adm_back_link($this->u_action), E_USER_WARNING); } - $sql = 'UPDATE ' . STYLES_TABLE . ' - SET style_active = ' . (($action == 'activate') ? 1 : 0) . ' - WHERE style_id = ' . $style_id; - $db->sql_query($sql); - - // Set style to default for any member using deactivated style - if ($action == 'deactivate') + if (($action == 'deactivate' && confirm_box(true)) || $action == 'activate') { - $sql = 'UPDATE ' . USERS_TABLE . ' - SET user_style = ' . $config['default_style'] . " - WHERE user_style = $style_id"; + $sql = 'UPDATE ' . STYLES_TABLE . ' + SET style_active = ' . (($action == 'activate') ? 1 : 0) . ' + WHERE style_id = ' . $style_id; $db->sql_query($sql); - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET forum_style = 0 - WHERE forum_style = ' . $style_id; - $db->sql_query($sql); + // Set style to default for any member using deactivated style + if ($action == 'deactivate') + { + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_style = ' . $config['default_style'] . " + WHERE user_style = $style_id"; + $db->sql_query($sql); + + $sql = 'UPDATE ' . FORUMS_TABLE . ' + SET forum_style = 0 + WHERE forum_style = ' . $style_id; + $db->sql_query($sql); + } + } + else if ($action == 'deactivate') + { + $s_hidden_fields = array( + 'i' => $id, + 'mode' => $mode, + 'action' => $action, + 'style_id' => $style_id, + ); + confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields)); } break; } @@ -734,7 +747,8 @@ parse_css_file = {PARSE_CSS_FILE} { if (!($fp = @fopen($file, 'wb'))) { - trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); + // File exists and is writeable, but still not able to be written to + trigger_error(sprintf($user->lang['TEMPLATE_FILE_NOT_WRITABLE'], htmlspecialchars($template_file)) . adm_back_link($this->u_action), E_USER_WARNING); } fwrite($fp, $template_data); fclose($fp); @@ -827,6 +841,11 @@ parse_css_file = {PARSE_CSS_FILE} unset($file_info); } + if (empty($filelist[''])) + { + trigger_error($user->lang['NO_TEMPLATE'] . adm_back_link($this->u_action), E_USER_WARNING); + } + // Now create the categories $filelist_cats[''] = array(); foreach ($filelist as $pathfile => $file_ary) @@ -1024,12 +1043,12 @@ parse_css_file = {PARSE_CSS_FILE} foreach ($file_ary as $file) { - $file = str_replace('/', '.', $file); + $file = str_replace('/', '.', $file); // perform some dirty guessing to get the path right. // We assume that three dots in a row were '../' - $tpl_file = str_replace('.', '/', $file); - $tpl_file = str_replace('///', '../', $tpl_file); + $tpl_file = str_replace('.', '/', $file); + $tpl_file = str_replace('///', '../', $tpl_file); $filename = "{$cache_prefix}_$file.html.$phpEx"; @@ -1061,6 +1080,11 @@ parse_css_file = {PARSE_CSS_FILE} } } + // Correct the filename if it is stored in database and the file is in a subfolder. + if ($template_row['template_storedb']) + { + $file = str_replace('.', '/', $file); + } $template->assign_block_vars('file', array( 'U_VIEWSOURCE' => $this->u_action . "&action=cache&id=$template_id&source=$file", @@ -1068,7 +1092,7 @@ parse_css_file = {PARSE_CSS_FILE} 'CACHED' => $user->format_date(filemtime("{$phpbb_root_path}cache/$filename")), 'FILENAME' => $file, 'FILENAME_PATH' => $file_tpl, - 'FILESIZE' => sprintf('%.1f ' . $user->lang['KIB'], filesize("{$phpbb_root_path}cache/$filename") / 1024), + 'FILESIZE' => get_formatted_filesize(filesize("{$phpbb_root_path}cache/$filename")), 'MODIFIED' => $user->format_date((!$template_row['template_storedb']) ? filemtime($file_tpl) : $filemtime[$file . '.html'])) ); } @@ -1266,7 +1290,6 @@ parse_css_file = {PARSE_CSS_FILE} ); } - /** * Edit imagesets * @@ -2404,7 +2427,6 @@ parse_css_file = {PARSE_CSS_FILE} } } - if ($mode == 'template') { $super = array(); @@ -2535,9 +2557,22 @@ parse_css_file = {PARSE_CSS_FILE} { trigger_error("Could not open {$phpbb_root_path}styles/$template_path$pathfile$file", E_USER_ERROR); } - $template_data = fread($fp, filesize("{$phpbb_root_path}styles/$template_path$pathfile$file")); + + $filesize = filesize("{$phpbb_root_path}styles/$template_path$pathfile$file"); + + if ($filesize) + { + $template_data = fread($fp, $filesize); + } + fclose($fp); + if (!$filesize) + { + // File is empty + continue; + } + if (preg_match_all('##is', $template_data, $matches)) { foreach ($matches[1] as $match) @@ -3204,7 +3239,6 @@ parse_css_file = {PARSE_CSS_FILE} $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - if ($row) { // If it exist, we just use the style on installation @@ -3255,7 +3289,6 @@ parse_css_file = {PARSE_CSS_FILE} $inherit_bf = false; } - if (sizeof($error)) { return false; @@ -3525,7 +3558,6 @@ parse_css_file = {PARSE_CSS_FILE} break; } - $sql = "SELECT {$mode}_inherits_id FROM $sql_from WHERE {$mode}_id = " . (int) $id; diff --git a/phpBB/includes/acp/acp_update.php b/phpBB/includes/acp/acp_update.php index dbb25bdbbd..121c72aeb3 100644 --- a/phpBB/includes/acp/acp_update.php +++ b/phpBB/includes/acp/acp_update.php @@ -37,12 +37,7 @@ class acp_update $errstr = ''; $errno = 0; - $info = get_remote_file('www.phpbb.com', '/updatecheck', ((defined('PHPBB_QA')) ? '30x_qa.txt' : '30x.txt'), $errstr, $errno); - - if ($info === false) - { - trigger_error($errstr, E_USER_WARNING); - } + $info = obtain_latest_version_info(request_var('versioncheck_force', false), true); $info = explode("\n", $info); $latest_version = trim($info[0]); @@ -68,6 +63,7 @@ class acp_update 'S_UP_TO_DATE_AUTO' => $up_to_date_automatic, 'S_VERSION_CHECK' => true, 'U_ACTION' => $this->u_action, + 'U_VERSIONCHECK_FORCE' => append_sid($this->u_action . '&versioncheck_force=1'), 'LATEST_VERSION' => $latest_version, 'CURRENT_VERSION' => $config['version'], diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php index e5f83faec3..1afec6183a 100644 --- a/phpBB/includes/acp/acp_users.php +++ b/phpBB/includes/acp/acp_users.php @@ -385,6 +385,31 @@ class acp_users user_active_flip('flip', $user_id); + if ($user_row['user_type'] == USER_INACTIVE) + { + if ($config['require_activation'] == USER_ACTIVATION_ADMIN) + { + include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); + + $messenger = new messenger(false); + + $messenger->template('admin_welcome_activated', $user_row['user_lang']); + + $messenger->to($user_row['user_email'], $user_row['username']); + + $messenger->headers('X-AntiAbuse: Board servername - ' . $config['server_name']); + $messenger->headers('X-AntiAbuse: User_id - ' . $user->data['user_id']); + $messenger->headers('X-AntiAbuse: Username - ' . $user->data['username']); + $messenger->headers('X-AntiAbuse: User IP - ' . $user->ip); + + $messenger->assign_vars(array( + 'USERNAME' => htmlspecialchars_decode($user_row['username'])) + ); + + $messenger->send(NOTIFY_EMAIL); + } + } + $message = ($user_row['user_type'] == USER_INACTIVE) ? 'USER_ADMIN_ACTIVATED' : 'USER_ADMIN_DEACTIVED'; $log = ($user_row['user_type'] == USER_INACTIVE) ? 'LOG_USER_ACTIVE' : 'LOG_USER_INACTIVE'; @@ -495,6 +520,56 @@ class acp_users break; + case 'deloutbox': + + if (confirm_box(true)) + { + $msg_ids = array(); + $lang = 'EMPTY'; + + $sql = 'SELECT msg_id + FROM ' . PRIVMSGS_TO_TABLE . " + WHERE author_id = $user_id + AND folder_id = " . PRIVMSGS_OUTBOX; + $result = $db->sql_query($sql); + + if ($row = $db->sql_fetchrow($result)) + { + if (!function_exists('delete_pm')) + { + include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); + } + + do + { + $msg_ids[] = (int) $row['msg_id']; + } + while ($row = $db->sql_fetchrow($result)); + + $db->sql_freeresult($result); + + delete_pm($user_id, $msg_ids, PRIVMSGS_OUTBOX); + + add_log('admin', 'LOG_USER_DEL_OUTBOX', $user_row['username']); + + $lang = 'EMPTIED'; + } + $db->sql_freeresult($result); + + trigger_error($user->lang['USER_OUTBOX_' . $lang] . adm_back_link($this->u_action . '&u=' . $user_id)); + } + else + { + confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( + 'u' => $user_id, + 'i' => $id, + 'mode' => $mode, + 'action' => $action, + 'update' => true)) + ); + } + break; + case 'moveposts': if (!check_form_key($form_name)) @@ -650,6 +725,28 @@ class acp_users trigger_error($user->lang['USER_POSTS_MOVED'] . adm_back_link($this->u_action . '&u=' . $user_id)); break; + + case 'leave_nr': + + if (confirm_box(true)) + { + remove_newly_registered($user_id, $user_row); + + add_log('admin', 'LOG_USER_REMOVED_NR', $user_row['username']); + trigger_error($user->lang['USER_LIFTED_NR'] . adm_back_link($this->u_action . '&u=' . $user_id)); + } + else + { + confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( + 'u' => $user_id, + 'i' => $id, + 'mode' => $mode, + 'action' => $action, + 'update' => true)) + ); + } + + break; } // Handle registration info updates @@ -775,7 +872,7 @@ class acp_users { $sql_ary += array( 'user_email' => $update_email, - 'user_email_hash' => crc32($update_email) . strlen($update_email) + 'user_email_hash' => phpbb_email_hash($update_email), ); add_log('user', $user_id, 'LOG_USER_UPDATE_EMAIL', $user_row['username'], $user_row['user_email'], $update_email); @@ -820,7 +917,11 @@ class acp_users if ($user_id == $user->data['user_id']) { - $quick_tool_ary = array('delsig' => 'DEL_SIG', 'delavatar' => 'DEL_AVATAR', 'moveposts' => 'MOVE_POSTS', 'delposts' => 'DEL_POSTS', 'delattach' => 'DEL_ATTACH'); + $quick_tool_ary = array('delsig' => 'DEL_SIG', 'delavatar' => 'DEL_AVATAR', 'moveposts' => 'MOVE_POSTS', 'delposts' => 'DEL_POSTS', 'delattach' => 'DEL_ATTACH', 'deloutbox' => 'DEL_OUTBOX'); + if ($user_row['user_new']) + { + $quick_tool_ary['leave_nr'] = 'LEAVE_NR'; + } } else { @@ -836,12 +937,17 @@ class acp_users $quick_tool_ary += array('active' => (($user_row['user_type'] == USER_INACTIVE) ? 'ACTIVATE' : 'DEACTIVATE')); } - $quick_tool_ary += array('delsig' => 'DEL_SIG', 'delavatar' => 'DEL_AVATAR', 'moveposts' => 'MOVE_POSTS', 'delposts' => 'DEL_POSTS', 'delattach' => 'DEL_ATTACH'); + $quick_tool_ary += array('delsig' => 'DEL_SIG', 'delavatar' => 'DEL_AVATAR', 'moveposts' => 'MOVE_POSTS', 'delposts' => 'DEL_POSTS', 'delattach' => 'DEL_ATTACH', 'deloutbox' => 'DEL_OUTBOX'); if ($config['email_enable'] && ($user_row['user_type'] == USER_NORMAL || $user_row['user_type'] == USER_INACTIVE)) { $quick_tool_ary['reactivate'] = 'FORCE'; } + + if ($user_row['user_new']) + { + $quick_tool_ary['leave_nr'] = 'LEAVE_NR'; + } } $s_action_options = ''; @@ -1035,6 +1141,161 @@ class acp_users break; + case 'warnings': + $user->add_lang('mcp'); + + // Set up general vars + $start = request_var('start', 0); + $deletemark = (isset($_POST['delmarked'])) ? true : false; + $deleteall = (isset($_POST['delall'])) ? true : false; + $confirm = (isset($_POST['confirm'])) ? true : false; + $marked = request_var('mark', array(0)); + $message = utf8_normalize_nfc(request_var('message', '', true)); + + // Sort keys + $sort_days = request_var('st', 0); + $sort_key = request_var('sk', 't'); + $sort_dir = request_var('sd', 'd'); + + // Delete entries if requested and able + if ($deletemark || $deleteall || $confirm) + { + if (confirm_box(true)) + { + $where_sql = ''; + $deletemark = request_var('delmarked', 0); + $deleteall = request_var('delall', 0); + if ($deletemark && $marked) + { + $sql_in = array(); + foreach ($marked as $mark) + { + $sql_in[] = $mark; + } + $where_sql = ' AND ' . $db->sql_in_set('warning_id', $sql_in); + unset($sql_in); + } + + if ($where_sql || $deleteall) + { + $sql = 'DELETE FROM ' . WARNINGS_TABLE . " + WHERE user_id = $user_id + $where_sql"; + $db->sql_query($sql); + + if ($deleteall) + { + $log_warnings = $deleted_warnings = 0; + } + else + { + $num_warnings = (int) $db->sql_affectedrows(); + $deleted_warnings = ' user_warnings - ' . $num_warnings; + $log_warnings = ($num_warnings > 2) ? 2 : $num_warnings; + } + + $sql = 'UPDATE ' . USERS_TABLE . " + SET user_warnings = $deleted_warnings + WHERE user_id = $user_id"; + $db->sql_query($sql); + + switch ($log_warnings) + { + case 2: + add_log('admin', 'LOG_WARNINGS_DELETED', $user_row['username'], $num_warnings); + break; + case 1: + add_log('admin', 'LOG_WARNING_DELETED', $user_row['username']); + break; + default: + add_log('admin', 'LOG_WARNINGS_DELETED_ALL', $user_row['username']); + break; + } + } + } + else + { + $s_hidden_fields = array( + 'i' => $id, + 'mode' => $mode, + 'u' => $user_id, + 'mark' => $marked, + ); + if (isset($_POST['delmarked'])) + { + $s_hidden_fields['delmarked'] = 1; + } + if (isset($_POST['delall'])) + { + $s_hidden_fields['delall'] = 1; + } + if (isset($_POST['delall']) || (isset($_POST['delmarked']) && sizeof($marked))) + { + confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields($s_hidden_fields)); + } + } + } + + $sql = 'SELECT w.warning_id, w.warning_time, w.post_id, l.log_operation, l.log_data, l.user_id AS mod_user_id, m.username AS mod_username, m.user_colour AS mod_user_colour + FROM ' . WARNINGS_TABLE . ' w + LEFT JOIN ' . LOG_TABLE . ' l + ON (w.log_id = l.log_id) + LEFT JOIN ' . USERS_TABLE . ' m + ON (l.user_id = m.user_id) + WHERE w.user_id = ' . $user_id . ' + ORDER BY w.warning_time DESC'; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + if (!$row['log_operation']) + { + // We do not have a log-entry anymore, so there is no data available + $row['action'] = $user->lang['USER_WARNING_LOG_DELETED']; + } + else + { + $row['action'] = (isset($user->lang[$row['log_operation']])) ? $user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}'; + if (!empty($row['log_data'])) + { + $log_data_ary = @unserialize($row['log_data']); + $log_data_ary = ($log_data_ary === false) ? array() : $log_data_ary; + + if (isset($user->lang[$row['log_operation']])) + { + // Check if there are more occurrences of % than arguments, if there are we fill out the arguments array + // It doesn't matter if we add more arguments than placeholders + if ((substr_count($row['action'], '%') - sizeof($log_data_ary)) > 0) + { + $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($row['action'], '%') - sizeof($log_data_ary), '')); + } + $row['action'] = vsprintf($row['action'], $log_data_ary); + $row['action'] = bbcode_nl2br(censor_text($row['action'])); + } + else if (!empty($log_data_ary)) + { + $row['action'] .= '
    ' . implode('', $log_data_ary); + } + } + } + + + $template->assign_block_vars('warn', array( + 'ID' => $row['warning_id'], + 'USERNAME' => ($row['log_operation']) ? get_username_string('full', $row['mod_user_id'], $row['mod_username'], $row['mod_user_colour']) : '-', + 'ACTION' => make_clickable($row['action']), + 'DATE' => $user->format_date($row['warning_time']), + )); + } + $db->sql_freeresult($result); + + $template->assign_vars(array( + 'S_WARNINGS' => true, + 'S_CLEARLOGS' => $auth->acl_get('a_clearlogs'), + )); + + break; + case 'profile': include($phpbb_root_path . 'includes/functions_user.' . $phpEx); @@ -1136,54 +1397,7 @@ class acp_users $db->sql_query($sql); // Update Custom Fields - if (sizeof($cp_data)) - { - switch ($db->sql_layer) - { - case 'oracle': - case 'firebird': - case 'postgres': - $right_delim = $left_delim = '"'; - break; - - case 'sqlite': - case 'mssql': - case 'mssql_odbc': - $right_delim = ']'; - $left_delim = '['; - break; - - case 'mysql': - case 'mysql4': - case 'mysqli': - $right_delim = $left_delim = '`'; - break; - } - - foreach ($cp_data as $key => $value) - { - // Firebird is case sensitive with delimiter - $cp_data[$left_delim . (($db->sql_layer == 'firebird') ? strtoupper($key) : $key) . $right_delim] = $value; - unset($cp_data[$key]); - } - - $sql = 'UPDATE ' . PROFILE_FIELDS_DATA_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $cp_data) . " - WHERE user_id = $user_id"; - $db->sql_query($sql); - - if (!$db->sql_affectedrows()) - { - $cp_data['user_id'] = (int) $user_id; - - $db->sql_return_on_error(true); - - $sql = 'INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $cp_data); - $db->sql_query($sql); - - $db->sql_return_on_error(false); - } - } + $cp->update_profile_field_data($user_id, $cp_data); trigger_error($user->lang['USER_PROFILE_UPDATED'] . adm_back_link($this->u_action . '&u=' . $user_id)); } @@ -1476,8 +1690,19 @@ class acp_users $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); } + if (!$config['allow_avatar'] && $user_row['user_avatar_type']) + { + $error[] = $user->lang['USER_AVATAR_NOT_ALLOWED']; + } + else if ((($user_row['user_avatar_type'] == AVATAR_UPLOAD) && !$config['allow_avatar_upload']) || + (($user_row['user_avatar_type'] == AVATAR_REMOTE) && !$config['allow_avatar_remote']) || + (($user_row['user_avatar_type'] == AVATAR_GALLERY) && !$config['allow_avatar_local'])) + { + $error[] = $user->lang['USER_AVATAR_TYPE_NOT_ALLOWED']; + } + // Generate users avatar - $avatar_img = ($user_row['user_avatar']) ? get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']) : ''; + $avatar_img = ($user_row['user_avatar']) ? get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height'], 'USER_AVATAR', true) : ''; $display_gallery = (isset($_POST['display_gallery'])) ? true : false; $avatar_select = basename(request_var('avatar_select', '')); @@ -1490,10 +1715,11 @@ class acp_users $template->assign_vars(array( 'S_AVATAR' => true, - 'S_CAN_UPLOAD' => ($can_upload && $config['allow_avatar_upload']) ? true : false, - 'S_ALLOW_REMOTE' => ($config['allow_avatar_remote']) ? true : false, - 'S_DISPLAY_GALLERY' => ($config['allow_avatar_local'] && !$display_gallery) ? true : false, - 'S_IN_GALLERY' => ($config['allow_avatar_local'] && $display_gallery) ? true : false, + 'S_UPLOAD_FILE' => ($config['allow_avatar'] && $can_upload && $config['allow_avatar_upload']) ? true : false, + 'S_REMOTE_UPLOAD' => ($config['allow_avatar'] && $can_upload && $config['allow_avatar_remote_upload']) ? true : false, + 'S_ALLOW_REMOTE' => ($config['allow_avatar'] && $config['allow_avatar_remote']) ? true : false, + 'S_DISPLAY_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local'] && !$display_gallery) ? true : false, + 'S_IN_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local'] && $display_gallery) ? true : false, 'AVATAR_IMAGE' => $avatar_img, 'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'], @@ -1551,9 +1777,9 @@ class acp_users include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); include_once($phpbb_root_path . 'includes/functions_display.' . $phpEx); - $enable_bbcode = ($config['allow_sig_bbcode']) ? ((request_var('disable_bbcode', !$user->optionget('bbcode'))) ? false : true) : false; - $enable_smilies = ($config['allow_sig_smilies']) ? ((request_var('disable_smilies', !$user->optionget('smilies'))) ? false : true) : false; - $enable_urls = ($config['allow_sig_links']) ? ((request_var('disable_magic_url', false)) ? false : true) : false; + $enable_bbcode = ($config['allow_sig_bbcode']) ? (bool) $this->optionget($user_row, 'sig_bbcode') : false; + $enable_smilies = ($config['allow_sig_smilies']) ? (bool) $this->optionget($user_row, 'sig_smilies') : false; + $enable_urls = ($config['allow_sig_links']) ? (bool) $this->optionget($user_row, 'sig_links') : false; $signature = utf8_normalize_nfc(request_var('signature', (string) $user_row['user_sig'], true)); $preview = (isset($_POST['preview'])) ? true : false; @@ -1562,6 +1788,10 @@ class acp_users { include_once($phpbb_root_path . 'includes/message_parser.' . $phpEx); + $enable_bbcode = ($config['allow_sig_bbcode']) ? ((request_var('disable_bbcode', false)) ? false : true) : false; + $enable_smilies = ($config['allow_sig_smilies']) ? ((request_var('disable_smilies', false)) ? false : true) : false; + $enable_urls = ($config['allow_sig_links']) ? ((request_var('disable_magic_url', false)) ? false : true) : false; + $message_parser = new parse_message($signature); // Allowing Quote BBCode @@ -1579,8 +1809,13 @@ class acp_users if (!sizeof($error) && $submit) { + $this->optionset($user_row, 'sig_bbcode', $enable_bbcode); + $this->optionset($user_row, 'sig_smilies', $enable_smilies); + $this->optionset($user_row, 'sig_links', $enable_urls); + $sql_ary = array( 'user_sig' => (string) $message_parser->message, + 'user_options' => $user_row['user_options'], 'user_sig_bbcode_uid' => (string) $message_parser->bbcode_uid, 'user_sig_bbcode_bitfield' => (string) $message_parser->bbcode_bitfield ); @@ -1871,6 +2106,29 @@ class acp_users } break; + + case 'approve': + + if (confirm_box(true)) + { + if (!$group_id) + { + trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action . '&u=' . $user_id), E_USER_WARNING); + } + group_user_attributes($action, $group_id, $user_id); + } + else + { + confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array( + 'u' => $user_id, + 'i' => $id, + 'mode' => $mode, + 'action' => $action, + 'g' => $group_id)) + ); + } + + break; } // Add user to group? @@ -1963,10 +2221,12 @@ class acp_users 'U_DEFAULT' => $this->u_action . "&action=default&u=$user_id&g=" . $data['group_id'], 'U_DEMOTE_PROMOTE' => $this->u_action . '&action=' . (($data['group_leader']) ? 'demote' : 'promote') . "&u=$user_id&g=" . $data['group_id'], 'U_DELETE' => $this->u_action . "&action=delete&u=$user_id&g=" . $data['group_id'], + 'U_APPROVE' => ($group_type == 'pending') ? $this->u_action . "&action=approve&u=$user_id&g=" . $data['group_id'] : '', 'GROUP_NAME' => ($group_type == 'special') ? $user->lang['G_' . $data['group_name']] : $data['group_name'], 'L_DEMOTE_PROMOTE' => ($data['group_leader']) ? $user->lang['GROUP_DEMOTE'] : $user->lang['GROUP_PROMOTE'], + 'S_IS_MEMBER' => ($group_type != 'pending') ? true : false, 'S_NO_DEFAULT' => ($user_row['group_id'] != $data['group_id']) ? true : false, 'S_SPECIAL_GROUP' => ($group_type == 'special') ? true : false, ) diff --git a/phpBB/includes/acp/acp_words.php b/phpBB/includes/acp/acp_words.php index 596c2fc743..1cb9545967 100644 --- a/phpBB/includes/acp/acp_words.php +++ b/phpBB/includes/acp/acp_words.php @@ -23,7 +23,7 @@ if (!defined('IN_PHPBB')) class acp_words { var $u_action; - + function main($id, $mode) { global $db, $user, $auth, $template, $cache; @@ -47,8 +47,9 @@ class acp_words switch ($action) { case 'edit': + $word_id = request_var('id', 0); - + if (!$word_id) { trigger_error($user->lang['NO_WORD'] . adm_back_link($this->u_action), E_USER_WARNING); @@ -73,7 +74,7 @@ class acp_words 'REPLACEMENT' => (isset($word_info['replacement'])) ? $word_info['replacement'] : '', 'S_HIDDEN_FIELDS' => $s_hidden_fields) ); - + return; break; @@ -84,11 +85,12 @@ class acp_words { trigger_error($user->lang['FORM_INVALID']. adm_back_link($this->u_action), E_USER_WARNING); } + $word_id = request_var('id', 0); $word = utf8_normalize_nfc(request_var('word', '', true)); $replacement = utf8_normalize_nfc(request_var('replacement', '', true)); - - if (!$word || !$replacement) + + if ($word === '' || $replacement === '') { trigger_error($user->lang['ENTER_WORD'] . adm_back_link($this->u_action), E_USER_WARNING); } diff --git a/phpBB/includes/acp/info/acp_board.php b/phpBB/includes/acp/info/acp_board.php index 72d86676a6..58b650650c 100644 --- a/phpBB/includes/acp/info/acp_board.php +++ b/phpBB/includes/acp/info/acp_board.php @@ -26,6 +26,7 @@ class acp_board_info 'message' => array('title' => 'ACP_MESSAGE_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION', 'ACP_MESSAGES')), 'post' => array('title' => 'ACP_POST_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')), 'signature' => array('title' => 'ACP_SIGNATURE_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')), + 'feed' => array('title' => 'ACP_FEED_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')), 'registration' => array('title' => 'ACP_REGISTER_SETTINGS', 'auth' => 'acl_a_board', 'cat' => array('ACP_BOARD_CONFIGURATION')), 'auth' => array('title' => 'ACP_AUTH_SETTINGS', 'auth' => 'acl_a_server', 'cat' => array('ACP_CLIENT_COMMUNICATION')), diff --git a/phpBB/includes/acp/info/acp_permissions.php b/phpBB/includes/acp/info/acp_permissions.php index 22de666af3..6f341742f3 100644 --- a/phpBB/includes/acp/info/acp_permissions.php +++ b/phpBB/includes/acp/info/acp_permissions.php @@ -24,6 +24,7 @@ class acp_permissions_info 'trace' => array('title' => 'ACP_PERMISSION_TRACE', 'auth' => 'acl_a_viewauth', 'display' => false, 'cat' => array('ACP_PERMISSION_MASKS')), 'setting_forum_local' => array('title' => 'ACP_FORUM_PERMISSIONS', 'auth' => 'acl_a_fauth && (acl_a_authusers || acl_a_authgroups)', 'cat' => array('ACP_FORUM_BASED_PERMISSIONS')), + 'setting_forum_copy' => array('title' => 'ACP_FORUM_PERMISSIONS_COPY', 'auth' => 'acl_a_fauth && acl_a_authusers && acl_a_authgroups && acl_a_mauth', 'cat' => array('ACP_FORUM_BASED_PERMISSIONS')), 'setting_mod_local' => array('title' => 'ACP_FORUM_MODERATORS', 'auth' => 'acl_a_mauth && (acl_a_authusers || acl_a_authgroups)', 'cat' => array('ACP_FORUM_BASED_PERMISSIONS')), 'setting_user_global' => array('title' => 'ACP_USERS_PERMISSIONS', 'auth' => 'acl_a_authusers && (acl_a_aauth || acl_a_mauth || acl_a_uauth)', 'cat' => array('ACP_GLOBAL_PERMISSIONS', 'ACP_CAT_USERS')), 'setting_user_local' => array('title' => 'ACP_USERS_FORUM_PERMISSIONS', 'auth' => 'acl_a_authusers && (acl_a_mauth || acl_a_fauth)', 'cat' => array('ACP_FORUM_BASED_PERMISSIONS', 'ACP_CAT_USERS')), diff --git a/phpBB/includes/acp/info/acp_send_statistics.php b/phpBB/includes/acp/info/acp_send_statistics.php new file mode 100644 index 0000000000..de5dcdb8ad --- /dev/null +++ b/phpBB/includes/acp/info/acp_send_statistics.php @@ -0,0 +1,37 @@ + 'acp_send_statistics', + 'title' => 'ACP_SEND_STATISTICS', + 'version' => '1.0.0', + 'modes' => array( + 'send_statistics' => array('title' => 'ACP_SEND_STATISTICS', 'auth' => 'acl_a_server', 'cat' => array('ACP_SERVER_CONFIGURATION')), + ), + ); + } + + function install() + { + } + + function uninstall() + { + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/acp/info/acp_users.php b/phpBB/includes/acp/info/acp_users.php index 0cd5f7ae97..10081ac870 100644 --- a/phpBB/includes/acp/info/acp_users.php +++ b/phpBB/includes/acp/info/acp_users.php @@ -22,6 +22,7 @@ class acp_users_info 'modes' => array( 'overview' => array('title' => 'ACP_MANAGE_USERS', 'auth' => 'acl_a_user', 'cat' => array('ACP_CAT_USERS')), 'feedback' => array('title' => 'ACP_USER_FEEDBACK', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')), + 'warnings' => array('title' => 'ACP_USER_WARNINGS', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')), 'profile' => array('title' => 'ACP_USER_PROFILE', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')), 'prefs' => array('title' => 'ACP_USER_PREFS', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')), 'avatar' => array('title' => 'ACP_USER_AVATAR', 'auth' => 'acl_a_user', 'display' => false, 'cat' => array('ACP_CAT_USERS')), diff --git a/phpBB/includes/auth.php b/phpBB/includes/auth.php index 1196a9a0f0..02819f9e78 100644 --- a/phpBB/includes/auth.php +++ b/phpBB/includes/auth.php @@ -64,9 +64,9 @@ class auth $db->sql_freeresult($result); $cache->put('_acl_options', $this->acl_options); - $this->acl_cache($userdata); } - else if (!trim($userdata['user_permissions'])) + + if (!trim($userdata['user_permissions'])) { $this->acl_cache($userdata); } @@ -608,22 +608,26 @@ class auth // Now grab group settings - non-role specific... $sql_ary[] = 'SELECT ug.user_id, a.forum_id, a.auth_setting, a.auth_option_id' . $sql_opts_select . ' - FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug' . $sql_opts_from . ' + FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g' . $sql_opts_from . ' WHERE a.auth_role_id = 0 ' . (($sql_opts_from) ? 'AND a.auth_option_id = ao.auth_option_id ' : '') . ' AND a.group_id = ug.group_id + AND g.group_id = ug.group_id AND ug.user_pending = 0 + AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . " $sql_forum $sql_opts"; // Now grab group settings - role specific... $sql_ary[] = 'SELECT ug.user_id, a.forum_id, r.auth_setting, r.auth_option_id' . $sql_opts_select . ' - FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . ACL_ROLES_DATA_TABLE . ' r' . $sql_opts_from . ' + FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g, ' . ACL_ROLES_DATA_TABLE . ' r' . $sql_opts_from . ' WHERE a.auth_role_id = r.role_id ' . (($sql_opts_from) ? 'AND r.auth_option_id = ao.auth_option_id ' : '') . ' AND a.group_id = ug.group_id + AND g.group_id = ug.group_id AND ug.user_pending = 0 + AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) ' . (($sql_user) ? 'AND ug.' . $sql_user : '') . " $sql_forum $sql_opts"; @@ -825,9 +829,11 @@ class auth // Now grab group-specific permission settings $sql = 'SELECT a.forum_id, a.auth_option_id, a.auth_role_id, a.auth_setting - FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug + FROM ' . ACL_GROUPS_TABLE . ' a, ' . USER_GROUP_TABLE . ' ug, ' . GROUPS_TABLE . ' g WHERE a.group_id = ug.group_id + AND g.group_id = ug.group_id AND ug.user_pending = 0 + AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) AND ug.user_id = ' . $user_id; $result = $db->sql_query($sql); diff --git a/phpBB/includes/auth/auth_apache.php b/phpBB/includes/auth/auth_apache.php index 930f5a0632..391e7abb0e 100644 --- a/phpBB/includes/auth/auth_apache.php +++ b/phpBB/includes/auth/auth_apache.php @@ -217,6 +217,7 @@ function user_row_apache($username, $password) 'group_id' => (int) $row['group_id'], 'user_type' => USER_NORMAL, 'user_ip' => $user->ip, + 'user_new' => ($config['new_member_post_limit']) ? 1 : 0, ); } diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php index 24d4c56614..5dc141ff77 100644 --- a/phpBB/includes/auth/auth_db.php +++ b/phpBB/includes/auth/auth_db.php @@ -68,7 +68,6 @@ function login_db(&$username, &$password) if ($config['max_login_attempts'] && $row['user_login_attempts'] >= $config['max_login_attempts']) { $confirm_id = request_var('confirm_id', ''); - $confirm_code = request_var('confirm_code', ''); // Visual Confirmation handling if (!$confirm_id) @@ -81,41 +80,15 @@ function login_db(&$username, &$password) } else { - global $user; + $captcha =& phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha->init(CONFIRM_LOGIN); + $vc_response = $captcha->validate(); - $sql = 'SELECT code - FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_LOGIN; - $result = $db->sql_query($sql); - $confirm_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($confirm_row) - { - if (strcasecmp($confirm_row['code'], $confirm_code) === 0) - { - $sql = 'DELETE FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_LOGIN; - $db->sql_query($sql); - } - else - { - return array( - 'status' => LOGIN_ERROR_ATTEMPTS, - 'error_msg' => 'CONFIRM_CODE_WRONG', - 'user_row' => $row, - ); - } - } - else + if ($vc_response) { return array( 'status' => LOGIN_ERROR_ATTEMPTS, - 'error_msg' => 'CONFIRM_CODE_WRONG', + 'error_msg' => 'LOGIN_ERROR_ATTEMPTS', 'user_row' => $row, ); } @@ -157,7 +130,7 @@ function login_db(&$username, &$password) $row['user_pass_convert'] = 0; $row['user_password'] = $hash; } - else + else { // Although we weren't able to convert this password we have to // increase login attempt count to make sure this cannot be exploited diff --git a/phpBB/includes/auth/auth_ldap.php b/phpBB/includes/auth/auth_ldap.php index d49662fb2d..a6092baba5 100644 --- a/phpBB/includes/auth/auth_ldap.php +++ b/phpBB/includes/auth/auth_ldap.php @@ -63,9 +63,11 @@ function init_ldap() // ldap_connect only checks whether the specified server is valid, so the connection might still fail $search = @ldap_search( $ldap, - $config['ldap_base_dn'], + htmlspecialchars_decode($config['ldap_base_dn']), ldap_user_filter($user->data['username']), - (empty($config['ldap_email'])) ? array($config['ldap_uid']) : array($config['ldap_uid'], $config['ldap_email']), + (empty($config['ldap_email'])) ? + array(htmlspecialchars_decode($config['ldap_uid'])) : + array(htmlspecialchars_decode($config['ldap_uid']), htmlspecialchars_decode($config['ldap_email'])), 0, 1 ); @@ -85,7 +87,7 @@ function init_ldap() return sprintf($user->lang['LDAP_NO_IDENTITY'], $user->data['username']); } - if (!empty($config['ldap_email']) && !isset($result[0][$config['ldap_email']])) + if (!empty($config['ldap_email']) && !isset($result[0][htmlspecialchars_decode($config['ldap_email'])])) { return $user->lang['LDAP_NO_EMAIL']; } @@ -152,7 +154,7 @@ function login_ldap(&$username, &$password) if ($config['ldap_user'] || $config['ldap_password']) { - if (!@ldap_bind($ldap, $config['ldap_user'], htmlspecialchars_decode($config['ldap_password']))) + if (!@ldap_bind($ldap, htmlspecialchars_decode($config['ldap_user']), htmlspecialchars_decode($config['ldap_password']))) { return $user->lang['LDAP_NO_SERVER_CONNECTION']; } @@ -160,9 +162,11 @@ function login_ldap(&$username, &$password) $search = @ldap_search( $ldap, - $config['ldap_base_dn'], + htmlspecialchars_decode($config['ldap_base_dn']), ldap_user_filter($username), - (empty($config['ldap_email'])) ? array($config['ldap_uid']) : array($config['ldap_uid'], $config['ldap_email']), + (empty($config['ldap_email'])) ? + array(htmlspecialchars_decode($config['ldap_uid'])) : + array(htmlspecialchars_decode($config['ldap_uid']), htmlspecialchars_decode($config['ldap_email'])), 0, 1 ); @@ -223,10 +227,11 @@ function login_ldap(&$username, &$password) $ldap_user_row = array( 'username' => $username, 'user_password' => phpbb_hash($password), - 'user_email' => (!empty($config['ldap_email'])) ? $ldap_result[0][$config['ldap_email']][0] : '', + 'user_email' => (!empty($config['ldap_email'])) ? utf8_htmlspecialchars($ldap_result[0][htmlspecialchars_decode($config['ldap_email'])][0]) : '', 'group_id' => (int) $row['group_id'], 'user_type' => USER_NORMAL, 'user_ip' => $user->ip, + 'user_new' => ($config['new_member_post_limit']) ? 1 : 0, ); unset($ldap_result); @@ -276,7 +281,8 @@ function ldap_user_filter($username) $filter = '(' . $config['ldap_uid'] . '=' . ldap_escape(htmlspecialchars_decode($username)) . ')'; if ($config['ldap_user_filter']) { - $filter = "(&$filter({$config['ldap_user_filter']}))"; + $_filter = ($config['ldap_user_filter'][0] == '(' && substr($config['ldap_user_filter'], -1) == ')') ? $config['ldap_user_filter'] : "({$config['ldap_user_filter']})"; + $filter = "(&{$filter}{$_filter})"; } return $filter; } diff --git a/phpBB/includes/bbcode.php b/phpBB/includes/bbcode.php index 562488db70..693523dcbb 100644 --- a/phpBB/includes/bbcode.php +++ b/phpBB/includes/bbcode.php @@ -265,7 +265,7 @@ class bbcode case 6: $this->bbcode_cache[$bbcode_id] = array( 'preg' => array( - '!\[color=(#[0-9a-f]{6}|[a-z\-]+):$uid\](.*?)\[/color:$uid\]!is' => $this->bbcode_tpl('color', $bbcode_id), + '!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+):$uid\](.*?)\[/color:$uid\]!is' => $this->bbcode_tpl('color', $bbcode_id), ) ); break; diff --git a/phpBB/includes/cache.php b/phpBB/includes/cache.php index fc9a01ae4e..1effada666 100644 --- a/phpBB/includes/cache.php +++ b/phpBB/includes/cache.php @@ -84,7 +84,15 @@ class cache extends acm $censors = array(); while ($row = $db->sql_fetchrow($result)) { - $censors['match'][] = '#(?=') || (version_compare(PHP_VERSION, '5.0.0-dev', '<=') && version_compare(PHP_VERSION, '4.4.0', '>='))) && @preg_match('/\p{L}/u', 'a') !== false) + { + $censors['match'][] = '#(?sql_freeresult($result); diff --git a/phpBB/includes/captcha/captcha_factory.php b/phpBB/includes/captcha/captcha_factory.php new file mode 100644 index 0000000000..73406a954f --- /dev/null +++ b/phpBB/includes/captcha/captcha_factory.php @@ -0,0 +1,100 @@ + array(), + 'unavailable' => array(), + ); + + $dp = @opendir($phpbb_root_path . 'includes/captcha/plugins'); + + if ($dp) + { + while (($file = readdir($dp)) !== false) + { + if ((preg_match('#_plugin\.' . $phpEx . '$#', $file))) + { + $name = preg_replace('#^(.*?)_plugin\.' . $phpEx . '$#', '\1', $file); + if (!class_exists($name)) + { + include($phpbb_root_path . "includes/captcha/plugins/$file"); + } + + if (call_user_func(array($name, 'is_available'))) + { + $captchas['available'][$name] = call_user_func(array($name, 'get_name')); + } + else + { + $captchas['unavailable'][$name] = call_user_func(array($name, 'get_name')); + } + } + } + closedir($dp); + } + + return $captchas; + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/captcha/captcha_gd.php b/phpBB/includes/captcha/captcha_gd.php index 9734a63c1b..96e39af85b 100644 --- a/phpBB/includes/captcha/captcha_gd.php +++ b/phpBB/includes/captcha/captcha_gd.php @@ -34,8 +34,8 @@ class captcha function execute($code, $seed) { global $config; - srand($seed); - //mt_srand($seed); + + mt_srand($seed); // Create image $img = imagecreatetruecolor($this->width, $this->height); @@ -108,7 +108,7 @@ class captcha if ($config['captcha_gd_3d_noise']) { - $xoffset = rand(0,9); + $xoffset = mt_rand(0,9); $noise_bitmaps = $this->captcha_noise_bg_bitmaps(); for ($i = 0; $i < $code_len; ++$i) { diff --git a/phpBB/includes/captcha/captcha_gd_wave.php b/phpBB/includes/captcha/captcha_gd_wave.php new file mode 100644 index 0000000000..f706c98d43 --- /dev/null +++ b/phpBB/includes/captcha/captcha_gd_wave.php @@ -0,0 +1,845 @@ +width; + $img_y = $this->height; + + // Generate image + $img = imagecreatetruecolor($img_x, $img_y); + $x_grid = mt_rand(6, 10); + $y_grid = mt_rand(6, 10); + + // Ok, so lets cut to the chase. We could accurately represent this in 3d and + // do all the appropriate linear transforms. my questions is... why bother? + // The computational overhead is unnecessary when you consider the simple fact: + // we're not here to accurately represent a model, but to just show off some random-ish + // polygons + + // Conceive of 3 spaces. + // 1) planar-space (discrete "pixel" grid) + // 2) 3-space. (planar-space with z/height aspect) + // 3) image space (pixels on the screen) + // resolution of the planar-space we're embedding the text code in + $plane_x = 100; + $plane_y = 30; + + $subdivision_factor = 3; + + // $box is the 4 points in img_space that correspond to the corners of the plane in 3-space + $box = array( + 'upper_left' => array( + 'x' => mt_rand(5, 15), + 'y' => mt_rand(10, 15) + ), + 'upper_right' => array( + 'x' => mt_rand($img_x - 35, $img_x - 19), + 'y' => mt_rand(10, 17) + ), + 'lower_left' => array( + 'x' => mt_rand($img_x - 5, $img_x - 45), + 'y' => mt_rand($img_y - 0, $img_y - 15) + ), + ); + + $box['lower_right'] = array( + 'x' => $box['lower_left']['x'] + $box['upper_left']['x'] - $box['upper_right']['x'], + 'y' => $box['lower_left']['y'] + $box['upper_left']['y'] - $box['upper_right']['y'], + ); + + // TODO + $background = imagecolorallocate($img, mt_rand(155, 255), mt_rand(155, 255), mt_rand(155, 255)); + imagefill($img, 0, 0, $background); + $black = imagecolorallocate($img, 0, 0, 0); + + $random = array(); + $fontcolors = array(); + + for ($i = 0; $i < 15; ++$i) + { + $random[$i] = imagecolorallocate($img, mt_rand(120, 255), mt_rand(120, 255), mt_rand(120, 255)); + } + + $fontcolors[0] = imagecolorallocate($img, mt_rand(0, 120), mt_rand(0, 120), mt_rand(0, 120)); + + $colors = array(); + + $minr = mt_rand(20, 30); + $ming = mt_rand(20, 30); + $minb = mt_rand(20, 30); + + $maxr = mt_rand(150, 230); + $maxg = mt_rand(150, 230); + $maxb = mt_rand(150, 230); + + for ($i = -30; $i <= 30; ++$i) + { + $coeff1 = ($i + 12) / 45; + $coeff2 = 1 - $coeff1; + $colors[$i] = imagecolorallocate($img, ($coeff2 * $maxr) + ($coeff1 * $minr), ($coeff2 * $maxg) + ($coeff1 * $ming), ($coeff2 * $maxb) + ($coeff1 * $minb)); + } + + // $img_buffer is the last row of 3-space positions (converted to img-space), cached + // (using this means we don't need to recalculate all 4 positions for each new polygon, + // merely the newest point that we're adding, which is then cached. + $img_buffer = array(array(), array()); + + // In image-space, the x- and y-offset necessary to move one unit in the x-direction in planar-space + $dxx = ($box['upper_right']['x'] - $box['upper_left']['x']) / ($subdivision_factor * $plane_x); + $dxy = ($box['upper_right']['y'] - $box['upper_left']['y']) / ($subdivision_factor * $plane_x); + + // In image-space, the x- and y-offset necessary to move one unit in the y-direction in planar-space + $dyx = ($box['lower_right']['x'] - $box['upper_left']['x']) / ($subdivision_factor * $plane_y); + $dyy = ($box['lower_right']['y'] - $box['upper_left']['y']) / ($subdivision_factor * $plane_y); + + // Initial captcha-letter offset in planar-space + $plane_offset_x = mt_rand(3, 8); + $plane_offset_y = mt_rand( 12, 15); + + // character map + $map = $this->captcha_bitmaps(); + + // matrix + $plane = array(); + + // for each character, we'll silkscreen it into our boolean pixel plane + for ($c = 0, $code_num = strlen($code); $c < $code_num; ++$c) + { + $letter = $code[$c]; + + for ($x = $map['width'] - 1; $x >= 0; --$x) + { + for ($y = $map['height'] - 1; $y >= 0; --$y) + { + if ($map['data'][$letter][$y][$x]) + { + $plane[$y + $plane_offset_y + (($c & 1) ? 1 : -1)][$x + $plane_offset_x] = true; + } + } + } + $plane_offset_x += 11; + } + + // calculate our first buffer, we can't actually draw polys with these yet + // img_pos_prev == screen x,y location to our immediate left. + // img_pos_cur == current screen x,y location + // we calculate screen position of our + // current cell based on the difference from the previous cell + // rather than recalculating from absolute coordinates + // What we cache into the $img_buffer contains the raised text coordinates. + $img_pos_prev = $img_buffer[0][0] = array($box['upper_left']['x'], $box['upper_left']['y']); + $cur_height = $prev_height = $this->wave_height(0, 0, $subdivision_factor); + $full_x = $plane_x * $subdivision_factor; + $full_y = $plane_y * $subdivision_factor; + + for ($x = 1; $x <= $full_x; ++$x) + { + $cur_height = $this->wave_height($x, 0, $subdivision_factor); + $offset = $cur_height - $prev_height; + $img_pos_cur = array($img_pos_prev[0] + $dxx, $img_pos_prev[1] + $dxy + $offset); + + $img_buffer[0][$x] = $img_pos_cur; + $img_pos_prev = $img_pos_cur; + $prev_height = $cur_height; + } + + for ($y = 1; $y <= $full_y; ++$y) + { + // swap buffers + $buffer_cur = $y & 1; + $buffer_prev = 1 - $buffer_cur; + + $prev_height = $this->wave_height(0, $y, $subdivision_factor); + $offset = $prev_height - $this->wave_height(0, $y - 1, $subdivision_factor); + $img_pos_cur = array($img_buffer[$buffer_prev][0][0] + $dyx, min($img_buffer[$buffer_prev][0][1] + $dyy + $offset, $img_y - 1)); + + // make sure we don't try to write off the page + $img_pos_prev = $img_pos_cur; + + $img_buffer[$buffer_cur][0] = $img_pos_cur; + + for ($x = 1; $x <= $full_x; ++$x) + { + $cur_height = $this->wave_height($x, $y, $subdivision_factor) + $this->grid_height($x, $y, 1, $x_grid, $y_grid); + + // height is a z-factor, not a y-factor + $offset = $cur_height - $prev_height; + $img_pos_cur = array($img_pos_prev[0] + $dxx, $img_pos_prev[1] + $dxy + $offset); + + // height is float, index it to an int, get closest color + $color = $colors[intval($cur_height)]; + $img_pos_prev = $img_pos_cur; + $prev_height = $cur_height; + + $y_index_old = intval(($y - 1) / $subdivision_factor); + $y_index_new = intval($y / $subdivision_factor); + $x_index_old = intval(($x - 1) / $subdivision_factor); + $x_index_new = intval($x / $subdivision_factor); + + if (!empty($plane[$y_index_new][$x_index_new])) + { + $img_pos_cur[1] += $this->wave_height($x, $y, $subdivision_factor, 1) - 30 - $cur_height; + $color = $colors[20]; + } + $img_pos_cur[1] = min($img_pos_cur[1], $img_y - 1); + $img_buffer[$buffer_cur][$x] = $img_pos_cur; + + // Smooth the edges as much as possible by having not more than one low<->high traingle per square + // Otherwise, just + $diag_down = (empty($plane[$y_index_old][$x_index_old]) == empty($plane[$y_index_new][$x_index_new])); + $diag_up = (empty($plane[$y_index_old][$x_index_new]) == empty($plane[$y_index_new][$x_index_old])); + + // natural switching + $mode = ($x + $y) & 1; + + // override if it requires it + if ($diag_down != $diag_up) + { + $mode = $diag_up; + } + + if ($mode) + { + // +-/ / + // 1 |/ 2 /| + // / /-+ + $poly1 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_prev][$x]); + $poly2 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_cur][$x], $img_buffer[$buffer_prev][$x]); + } + else + { + // \ \-+ + // 1 |\ 2 \| + // +-\ \ + $poly1 = array_merge($img_buffer[$buffer_cur][$x - 1], $img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_cur][$x]); + $poly2 = array_merge($img_buffer[$buffer_prev][$x - 1], $img_buffer[$buffer_prev][$x], $img_buffer[$buffer_cur][$x]); + } + + imagefilledpolygon($img, $poly1, 3, $color); + imagefilledpolygon($img, $poly2, 3, $color); + } + } + + // Output image + header('Content-Type: image/png'); + header('Cache-control: no-cache, no-store'); + //$mtime = explode(' ', microtime()); + //$totaltime = $mtime[0] + $mtime[1] - $starttime; + + //echo $totaltime . "
    \n"; + //echo memory_get_usage() - $tmp; + imagepng($img); + imagedestroy($img); + } + + function wave_height($x, $y, $factor = 1, $tweak = 0.7) + { + // stretch the wave. TODO: pretty it up + $x = $x/5 + 180; + $y = $y/4; + return ((sin($x / (3 * $factor)) + sin($y / (3 * $factor))) * 10 * $tweak); + } + + function grid_height($x, $y, $factor = 1, $x_grid, $y_grid) + { + return ((!($x % ($x_grid * $factor)) || !($y % ($y_grid * $factor))) ? 3 : 0); + } + + function captcha_bitmaps() + { + return array( + 'width' => 9, + 'height' => 13, + 'data' => array( + 'A' => array( + array(0,0,1,1,1,1,0,0,0), + array(0,1,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,1,1,1,1,1,1,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'B' => array( + array(1,1,1,1,1,1,0,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,1,0,0), + array(1,1,1,1,1,1,0,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,1,0,0), + array(1,1,1,1,1,1,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'C' => array( + array(0,0,1,1,1,1,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'D' => array( + array(1,1,1,1,1,1,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,1,0), + array(1,1,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'E' => array( + array(0,0,1,1,1,1,1,1,1), + array(0,1,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,1,1,1,1,1,1,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(0,1,0,0,0,0,0,0,0), + array(0,0,1,1,1,1,1,1,1), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'F' => array( + array(0,0,1,1,1,1,1,1,0), + array(0,1,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,1,1,1,1,1,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'G' => array( + array(0,0,1,1,1,1,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,1,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'H' => array( + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,1,1,1,1,1,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'I' => array( + array(0,1,1,1,1,1,1,1,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,1,1,1,1,1,1,1,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'J' => array( + array(0,0,0,0,0,0,1,1,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,0,1), + array(0,0,1,0,0,0,0,1,0), + array(0,0,0,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'K' => array( + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,1,0,0,0), + array(1,0,0,0,1,0,0,0,0), + array(1,0,0,1,0,0,0,0,0), + array(1,0,1,0,0,0,0,0,0), + array(1,1,0,0,0,0,0,0,0), + array(1,0,1,0,0,0,0,0,0), + array(1,0,0,1,0,0,0,0,0), + array(1,0,0,0,1,0,0,0,0), + array(1,0,0,0,0,1,0,0,0), + array(1,0,0,0,0,0,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'L' => array( + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(0,1,0,0,0,0,0,0,0), + array(0,0,1,1,1,1,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'M' => array( + array(0,1,0,0,0,0,0,1,0), + array(0,1,1,0,0,0,1,1,0), + array(0,1,0,1,0,1,0,1,0), + array(0,1,0,0,1,0,0,1,0), + array(0,1,0,0,0,0,0,1,0), + array(0,1,0,0,0,0,0,1,0), + array(0,1,0,0,0,0,0,1,0), + array(0,1,0,0,0,0,0,1,0), + array(0,1,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'N' => array( + array(1,0,0,0,0,0,0,0,1), + array(1,1,0,0,0,0,0,0,1), + array(1,0,1,0,0,0,0,0,1), + array(1,0,0,1,0,0,0,0,1), + array(1,0,0,0,1,0,0,0,1), + array(1,0,0,0,0,1,0,0,1), + array(1,0,0,0,0,0,1,0,1), + array(1,0,0,0,0,0,0,1,1), + array(1,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'O' => array( + array(0,0,0,1,1,1,0,0,0), + array(0,0,1,0,0,0,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,0,0,0,1,0,0), + array(0,0,0,1,1,1,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'P' => array( + array(1,1,1,1,1,1,0,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,1,0,0), + array(1,1,1,1,1,1,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'Q' => array( + array(0,0,1,1,1,1,0,0,0), + array(0,1,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,1,0,0,1,0), + array(1,0,0,0,0,1,0,1,0), + array(0,1,0,0,0,0,1,0,0), + array(0,0,1,1,1,1,0,1,0), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'R' => array( + array(1,1,1,1,1,1,0,0,0), + array(1,0,0,0,0,0,1,0,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,1,0,0), + array(1,1,1,1,1,1,0,0,0), + array(1,0,1,0,0,0,0,0,0), + array(1,0,0,1,0,0,0,0,0), + array(1,0,0,0,1,0,0,0,0), + array(1,0,0,0,0,1,0,0,0), + array(1,0,0,0,0,0,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'S' => array( + array(0,0,1,1,1,1,1,1,1), + array(0,1,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(0,1,0,0,0,0,0,0,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,1,0), + array(1,1,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'T' => array( + array(1,1,1,1,1,1,1,1,1), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'U' => array( + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'V' => array( + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,0,0,0,1,0,0), + array(0,0,0,1,0,1,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'W' => array( + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,1,0,0,0,1), + array(1,0,0,1,0,1,0,0,1), + array(1,0,1,0,0,0,1,0,1), + array(1,1,0,0,0,0,0,1,1), + array(1,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'X' => array( + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,0,0,0,1,0,0), + array(0,0,0,1,0,1,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,1,0,1,0,0,0), + array(0,0,1,0,0,0,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'Y' => array( + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,0,0,0,1,0,0), + array(0,0,0,1,0,1,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + 'Z' => array( + array(1,1,1,1,1,1,1,1,1), + array(1,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,1,0,0), + array(0,0,0,0,0,1,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,1,0,0,0,0,0), + array(0,0,1,0,0,0,0,0,0), + array(0,1,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,1), + array(1,1,1,1,1,1,1,1,1), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '1' => array( + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,1,1,0,0,0,0), + array(0,0,1,0,1,0,0,0,0), + array(0,1,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,1,1,1,1,1,1,1,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '2' => array( + array(0,0,0,1,1,1,0,0,0), + array(0,0,1,0,0,0,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,1,0,0), + array(0,0,0,0,0,1,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,1,0,0,0,0,0), + array(0,0,1,0,0,0,0,0,0), + array(0,1,1,1,1,1,1,1,1), + array(0,0,0,0,0,0,0,0,0), + ), + '3' => array( + array(0,0,0,1,1,1,1,0,0), + array(0,0,1,0,0,0,0,1,0), + array(0,1,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,1,1,0,0), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,0,1), + array(0,0,1,0,0,0,0,1,0), + array(0,0,0,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '4' => array( + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,1,1,0), + array(0,0,0,0,0,1,0,1,0), + array(0,0,0,0,1,0,0,1,0), + array(0,0,0,1,0,0,0,1,0), + array(0,0,1,0,0,0,0,1,0), + array(0,1,1,1,1,1,1,1,1), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '5' => array( + array(1,1,1,1,1,1,1,1,1), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(0,1,0,0,0,0,0,0,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '6' => array( + array(0,0,1,1,1,1,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,0,0,0,0,0,0), + array(1,0,0,1,1,1,1,0,0), + array(1,0,1,0,0,0,0,1,0), + array(1,1,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '7' => array( + array(1,1,1,1,1,1,1,1,1), + array(1,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,1,0), + array(0,0,0,0,0,0,1,0,0), + array(0,0,0,0,0,1,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,1,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '8' => array( + array(0,0,1,1,1,1,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,1,0,0,0,0,0,1,0), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(1,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,0), + array(0,0,1,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + '9' => array( + array(0,0,0,1,1,1,1,0,0), + array(0,0,1,0,0,0,0,1,0), + array(0,1,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,1,1), + array(0,0,1,1,1,1,1,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,0,0,0,0,0,0,0,1), + array(0,1,0,0,0,0,0,0,1), + array(0,0,1,0,0,0,0,1,0), + array(0,0,0,1,1,1,1,0,0), + array(0,0,0,0,0,0,0,0,0), + array(0,0,0,0,0,0,0,0,0), + ), + ) + ); + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/captcha_abstract.php b/phpBB/includes/captcha/plugins/captcha_abstract.php new file mode 100644 index 0000000000..db4b7649c7 --- /dev/null +++ b/phpBB/includes/captcha/plugins/captcha_abstract.php @@ -0,0 +1,375 @@ +confirm_id = request_var('confirm_id', ''); + $this->confirm_code = request_var('confirm_code', ''); + $refresh = request_var('refresh_vc', false) && $config['confirm_refresh']; + + $this->type = (int) $type; + + if (!strlen($this->confirm_id) || !$this->load_code()) + { + // we have no confirm ID, better get ready to display something + $this->generate_code(); + } + else if ($refresh) + { + $this->regenerate_code(); + } + } + + function execute_demo() + { + global $user; + + $this->code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); + $this->seed = hexdec(substr(unique_id(), 4, 10)); + + // compute $seed % 0x7fffffff + $this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); + + $captcha = new captcha(); + define('IMAGE_OUTPUT', 1); + $captcha->execute($this->code, $this->seed); + } + + function execute() + { + if (empty($this->code)) + { + if (!$this->load_code()) + { + // invalid request, bail out + return false; + } + } + $captcha = new captcha(); + define('IMAGE_OUTPUT', 1); + $captcha->execute($this->code, $this->seed); + } + + function get_template() + { + global $config, $user, $template, $phpEx, $phpbb_root_path; + + if ($this->is_solved()) + { + return false; + } + else + { + $link = append_sid($phpbb_root_path . 'ucp.' . $phpEx, 'mode=confirm&confirm_id=' . $this->confirm_id . '&type=' . $this->type); + $explain = $user->lang(($this->type != CONFIRM_POST) ? 'CONFIRM_EXPLAIN' : 'POST_CONFIRM_EXPLAIN', '', ''); + + $template->assign_vars(array( + 'CONFIRM_IMAGE_LINK' => $link, + 'CONFIRM_IMAGE' => '', + 'CONFIRM_IMG' => '', + 'CONFIRM_ID' => $this->confirm_id, + 'S_CONFIRM_CODE' => true, + 'S_TYPE' => $this->type, + 'S_CONFIRM_REFRESH' => ($config['enable_confirm'] && $config['confirm_refresh'] && $this->type == CONFIRM_REG) ? true : false, + 'L_CONFIRM_EXPLAIN' => $explain, + )); + + return 'captcha_default.html'; + } + } + + function get_demo_template($id) + { + global $config, $user, $template, $phpbb_admin_path, $phpEx; + + $variables = ''; + + if (is_array($this->captcha_vars)) + { + foreach ($this->captcha_vars as $captcha_var => $template_var) + { + $variables .= '&' . rawurlencode($captcha_var) . '=' . request_var($captcha_var, (int) $config[$captcha_var]); + } + } + + // acp_captcha has a delivery function; let's use it + $template->assign_vars(array( + 'CONFIRM_IMAGE' => append_sid($phpbb_admin_path . 'index.' . $phpEx, 'captcha_demo=1&mode=visual&i=' . $id . '&select_captcha=' . $this->get_class_name()) . $variables, + 'CONFIRM_ID' => $this->confirm_id, + )); + + return 'captcha_default_acp_demo.html'; + } + + function get_hidden_fields() + { + $hidden_fields = array(); + + // this is required for posting.php - otherwise we would forget about the captcha being already solved + if ($this->solved) + { + $hidden_fields['confirm_code'] = $this->confirm_code; + } + $hidden_fields['confirm_id'] = $this->confirm_id; + return $hidden_fields; + } + + function garbage_collect($type) + { + global $db, $config; + + $sql = 'SELECT DISTINCT c.session_id + FROM ' . CONFIRM_TABLE . ' c + LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id) + WHERE s.session_id IS NULL' . + ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); + $result = $db->sql_query($sql); + + if ($row = $db->sql_fetchrow($result)) + { + $sql_in = array(); + do + { + $sql_in[] = (string) $row['session_id']; + } + while ($row = $db->sql_fetchrow($result)); + + if (sizeof($sql_in)) + { + $sql = 'DELETE FROM ' . CONFIRM_TABLE . ' + WHERE ' . $db->sql_in_set('session_id', $sql_in); + $db->sql_query($sql); + } + } + $db->sql_freeresult($result); + } + + function uninstall() + { + $this->garbage_collect(0); + } + + function install() + { + return; + } + + function validate() + { + global $config, $db, $user; + + $error = ''; + if (!$this->confirm_id) + { + $error = $user->lang['CONFIRM_CODE_WRONG']; + } + else + { + if ($this->check_code()) + { + // $this->delete_code(); commented out to allow posting.php to repeat the question + $this->solved = true; + } + else + { + $error = $user->lang['CONFIRM_CODE_WRONG']; + } + } + + if (strlen($error)) + { + // okay, incorrect answer. Let's ask a new question. + $this->new_attempt(); + return $error; + } + else + { + return false; + } + } + + /** + * The old way to generate code, suitable for GD and non-GD. Resets the internal state. + */ + function generate_code() + { + global $db, $user; + + $this->code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); + $this->confirm_id = md5(unique_id($user->ip)); + $this->seed = hexdec(substr(unique_id(), 4, 10)); + $this->solved = 0; + // compute $seed % 0x7fffffff + $this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); + + $sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( + 'confirm_id' => (string) $this->confirm_id, + 'session_id' => (string) $user->session_id, + 'confirm_type' => (int) $this->type, + 'code' => (string) $this->code, + 'seed' => (int) $this->seed) + ); + $db->sql_query($sql); + } + + /** + * New Question, if desired. + */ + function regenerate_code() + { + global $db, $user; + + $this->code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); + $this->seed = hexdec(substr(unique_id(), 4, 10)); + $this->solved = 0; + // compute $seed % 0x7fffffff + $this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); + + $sql = 'UPDATE ' . CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( + 'code' => (string) $this->code, + 'seed' => (int) $this->seed)) . ' + WHERE + confirm_id = \'' . $db->sql_escape($this->confirm_id) . '\' + AND session_id = \'' . $db->sql_escape($user->session_id) . '\''; + $db->sql_query($sql); + } + + /** + * New Question, if desired. + */ + function new_attempt() + { + global $db, $user; + + $this->code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); + $this->seed = hexdec(substr(unique_id(), 4, 10)); + $this->solved = 0; + // compute $seed % 0x7fffffff + $this->seed -= 0x7fffffff * floor($this->seed / 0x7fffffff); + + $sql = 'UPDATE ' . CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( + 'code' => (string) $this->code, + 'seed' => (int) $this->seed)) . ' + , attempts = attempts + 1 + WHERE + confirm_id = \'' . $db->sql_escape($this->confirm_id) . '\' + AND session_id = \'' . $db->sql_escape($user->session_id) . '\''; + $db->sql_query($sql); + } + + /** + * Look up everything we need for painting&checking. + */ + function load_code() + { + global $db, $user; + + $sql = 'SELECT code, seed, attempts + FROM ' . CONFIRM_TABLE . " + WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' + AND session_id = '" . $db->sql_escape($user->session_id) . "' + AND confirm_type = " . $this->type; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if ($row) + { + $this->code = $row['code']; + $this->seed = $row['seed']; + $this->attempts = $row['attempts']; + return true; + } + + return false; + } + + function check_code() + { + return (strcasecmp($this->code, $this->confirm_code) === 0); + } + + function delete_code() + { + global $db, $user; + + $sql = 'DELETE FROM ' . CONFIRM_TABLE . " + WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' + AND session_id = '" . $db->sql_escape($user->session_id) . "' + AND confirm_type = " . $this->type; + $db->sql_query($sql); + } + + function get_attempt_count() + { + return $this->attempts; + } + + function reset() + { + global $db, $user; + + $sql = 'DELETE FROM ' . CONFIRM_TABLE . " + WHERE session_id = '" . $db->sql_escape($user->session_id) . "' + AND confirm_type = " . (int) $this->type; + $db->sql_query($sql); + + // we leave the class usable by generating a new question + $this->generate_code(); + } + + function is_solved() + { + if (request_var('confirm_code', false) && $this->solved === 0) + { + $this->validate(); + } + return (bool) $this->solved; + } + + /** + * API function + */ + function has_config() + { + return false; + } + +} + +?> \ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_gd_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_gd_plugin.php new file mode 100644 index 0000000000..a85566deff --- /dev/null +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_gd_plugin.php @@ -0,0 +1,163 @@ + 'CAPTCHA_GD_X_GRID', + 'captcha_gd_y_grid' => 'CAPTCHA_GD_Y_GRID', + 'captcha_gd_foreground_noise' => 'CAPTCHA_GD_FOREGROUND_NOISE', +// 'captcha_gd' => 'CAPTCHA_GD_PREVIEWED', + 'captcha_gd_wave' => 'CAPTCHA_GD_WAVE', + 'captcha_gd_3d_noise' => 'CAPTCHA_GD_3D_NOISE', + 'captcha_gd_fonts' => 'CAPTCHA_GD_FONTS', + ); + + function phpbb_captcha_gd() + { + global $phpbb_root_path, $phpEx; + + if (!class_exists('captcha')) + { + include($phpbb_root_path . 'includes/captcha/captcha_gd.' . $phpEx); + } + } + + function &get_instance() + { + $instance =& new phpbb_captcha_gd(); + return $instance; + } + + function is_available() + { + global $phpbb_root_path, $phpEx; + + if (@extension_loaded('gd')) + { + return true; + } + + if (!function_exists('can_load_dll')) + { + include($phpbb_root_path . 'includes/functions_install.' . $phpEx); + } + + return can_load_dll('gd'); + } + + /** + * API function + */ + function has_config() + { + return true; + } + + function get_name() + { + return 'CAPTCHA_GD'; + } + + function get_class_name() + { + return 'phpbb_captcha_gd'; + } + + function acp_page($id, &$module) + { + global $db, $user, $auth, $template; + global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + + $user->add_lang('acp/board'); + + $config_vars = array( + 'enable_confirm' => 'REG_ENABLE', + 'enable_post_confirm' => 'POST_ENABLE', + 'confirm_refresh' => 'CONFIRM_REFRESH', + 'captcha_gd' => 'CAPTCHA_GD', + ); + + $module->tpl_name = 'captcha_gd_acp'; + $module->page_title = 'ACP_VC_SETTINGS'; + $form_key = 'acp_captcha'; + add_form_key($form_key); + + $submit = request_var('submit', ''); + + if ($submit && check_form_key($form_key)) + { + $captcha_vars = array_keys($this->captcha_vars); + foreach ($captcha_vars as $captcha_var) + { + $value = request_var($captcha_var, 0); + if ($value >= 0) + { + set_config($captcha_var, $value); + } + } + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action)); + } + else if ($submit) + { + trigger_error($user->lang['FORM_INVALID'] . adm_back_link($module->u_action)); + } + else + { + foreach ($this->captcha_vars as $captcha_var => $template_var) + { + $var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, 0) : $config[$captcha_var]; + $template->assign_var($template_var, $var); + } + + $template->assign_vars(array( + 'CAPTCHA_PREVIEW' => $this->get_demo_template($id), + 'CAPTCHA_NAME' => $this->get_class_name(), + 'U_ACTION' => $module->u_action, + )); + } + } + + function execute_demo() + { + global $config; + + $config_old = $config; + foreach ($this->captcha_vars as $captcha_var => $template_var) + { + $config[$captcha_var] = request_var($captcha_var, (int) $config[$captcha_var]); + } + parent::execute_demo(); + $config = $config_old; + } + +} + +?> \ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_gd_wave_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_gd_wave_plugin.php new file mode 100644 index 0000000000..2f55d15efd --- /dev/null +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_gd_wave_plugin.php @@ -0,0 +1,83 @@ +lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action)); + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_nogd_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_nogd_plugin.php new file mode 100644 index 0000000000..ac30ed4297 --- /dev/null +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_nogd_plugin.php @@ -0,0 +1,72 @@ +lang['CAPTCHA_NO_OPTIONS'] . adm_back_link($module->u_action)); + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php new file mode 100644 index 0000000000..6f53e8c5ad --- /dev/null +++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php @@ -0,0 +1,924 @@ +add_lang('captcha_qa'); + + // read input + $this->confirm_id = request_var('qa_confirm_id', ''); + $this->answer = request_var('qa_answer', '', true); + + $this->type = (int) $type; + $this->question_lang = $user->data['user_lang']; + + // we need all defined questions - shouldn't be too many, so we can just grab them + // try the user's lang first + $sql = 'SELECT question_id + FROM ' . CAPTCHA_QUESTIONS_TABLE . " + WHERE lang_iso = '" . $db->sql_escape($user->data['user_lang']) . "'"; + $result = $db->sql_query($sql, 3600); + + while ($row = $db->sql_fetchrow($result)) + { + $this->question_ids[$row['question_id']] = $row['question_id']; + } + $db->sql_freeresult($result); + + // fallback to the board default lang + if (!sizeof($this->question_ids)) + { + $this->question_lang = $config['default_lang']; + + $sql = 'SELECT question_id + FROM ' . CAPTCHA_QUESTIONS_TABLE . " + WHERE lang_iso = '" . $db->sql_escape($config['default_lang']) . "'"; + $result = $db->sql_query($sql, 7200); + + while ($row = $db->sql_fetchrow($result)) + { + $this->question_ids[$row['question_id']] = $row['question_id']; + } + $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()) + { + // we have no valid confirm ID, better get ready to ask something + $this->select_question(); + } + } + + /** + * API function + */ + function &get_instance() + { + $instance =& new phpbb_captcha_qa(); + + return $instance; + } + + /** + * See if the captcha has created its tables. + */ + function is_installed() + { + global $db, $phpbb_root_path, $phpEx; + + if (!class_exists('phpbb_db_tools')) + { + include("$phpbb_root_path/includes/db/db_tools.$phpEx"); + } + $db_tool = new phpbb_db_tools($db); + + return $db_tool->sql_table_exists(CAPTCHA_QUESTIONS_TABLE); + } + + /** + * API function - for the captcha to be available, it must have installed itself and there has to be at least one question in the board's default lang + */ + function is_available() + { + global $config, $db, $phpbb_root_path, $phpEx, $user; + + // load language file for pretty display in the ACP dropdown + $user->add_lang('captcha_qa'); + + if (!phpbb_captcha_qa::is_installed()) + { + return false; + } + + $sql = 'SELECT COUNT(question_id) as 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']); + } + + /** + * API function + */ + function has_config() + { + return true; + } + + /** + * API function + */ + function get_name() + { + return 'CAPTCHA_QA'; + } + + /** + * API function + */ + function get_class_name() + { + return 'phpbb_captcha_qa'; + } + + /** + * API function - not needed as we don't display an image + */ + function execute_demo() + { + } + + /** + * API function - not needed as we don't display an image + */ + function execute() + { + } + + /** + * API function - send the question to the template + */ + function get_template() + { + global $template; + + if ($this->is_solved()) + { + return false; + } + else + { + $template->assign_vars(array( + 'QA_CONFIRM_QUESTION' => $this->question_text, + 'QA_CONFIRM_ID' => $this->confirm_id, + 'S_CONFIRM_CODE' => true, + 'S_TYPE' => $this->type, + )); + + return 'captcha_qa.html'; + } + } + + /** + * API function - we just display a mockup so that the captcha doesn't need to be installed + */ + function get_demo_template() + { + return 'captcha_qa_acp_demo.html'; + } + + /** + * API function + */ + function get_hidden_fields() + { + $hidden_fields = array(); + + // this is required - otherwise we would forget about the captcha being already solved + if ($this->solved) + { + $hidden_fields['qa_answer'] = $this->answer; + } + $hidden_fields['qa_confirm_id'] = $this->confirm_id; + + return $hidden_fields; + } + + /** + * API function + */ + function garbage_collect($type) + { + global $db, $config; + + $sql = 'SELECT DISTINCT c.session_id + FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' c + LEFT JOIN ' . SESSIONS_TABLE . ' s + ON (c.session_id = s.session_id) + WHERE s.session_id IS NULL' . + ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); + $result = $db->sql_query($sql); + + if ($row = $db->sql_fetchrow($result)) + { + $sql_in = array(); + + do + { + $sql_in[] = (string) $row['session_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); + $db->sql_query($sql); + } + } + $db->sql_freeresult($result); + } + + /** + * API function - we don't drop the tables here, as that would cause the loss of all entered questions. + */ + function uninstall() + { + $this->garbage_collect(0); + } + + /** + * API function - set up shop + */ + function install() + { + global $db, $phpbb_root_path, $phpEx; + + if (!class_exists('phpbb_db_tools')) + { + include("$phpbb_root_path/includes/db/db_tools.$phpEx"); + } + $db_tool = new phpbb_db_tools($db); + + $tables = array(CAPTCHA_QUESTIONS_TABLE, CAPTCHA_ANSWERS_TABLE, CAPTCHA_QA_CONFIRM_TABLE); + + $schemas = array( + CAPTCHA_QUESTIONS_TABLE => array ( + 'COLUMNS' => array( + 'question_id' => array('UINT', Null, 'auto_increment'), + 'strict' => array('BOOL', 0), + 'lang_id' => array('UINT', 0), + 'lang_iso' => array('VCHAR:30', ''), + 'question_text' => array('TEXT_UNI', ''), + ), + 'PRIMARY_KEY' => 'question_id', + 'KEYS' => array( + 'lang_iso' => array('INDEX', 'lang_iso'), + ), + ), + CAPTCHA_ANSWERS_TABLE => array ( + 'COLUMNS' => array( + 'question_id' => array('UINT', 0), + 'answer_text' => array('STEXT_UNI', ''), + ), + 'KEYS' => array( + 'question_id' => array('INDEX', 'question_id'), + ), + ), + CAPTCHA_QA_CONFIRM_TABLE => array ( + 'COLUMNS' => array( + 'session_id' => array('CHAR:32', ''), + 'confirm_id' => array('CHAR:32', ''), + 'lang_iso' => array('VCHAR:30', ''), + 'question_id' => array('UINT', 0), + 'attempts' => array('UINT', 0), + 'confirm_type' => array('USINT', 0), + ), + 'KEYS' => array( + 'session_id' => array('INDEX', 'session_id'), + 'lookup' => array('INDEX', array('confirm_id', 'session_id', 'lang_iso')), + ), + 'PRIMARY_KEY' => 'confirm_id', + ), + ); + + foreach($schemas as $table => $schema) + { + if (!$db_tool->sql_table_exists($table)) + { + $db_tool->sql_create_table($table, $schema); + } + } + } + + /** + * API function - see what has to be done to validate + */ + function validate() + { + global $config, $db, $user; + + $error = ''; + + if (!$this->confirm_id) + { + $error = $user->lang['CONFIRM_QUESTION_WRONG']; + } + else + { + if ($this->check_answer()) + { + // $this->delete_code(); commented out to allow posting.php to repeat the question + $this->solved = true; + } + else + { + $error = $user->lang['CONFIRM_QUESTION_WRONG']; + } + } + + if (strlen($error)) + { + // okay, incorrect answer. Let's ask a new question. + $this->new_attempt(); + $this->solved = false; + + return $error; + } + else + { + return false; + } + } + + /** + * Select a question + */ + function select_question() + { + global $db, $user; + + $this->confirm_id = md5(unique_id($user->ip)); + $this->question = (int) array_rand($this->question_ids); + + $sql = 'INSERT INTO ' . CAPTCHA_QA_CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( + 'confirm_id' => (string) $this->confirm_id, + 'session_id' => (string) $user->session_id, + 'lang_iso' => (string) $this->question_lang, + 'confirm_type' => (int) $this->type, + 'question_id' => (int) $this->question, + )); + $db->sql_query($sql); + + $this->load_answer(); + } + + /** + * New Question, if desired. + */ + function reselect_question() + { + global $db, $user; + + $this->question = (int) array_rand($this->question_ids); + $this->solved = 0; + + $sql = 'UPDATE ' . CAPTCHA_QA_CONFIRM_TABLE . ' + SET question_id = ' . (int) $this->question . " + WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' + AND session_id = '" . $db->sql_escape($user->session_id) . "'"; + $db->sql_query($sql); + + $this->load_answer(); + } + + /** + * Wrong answer, so we increase the attempts and use a different question. + */ + function new_attempt() + { + global $db, $user; + + // yah, I would prefer a stronger rand, but this should work + $this->question = (int) array_rand($this->question_ids); + $this->solved = 0; + + $sql = 'UPDATE ' . CAPTCHA_QA_CONFIRM_TABLE . ' + SET question_id = ' . (int) $this->question . ", + attempts = attempts + 1 + WHERE confirm_id = '" . $db->sql_escape($this->confirm_id) . "' + AND session_id = '" . $db->sql_escape($user->session_id) . "'"; + $db->sql_query($sql); + + $this->load_answer(); + } + + /** + * Look up everything we need and populate the instance variables. + */ + function load_answer() + { + global $db, $user; + + $sql = 'SELECT con.question_id, attempts, question_text, strict + FROM ' . CAPTCHA_QA_CONFIRM_TABLE . ' con, ' . CAPTCHA_QUESTIONS_TABLE . " qes + WHERE con.question_id = qes.question_id + AND confirm_id = '" . $db->sql_escape($this->confirm_id) . "' + AND session_id = '" . $db->sql_escape($user->session_id) . "' + AND qes.lang_iso = '" . $db->sql_escape($this->question_lang) . "' + AND confirm_type = " . $this->type; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if ($row) + { + $this->question = $row['question_id']; + + $this->attempts = $row['attempts']; + $this->question_strict = $row['strict']; + $this->question_text = $row['question_text']; + + return true; + } + + return false; + } + + /** + * The actual validation + */ + function check_answer() + { + global $db; + + $answer = ($this->question_strict) ? request_var('qa_answer', '', true) : utf8_clean_string(request_var('qa_answer', '', true)); + + $sql = 'SELECT answer_text + FROM ' . CAPTCHA_ANSWERS_TABLE . ' + WHERE question_id = ' . (int) $this->question; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $solution = ($this->question_strict) ? $row['answer_text'] : utf8_clean_string($row['answer_text']); + + if ($solution === $answer) + { + $this->solved = true; + + break; + } + } + $db->sql_freeresult($result); + + return $this->solved; + } + + /** + * API function - clean the entry + */ + function delete_code() + { + global $db, $user; + + $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " + WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' + AND session_id = '" . $db->sql_escape($user->session_id) . "' + AND confirm_type = " . $this->type; + $db->sql_query($sql); + } + + /** + * API function + */ + function get_attempt_count() + { + return $this->attempts; + } + + /** + * API function + */ + function reset() + { + global $db, $user; + + $sql = 'DELETE FROM ' . CAPTCHA_QA_CONFIRM_TABLE . " + WHERE session_id = '" . $db->sql_escape($user->session_id) . "' + AND confirm_type = " . (int) $this->type; + $db->sql_query($sql); + + // we leave the class usable by generating a new question + $this->select_question(); + } + + /** + * API function + */ + function is_solved() + { + if (request_var('qa_answer', false) && $this->solved === 0) + { + $this->validate(); + } + + return (bool) $this->solved; + } + + /** + * API function - The ACP backend, this marks the end of the easy methods + */ + function acp_page($id, &$module) + { + global $db, $user, $auth, $template; + global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx; + + $user->add_lang('acp/board'); + $user->add_lang('captcha_qa'); + + if (!$this->is_installed()) + { + $this->install(); + } + + $module->tpl_name = 'captcha_qa_acp'; + $module->page_title = 'ACP_VC_SETTINGS'; + $form_key = 'acp_captcha'; + add_form_key($form_key); + + $submit = request_var('submit', false); + $question_id = request_var('question_id', 0); + $action = request_var('action', ''); + + // we have two pages, so users might want to navigate from one to the other + $list_url = $module->u_action . "&configure=1&select_captcha=" . $this->get_class_name(); + + $template->assign_vars(array( + 'U_ACTION' => $module->u_action, + 'QUESTION_ID' => $question_id , + 'CLASS' => $this->get_class_name(), + )); + + // show the list? + if (!$question_id && $action != 'add') + { + $this->acp_question_list($module); + } + else if ($question_id && $action == 'delete') + { + if (confirm_box(true)) + { + $this->acp_delete_question($question_id); + + 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 + { + // okay, show the editor + $error = false; + $input_question = request_var('question_text', '', true); + $input_answers = request_var('answers', '', true); + $input_lang = request_var('lang_iso', '', true); + $input_strict = request_var('strict', false); + $langs = $this->get_languages(); + + foreach ($langs as $lang => $entry) + { + $template->assign_block_vars('langs', array( + 'ISO' => $lang, + 'NAME' => $entry['name'], + )); + } + + $template->assign_vars(array( + 'U_LIST' => $list_url, + )); + + if ($question_id) + { + if ($question = $this->acp_get_question_data($question_id)) + { + $answers = (isset($input_answers[$lang])) ? $input_answers[$lang] : implode("\n", $question['answers']); + + $template->assign_vars(array( + 'QUESTION_TEXT' => ($input_question) ? $input_question : $question['question_text'], + 'LANG_ISO' => ($input_lang) ? $input_lang : $question['lang_iso'], + 'STRICT' => (isset($_REQUEST['strict'])) ? $input_strict : $question['strict'], + 'ANSWERS' => $answers, + )); + } + else + { + trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url)); + } + } + else + { + $template->assign_vars(array( + 'QUESTION_TEXT' => $input_question, + 'LANG_ISO' => $input_lang, + 'STRICT' => $input_strict, + 'ANSWERS' => $input_answers, + )); + } + + if ($submit && check_form_key($form_key)) + { + $data = $this->acp_get_question_input(); + + if (!$this->validate_input($data)) + { + $template->assign_vars(array( + 'S_ERROR' => true, + )); + } + else + { + if ($question_id) + { + $this->acp_update_question($data, $question_id); + } + else + { + $this->acp_add_question($data); + } + + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($list_url)); + } + } + else if ($submit) + { + trigger_error($user->lang['FORM_INVALID'] . adm_back_link($list_url)); + } + } + } + + /** + * This handles the list overview + */ + function acp_question_list(&$module) + { + global $db, $template; + + $sql = 'SELECT * + FROM ' . CAPTCHA_QUESTIONS_TABLE; + $result = $db->sql_query($sql); + + $template->assign_vars(array( + 'S_LIST' => true, + )); + + while ($row = $db->sql_fetchrow($result)) + { + $url = $module->u_action . "&question_id={$row['question_id']}&configure=1&select_captcha=" . $this->get_class_name() . '&'; + + $template->assign_block_vars('questions', array( + 'QUESTION_TEXT' => $row['question_text'], + 'QUESTION_ID' => $row['question_id'], + 'QUESTION_LANG' => $row['lang_iso'], + 'U_DELETE' => "{$url}action=delete", + 'U_EDIT' => "{$url}action=edit", + )); + } + $db->sql_freeresult($result); + } + + /** + * Grab a question and bring it into a format the editor understands + */ + function acp_get_question_data($question_id) + { + global $db; + + if ($question_id) + { + $sql = 'SELECT * + FROM ' . CAPTCHA_QUESTIONS_TABLE . ' + WHERE question_id = ' . $question_id; + $result = $db->sql_query($sql); + $question = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if (!$question) + { + return false; + } + + $question['answers'] = array(); + + $sql = 'SELECT * + FROM ' . CAPTCHA_ANSWERS_TABLE . ' + WHERE question_id = ' . $question_id; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $question['answers'][] = $row['answer_text']; + } + $db->sql_freeresult($result); + + return $question; + } + } + + /** + * Grab a question from input and bring it into a format the editor understands + */ + function acp_get_question_input() + { + $question = array( + 'question_text' => request_var('question_text', '', true), + 'strict' => request_var('strict', false), + 'lang_iso' => request_var('lang_iso', ''), + 'answers' => explode("\n", request_var('answers', '', true)), + ); + + return $question; + } + + /** + * Update a question. + * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data + */ + function acp_update_question($data, $question_id) + { + global $db, $cache; + + // easier to delete all answers than to figure out which to update + $sql = 'DELETE FROM ' . CAPTCHA_ANSWERS_TABLE . " WHERE question_id = $question_id"; + $db->sql_query($sql); + + $langs = $this->get_languages(); + $question_ary = $data; + $question_ary['lang_id'] = $langs[$question_ary['lang_iso']]['id']; + unset($question_ary['answers']); + + $sql = 'UPDATE ' . CAPTCHA_QUESTIONS_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $question_ary) . " + WHERE question_id = $question_id"; + $db->sql_query($sql); + + $this->acp_insert_answers($data, $question_id); + + $cache->destroy('sql', CAPTCHA_QUESTIONS_TABLE); + } + + /** + * Insert a question. + * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data + */ + function acp_add_question($data) + { + global $db, $cache; + + $langs = $this->get_languages(); + $question_ary = $data; + + $question_ary['lang_id'] = $langs[$data['lang_iso']]['id']; + unset($question_ary['answers']); + + $sql = 'INSERT INTO ' . CAPTCHA_QUESTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $question_ary); + $db->sql_query($sql); + + $question_id = $db->sql_nextid(); + + $this->acp_insert_answers($data, $question_id); + + $cache->destroy('sql', CAPTCHA_QUESTIONS_TABLE); + } + + /** + * Insert the answers. + * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data + */ + function acp_insert_answers($data, $question_id) + { + global $db, $cache; + + foreach ($data['answers'] as $answer) + { + $answer_ary = array( + 'question_id' => $question_id, + 'answer_text' => $answer, + ); + + $sql = 'INSERT INTO ' . CAPTCHA_ANSWERS_TABLE . ' ' . $db->sql_build_array('INSERT', $answer_ary); + $db->sql_query($sql); + } + + $cache->destroy('sql', CAPTCHA_ANSWERS_TABLE); + } + + /** + * Delete a question. + */ + function acp_delete_question($question_id) + { + global $db, $cache; + + $tables = array(CAPTCHA_QUESTIONS_TABLE, CAPTCHA_ANSWERS_TABLE); + + foreach ($tables as $table) + { + $sql = "DELETE FROM $table + WHERE question_id = $question_id"; + $db->sql_query($sql); + } + + $cache->destroy('sql', $tables); + } + + /** + * Check if the entered data can be inserted/used + * param mixed $data : an array as created from acp_get_question_input or acp_get_question_data + */ + function validate_input($question_data) + { + $langs = $this->get_languages(); + + if (!isset($question_data['lang_iso']) || + !isset($question_data['question_text']) || + !isset($question_data['strict']) || + !isset($question_data['answers'])) + { + return false; + } + + if (!isset($langs[$question_data['lang_iso']]) || + !$question_data['question_text'] || + !sizeof($question_data['answers'])) + { + return false; + } + + return true; + } + + /** + * List the installed language packs + */ + function get_languages() + { + global $db; + + $sql = 'SELECT * + FROM ' . LANG_TABLE; + $result = $db->sql_query($sql); + + $langs = array(); + while ($row = $db->sql_fetchrow($result)) + { + $langs[$row['lang_iso']] = array( + 'name' => $row['lang_local_name'], + 'id' => (int) $row['lang_id'], + ); + } + $db->sql_freeresult($result); + + return $langs; + } +} + +?> \ 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 new file mode 100644 index 0000000000..2d37b13a4f --- /dev/null +++ b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php @@ -0,0 +1,334 @@ +add_lang('captcha_recaptcha'); + parent::init($type); + $this->challenge = request_var('recaptcha_challenge_field', ''); + $this->response = request_var('recaptcha_response_field', ''); + } + + function &get_instance() + { + $instance =& new phpbb_recaptcha(); + return $instance; + } + + function is_available() + { + global $config, $user; + $user->add_lang('captcha_recaptcha'); + return (isset($config['recaptcha_pubkey']) && !empty($config['recaptcha_pubkey'])); + } + + /** + * API function + */ + function has_config() + { + return true; + } + + function get_name() + { + return 'CAPTCHA_RECAPTCHA'; + } + + function get_class_name() + { + return 'phpbb_recaptcha'; + } + + function acp_page($id, &$module) + { + global $config, $db, $template, $user; + + $captcha_vars = array( + 'recaptcha_pubkey' => 'RECAPTCHA_PUBKEY', + 'recaptcha_privkey' => 'RECAPTCHA_PRIVKEY', + ); + + $module->tpl_name = 'captcha_recaptcha_acp'; + $module->page_title = 'ACP_VC_SETTINGS'; + $form_key = 'acp_captcha'; + add_form_key($form_key); + + $submit = request_var('submit', ''); + + if ($submit && check_form_key($form_key)) + { + $captcha_vars = array_keys($captcha_vars); + foreach ($captcha_vars as $captcha_var) + { + $value = request_var($captcha_var, ''); + if ($value) + { + set_config($captcha_var, $value); + } + } + trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($module->u_action)); + } + else if ($submit) + { + trigger_error($user->lang['FORM_INVALID'] . adm_back_link($module->u_action)); + } + else + { + foreach ($captcha_vars as $captcha_var => $template_var) + { + $var = (isset($_REQUEST[$captcha_var])) ? request_var($captcha_var, '') : ((isset($config[$captcha_var])) ? $config[$captcha_var] : ''); + $template->assign_var($template_var, $var); + } + + $template->assign_vars(array( + 'CAPTCHA_PREVIEW' => $this->get_demo_template($id), + 'CAPTCHA_NAME' => $this->get_class_name(), + 'U_ACTION' => $module->u_action, + )); + + } + } + + // not needed + function execute_demo() + { + } + + // not needed + function execute() + { + } + + function get_template() + { + global $config, $user, $template; + + if ($this->is_solved()) + { + return false; + } + else + { + $explain = $user->lang(($this->type != CONFIRM_POST) ? 'CONFIRM_EXPLAIN' : 'POST_CONFIRM_EXPLAIN', '', ''); + + $template->assign_vars(array( + 'RECAPTCHA_SERVER' => $this->recaptcha_server, + 'RECAPTCHA_PUBKEY' => isset($config['recaptcha_pubkey']) ? $config['recaptcha_pubkey'] : '', + 'RECAPTCHA_ERRORGET' => '', + 'S_RECAPTCHA_AVAILABLE' => $this->is_available(), + 'S_CONFIRM_CODE' => true, + 'S_TYPE' => $this->type, + 'L_CONFIRM_EXPLAIN' => $explain, + )); + + return 'captcha_recaptcha.html'; + } + } + + function get_demo_template($id) + { + return $this->get_template(); + } + + function get_hidden_fields() + { + $hidden_fields = array(); + + // this is required for posting.php - otherwise we would forget about the captcha being already solved + if ($this->solved) + { + $hidden_fields['confirm_code'] = $this->code; + } + $hidden_fields['confirm_id'] = $this->confirm_id; + return $hidden_fields; + } + + function uninstall() + { + $this->garbage_collect(0); + } + + function install() + { + return; + } + + function validate() + { + if (!parent::validate()) + { + return false; + } + else + { + return $this->recaptcha_check_answer(); + } + } + +// Code from here on is based on recaptchalib.php +/* + * This is a PHP library that handles calling reCAPTCHA. + * - Documentation and latest version + * http://recaptcha.net/plugins/php/ + * - Get a reCAPTCHA API Key + * http://recaptcha.net/api/getkey + * - Discussion group + * http://groups.google.com/group/recaptcha + * + * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net + * AUTHORS: + * Mike Crawford + * Ben Maurer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + /** + * Submits an HTTP POST to a reCAPTCHA server + * @param string $host + * @param string $path + * @param array $data + * @param int port + * @return array response + */ + function _recaptcha_http_post($host, $path, $data, $port = 80) + { + $req = $this->_recaptcha_qsencode ($data); + + $http_request = "POST $path HTTP/1.0\r\n"; + $http_request .= "Host: $host\r\n"; + $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n"; + $http_request .= "Content-Length: " . strlen($req) . "\r\n"; + $http_request .= "User-Agent: reCAPTCHA/PHP/phpBB\r\n"; + $http_request .= "\r\n"; + $http_request .= $req; + + $response = ''; + if (false == ($fs = @fsockopen($host, $port, $errno, $errstr, 10))) + { + trigger_error('Could not open socket', E_USER_ERROR); + } + + fwrite($fs, $http_request); + + while (!feof($fs)) + { + // One TCP-IP packet + $response .= fgets($fs, 1160); + } + fclose($fs); + $response = explode("\r\n\r\n", $response, 2); + + return $response; + } + + /** + * Calls an HTTP POST function to verify if the user's guess was correct + * @param array $extra_params an array of extra variables to post to the server + * @return ReCaptchaResponse + */ + function recaptcha_check_answer($extra_params = array()) + { + global $config, $user; + + //discard spam submissions + if ($this->challenge == null || strlen($this->challenge) == 0 || $this->response == null || strlen($this->response) == 0) + { + return $user->lang['RECAPTCHA_INCORRECT']; + } + + $response = $this->_recaptcha_http_post($this->recaptcha_verify_server, '/verify', + array( + 'privatekey' => $config['recaptcha_privkey'], + 'remoteip' => $user->ip, + 'challenge' => $this->challenge, + 'response' => $this->response + ) + $extra_params + ); + + $answers = explode("\n", $response[1]); + + if (trim($answers[0]) === 'true') + { + $this->solved = true; + return false; + } + else + { + if ($answers[1] === 'incorrect-captcha-sol') + { + return $user->lang['RECAPTCHA_INCORRECT']; + } + } + } + + /** + * Encodes the given data into a query string format + * @param $data - array of string elements to be encoded + * @return string - encoded request + */ + function _recaptcha_qsencode($data) + { + $req = ''; + foreach ($data as $key => $value) + { + $req .= $key . '=' . urlencode(stripslashes($value)) . '&'; + } + + // Cut the last '&' + $req = substr($req, 0, strlen($req) - 1); + return $req; + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php index 4cb21bc637..a526b9bf71 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.5'); +define('PHPBB_VERSION', '3.0.6-RC1'); // QA-related // define('PHPBB_QA', 1); @@ -91,6 +91,11 @@ define('FORUM_FLAG_PRUNE_ANNOUNCE', 4); define('FORUM_FLAG_PRUNE_STICKY', 8); define('FORUM_FLAG_ACTIVE_TOPICS', 16); define('FORUM_FLAG_POST_REVIEW', 32); +define('FORUM_FLAG_QUICK_REPLY', 64); + +// Forum Options... sequential order. Modifications should begin at number 10 (number 29 is maximum) +define('FORUM_OPTION_FEED_NEWS', 1); +define('FORUM_OPTION_FEED_EXCLUDE', 2); // Optional text flags define('OPTION_FLAG_BBCODE', 1); @@ -160,6 +165,9 @@ define('BBCODE_UID_LEN', 8); // Number of core BBCodes define('NUM_CORE_BBCODES', 12); +// Smiley hard limit +define('SMILEY_LIMIT', 1000); + // Magic url types define('MAGIC_URL_EMAIL', 1); define('MAGIC_URL_FULL', 2); diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index bc6b027b1f..ddc633c6d1 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -347,6 +347,11 @@ class phpbb_db_tools // holds the DDL for a column $columns = $statements = array(); + if ($this->sql_table_exists($table_name)) + { + return $this->_sql_run_sql($statements); + } + // Begin transaction $statements[] = 'begin'; @@ -580,6 +585,14 @@ class phpbb_db_tools } $statements = array(); + $sqlite = false; + + // For SQLite we need to perform the schema changes in a much more different way + if ($this->db->sql_layer == 'sqlite' && $this->return_statements) + { + $sqlite_data = array(); + $sqlite = true; + } // Change columns? if (!empty($schema_changes['change_columns'])) @@ -589,16 +602,27 @@ class phpbb_db_tools foreach ($columns as $column_name => $column_data) { // If the column exists we change it, else we add it ;) - if ($this->sql_column_exists($table, $column_name)) + if ($column_exists = $this->sql_column_exists($table, $column_name)) { - $result = $this->sql_column_change($table, $column_name, $column_data); + $result = $this->sql_column_change($table, $column_name, $column_data, true); } else { - $result = $this->sql_column_add($table, $column_name, $column_data); + $result = $this->sql_column_add($table, $column_name, $column_data, true); } - if ($this->return_statements) + if ($sqlite) + { + if ($column_exists) + { + $sqlite_data[$table]['change_columns'][] = $result; + } + else + { + $sqlite_data[$table]['add_columns'][] = $result; + } + } + else if ($this->return_statements) { $statements = array_merge($statements, $result); } @@ -614,16 +638,27 @@ class phpbb_db_tools foreach ($columns as $column_name => $column_data) { // Only add the column if it does not exist yet, else change it (to be consistent) - if ($this->sql_column_exists($table, $column_name)) + if ($column_exists = $this->sql_column_exists($table, $column_name)) { - $result = $this->sql_column_change($table, $column_name, $column_data); + $result = $this->sql_column_change($table, $column_name, $column_data, true); } else { - $result = $this->sql_column_add($table, $column_name, $column_data); + $result = $this->sql_column_add($table, $column_name, $column_data, true); } - if ($this->return_statements) + if ($sqlite) + { + if ($column_exists) + { + $sqlite_data[$table]['change_columns'][] = $result; + } + else + { + $sqlite_data[$table]['add_columns'][] = $result; + } + } + else if ($this->return_statements) { $statements = array_merge($statements, $result); } @@ -658,9 +693,13 @@ class phpbb_db_tools // Only remove the column if it exists... if ($this->sql_column_exists($table, $column)) { - $result = $this->sql_column_remove($table, $column); + $result = $this->sql_column_remove($table, $column, true); - if ($this->return_statements) + if ($sqlite) + { + $sqlite_data[$table]['drop_columns'][] = $result; + } + else if ($this->return_statements) { $statements = array_merge($statements, $result); } @@ -674,9 +713,13 @@ class phpbb_db_tools { foreach ($schema_changes['add_primary_keys'] as $table => $columns) { - $result = $this->sql_create_primary_key($table, $columns); + $result = $this->sql_create_primary_key($table, $columns, true); - if ($this->return_statements) + if ($sqlite) + { + $sqlite_data[$table]['primary_key'] = $result; + } + else if ($this->return_statements) { $statements = array_merge($statements, $result); } @@ -717,6 +760,147 @@ class phpbb_db_tools } } + if ($sqlite) + { + foreach ($sqlite_data as $table_name => $sql_schema_changes) + { + // Create temporary table with original data + $statements[] = 'begin'; + + $sql = "SELECT sql + FROM sqlite_master + WHERE type = 'table' + AND name = '{$table_name}' + ORDER BY type DESC, name;"; + $result = $this->db->sql_query($sql); + + if (!$result) + { + continue; + } + + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + // Create a backup table and populate it, destroy the existing one + $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); + $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; + $statements[] = 'DROP TABLE ' . $table_name; + + // Get the columns... + preg_match('#\((.*)\)#s', $row['sql'], $matches); + + $plain_table_cols = trim($matches[1]); + $new_table_cols = preg_split('/,(?![\s\w]+\))/m', $plain_table_cols); + $column_list = array(); + + foreach ($new_table_cols as $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + if ($entities[0] == 'PRIMARY') + { + continue; + } + $column_list[] = $entities[0]; + } + + // note down the primary key notation because sqlite only supports adding it to the end for the new table + $primary_key = false; + $_new_cols = array(); + + foreach ($new_table_cols as $key => $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + if ($entities[0] == 'PRIMARY') + { + $primary_key = $declaration; + continue; + } + $_new_cols[] = $declaration; + } + + $new_table_cols = $_new_cols; + + // First of all... change columns + if (!empty($sql_schema_changes['change_columns'])) + { + foreach ($sql_schema_changes['change_columns'] as $column_sql) + { + foreach ($new_table_cols as $key => $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + if (strpos($column_sql, $entities[0] . ' ') === 0) + { + $new_table_cols[$key] = $column_sql; + } + } + } + } + + if (!empty($sql_schema_changes['add_columns'])) + { + foreach ($sql_schema_changes['add_columns'] as $column_sql) + { + $new_table_cols[] = $column_sql; + } + } + + // Now drop them... + if (!empty($sql_schema_changes['drop_columns'])) + { + foreach ($sql_schema_changes['drop_columns'] as $column_name) + { + // Remove from column list... + $new_column_list = array(); + foreach ($column_list as $key => $value) + { + if ($value === $column_name) + { + continue; + } + + $new_column_list[] = $value; + } + + $column_list = $new_column_list; + + // Remove from table... + $_new_cols = array(); + foreach ($new_table_cols as $key => $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + if (strpos($column_name . ' ', $entities[0] . ' ') === 0) + { + continue; + } + $_new_cols[] = $declaration; + } + $new_table_cols = $_new_cols; + } + } + + // Primary key... + if (!empty($sql_schema_changes['primary_key'])) + { + $new_table_cols[] = 'PRIMARY KEY (' . implode(', ', $sql_schema_changes['primary_key']) . ')'; + } + // Add a new one or the old primary key + else if ($primary_key !== false) + { + $new_table_cols[] = $primary_key; + } + + $columns = implode(',', $column_list); + + // create a new table and fill it up. destroy the temp one + $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $new_table_cols) . ');'; + $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; + $statements[] = 'DROP TABLE ' . $table_name . '_temp'; + + $statements[] = 'commit'; + } + } + if ($this->return_statements) { return $statements; @@ -801,7 +985,7 @@ class phpbb_db_tools case 'oracle': $sql = "SELECT column_name FROM user_tab_columns - WHERE table_name = '{$table}'"; + WHERE LOWER(table_name) = '" . strtolower($table) . "'"; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { @@ -819,7 +1003,7 @@ class phpbb_db_tools case 'firebird': $sql = "SELECT RDB\$FIELD_NAME as FNAME FROM RDB\$RELATION_FIELDS - WHERE RDB\$RELATION_NAME = '{$table}'"; + WHERE RDB\$RELATION_NAME = '" . strtoupper($table) . "'"; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { @@ -972,10 +1156,12 @@ class phpbb_db_tools { case 'firebird': $sql .= " {$column_type} "; + $return_array['column_type_sql_type'] = " {$column_type} "; if (!is_null($column_data[1])) { $sql .= 'DEFAULT ' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ' '; + $return_array['column_type_sql_default'] = ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ' '; } $sql .= 'NOT NULL'; @@ -1129,7 +1315,7 @@ class phpbb_db_tools /** * Add new column */ - function sql_column_add($table_name, $column_name, $column_data) + function sql_column_add($table_name, $column_name, $column_data, $inline = false) { $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); $statements = array(); @@ -1158,6 +1344,12 @@ class phpbb_db_tools break; case 'sqlite': + + if ($inline && $this->return_statements) + { + return $column_name . ' ' . $column_data['column_type_sql']; + } + if (version_compare(sqlite_libversion(), '3.0') == -1) { $sql = "SELECT sql @@ -1222,7 +1414,7 @@ class phpbb_db_tools /** * Drop column */ - function sql_column_remove($table_name, $column_name) + function sql_column_remove($table_name, $column_name, $inline = false) { $statements = array(); @@ -1250,6 +1442,12 @@ class phpbb_db_tools break; case 'sqlite': + + if ($inline && $this->return_statements) + { + return $column_name; + } + if (version_compare(sqlite_libversion(), '3.0') == -1) { $sql = "SELECT sql @@ -1292,7 +1490,7 @@ class phpbb_db_tools $columns = implode(',', $column_list); - $new_table_cols = $new_table_cols = preg_replace('/' . $column_name . '[^,]+(?:,|$)/m', '', $new_table_cols); + $new_table_cols = preg_replace('/' . $column_name . '[^,]+(?:,|$)/m', '', $new_table_cols); // create a new table and fill it up. destroy the temp one $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');'; @@ -1347,6 +1545,11 @@ class phpbb_db_tools { $statements = array(); + if (!$this->sql_table_exists($table_name)) + { + return $this->_sql_run_sql($statements); + } + // the most basic operation, get rid of the table $statements[] = 'DROP TABLE ' . $table_name; @@ -1405,7 +1608,7 @@ class phpbb_db_tools /** * Add primary key */ - function sql_create_primary_key($table_name, $column) + function sql_create_primary_key($table_name, $column, $inline = false) { $statements = array(); @@ -1432,6 +1635,12 @@ class phpbb_db_tools break; case 'sqlite': + + if ($inline && $this->return_statements) + { + return $column; + } + $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' @@ -1639,7 +1848,7 @@ class phpbb_db_tools /** * Change column type (not name!) */ - function sql_column_change($table_name, $column_name, $column_data) + function sql_column_change($table_name, $column_name, $column_data, $inline = false) { $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); $statements = array(); @@ -1648,7 +1857,15 @@ class phpbb_db_tools { case 'firebird': // Change type... - $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql']; + if (!empty($column_data['column_type_sql_default'])) + { + $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql_type']; + $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" SET DEFAULT ' . ' ' . $column_data['column_type_sql_default']; + } + else + { + $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql']; + } break; case 'mssql': @@ -1729,6 +1946,11 @@ class phpbb_db_tools case 'sqlite': + if ($inline && $this->return_statements) + { + return $column_name . ' ' . $column_data['column_type_sql']; + } + $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php index b530a572da..a962696bb8 100644 --- a/phpBB/includes/db/dbal.php +++ b/phpBB/includes/db/dbal.php @@ -235,8 +235,8 @@ class dbal */ function sql_like_expression($expression) { - $expression = str_replace(array('_', '%'), array("\_", "\%"), $expression); - $expression = str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); + $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression); + $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression); return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\''); } @@ -411,6 +411,24 @@ class dbal } } + /** + * Run binary AND 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 AND 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_and($column_name, $bit, $compare = '') + { + if (method_exists($this, '_sql_bit_and')) + { + return $this->_sql_bit_and($column_name, $bit, $compare); + } + + return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : ''); + } + /** * Run more than one insert statement. * @@ -435,8 +453,7 @@ class dbal // If by accident the sql array is only one-dimensional we build a normal insert statement if (!is_array($_sql_ary)) { - $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary)); - return true; + return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary)); } $values = array(); @@ -447,7 +464,7 @@ class dbal $ary[] = '(' . implode(', ', $values) . ')'; } - $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary)); + return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary)); } else { @@ -458,7 +475,12 @@ class dbal return false; } - $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); + $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary)); + + if (!$result) + { + return false; + } } } diff --git a/phpBB/includes/db/firebird.php b/phpBB/includes/db/firebird.php index 3b31942a8b..fb1ef44c55 100644 --- a/phpBB/includes/db/firebird.php +++ b/phpBB/includes/db/firebird.php @@ -20,7 +20,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); /** * Firebird/Interbase Database Abstraction Layer -* Minimum Requirement is Firebird 2.0 +* Minimum Requirement is Firebird 2.1 * @package dbal */ class dbal_firebird extends dbal @@ -72,7 +72,7 @@ class dbal_firebird extends dbal return @ibase_server_info($this->service_handle, IBASE_SVC_SERVER_VERSION); } - return ($raw) ? '2.0' : 'Firebird/Interbase'; + return ($raw) ? '2.1' : 'Firebird/Interbase'; } /** @@ -446,6 +446,11 @@ class dbal_firebird extends dbal return $data; } + function _sql_bit_and($column_name, $bit, $compare = '') + { + return 'BIN_AND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); + } + /** * return sql error array * @access private diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php index a140c4b676..10f4a1a7a7 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/oracle.php @@ -568,6 +568,11 @@ class dbal_oracle extends dbal return $data; } + function _sql_bit_and($column_name, $bit, $compare = '') + { + return 'BITAND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : ''); + } + /** * return sql error array * @access private diff --git a/phpBB/includes/diff/engine.php b/phpBB/includes/diff/engine.php index eb0dcce395..e9f0e41b75 100644 --- a/phpBB/includes/diff/engine.php +++ b/phpBB/includes/diff/engine.php @@ -49,6 +49,8 @@ if (!defined('IN_PHPBB')) */ class diff_engine { + var $skip_whitespace_changes = true; + function diff(&$from_lines, &$to_lines, $preserve_cr = true) { // Remove empty lines... @@ -176,6 +178,20 @@ class diff_engine $add[] = $to_lines[$yi++]; } + // Here we are a bit naughty. Naughty Boy... Naughty Boy... + // We check if delete and add is filled and only consist of one item + if ($this->skip_whitespace_changes && sizeof($delete) == 1 && sizeof($add) == 1) + { + // Now we simply trim the string and see if the lines are identical + // If they are identical we do not need to take them into account for the merge (less conflicts in phpBB) + if (trim($delete[0]) === trim($add[0])) + { + // This line ensures the line found here is correctly copied later (remember: we naughty boys like loops) + $xi--; $yi--; $this->xchanged[$xi] = $this->ychanged[$yi] = false; + $delete = $add = array(); + } + } + if ($delete && $add) { $edits[] = new diff_op_change($delete, $add); diff --git a/phpBB/includes/diff/renderer.php b/phpBB/includes/diff/renderer.php index 02fb6ccc37..5cb1b6ada9 100644 --- a/phpBB/includes/diff/renderer.php +++ b/phpBB/includes/diff/renderer.php @@ -536,7 +536,7 @@ class diff_renderer_raw extends diff_renderer */ function get_diff_content($diff) { - return ''; + return ''; } function _block_header($xbeg, $xlen, $ybeg, $ylen) diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index 476565452c..092a5d5d86 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -71,12 +71,13 @@ function request_var($var_name, $default, $multibyte = false, $cookie = false) $_REQUEST[$var_name] = isset($_POST[$var_name]) ? $_POST[$var_name] : $_GET[$var_name]; } - if (!isset($_REQUEST[$var_name]) || (is_array($_REQUEST[$var_name]) && !is_array($default)) || (is_array($default) && !is_array($_REQUEST[$var_name]))) + $super_global = ($cookie) ? '_COOKIE' : '_REQUEST'; + if (!isset($GLOBALS[$super_global][$var_name]) || is_array($GLOBALS[$super_global][$var_name]) != is_array($default)) { return (is_array($default)) ? array() : $default; } - $var = $_REQUEST[$var_name]; + $var = $GLOBALS[$super_global][$var_name]; if (!is_array($default)) { $type = gettype($default); @@ -174,7 +175,7 @@ function set_config_count($config_name, $increment, $is_dynamic = false) switch ($db->sql_layer) { case 'firebird': - $sql_update = 'CAST(CAST(config_value as integer) + ' . (int) $increment . ' as CHAR)'; + $sql_update = 'CAST(CAST(config_value as integer) + ' . (int) $increment . ' as VARCHAR(255))'; break; case 'postgres': @@ -231,27 +232,82 @@ function unique_id($extra = 'c') /** * Return formatted string for filesizes +* +* @param int $value filesize in bytes +* @param bool $string_only true if language string should be returned +* @param array $allowed_units only allow these units (data array indexes) +* +* @return mixed data array if $string_only is false +* @author bantu */ -function get_formatted_filesize($bytes, $add_size_lang = true) +function get_formatted_filesize($value, $string_only = true, $allowed_units = false) { global $user; - if ($bytes >= pow(2, 30)) + $available_units = array( + 'gb' => array( + 'min' => 1073741824, // pow(2, 30) + 'index' => 3, + 'si_unit' => 'GB', + 'iec_unit' => 'GIB', + ), + 'mb' => array( + 'min' => 1048576, // pow(2, 20) + 'index' => 2, + 'si_unit' => 'MB', + 'iec_unit' => 'MIB', + ), + 'kb' => array( + 'min' => 1024, // pow(2, 10) + 'index' => 1, + 'si_unit' => 'KB', + 'iec_unit' => 'KIB', + ), + 'b' => array( + 'min' => 0, + 'index' => 0, + 'si_unit' => 'BYTES', // Language index + 'iec_unit' => 'BYTES', // Language index + ), + ); + + foreach ($available_units as $si_identifier => $unit_info) { - return ($add_size_lang) ? round($bytes / 1024 / 1024 / 1024, 2) . ' ' . $user->lang['GIB'] : round($bytes / 1024 / 1024 / 1024, 2); + if (!empty($allowed_units) && $si_identifier != 'b' && !in_array($si_identifier, $allowed_units)) + { + continue; + } + + if ($value >= $unit_info['min']) + { + $unit_info['si_identifier'] = $si_identifier; + + break; + } + } + unset($available_units); + + for ($i = 0; $i < $unit_info['index']; $i++) + { + $value /= 1024; + } + $value = round($value, 2); + + // Lookup units in language dictionary + $unit_info['si_unit'] = (isset($user->lang[$unit_info['si_unit']])) ? $user->lang[$unit_info['si_unit']] : $unit_info['si_unit']; + $unit_info['iec_unit'] = (isset($user->lang[$unit_info['iec_unit']])) ? $user->lang[$unit_info['iec_unit']] : $unit_info['iec_unit']; + + // Default to IEC + $unit_info['unit'] = $unit_info['iec_unit']; + + if (!$string_only) + { + $unit_info['value'] = $value; + + return $unit_info; } - if ($bytes >= pow(2, 20)) - { - return ($add_size_lang) ? round($bytes / 1024 / 1024, 2) . ' ' . $user->lang['MIB'] : round($bytes / 1024 / 1024, 2); - } - - if ($bytes >= pow(2, 10)) - { - return ($add_size_lang) ? round($bytes / 1024, 2) . ' ' . $user->lang['KIB'] : round($bytes / 1024, 2); - } - - return ($add_size_lang) ? ($bytes) . ' ' . $user->lang['BYTES'] : ($bytes); + return $value . ' ' . $unit_info['unit']; } /** @@ -495,6 +551,18 @@ function _hash_crypt_private($password, $setting, &$itoa64) return $output; } +/** +* Hashes an email address to a big integer +* +* @param string $email Email address +* +* @return string Big Integer +*/ +function phpbb_email_hash($email) +{ + return crc32(strtolower($email)) . strlen($email); +} + /** * Global function for chmodding directories and files for internal use * @@ -669,6 +737,67 @@ function phpbb_chmod($filename, $perms = CHMOD_READ) return $result; } +/** +* Test if a file/directory is writable +* +* This function calls the native is_writable() when not running under +* Windows and it is not disabled. +* +* @param string $file Path to perform write test on +* @return bool True when the path is writable, otherwise false. +*/ +function phpbb_is_writable($file) +{ + if (strtolower(substr(PHP_OS, 0, 3)) === 'win' || !function_exists('is_writable')) + { + if (file_exists($file)) + { + // Canonicalise path to absolute path + $file = phpbb_realpath($file); + + if (is_dir($file)) + { + // Test directory by creating a file inside the directory + $result = @tempnam($file, 'i_w'); + + if (is_string($result) && file_exists($result)) + { + unlink($result); + + // Ensure the file is actually in the directory (returned realpathed) + return (strpos($result, $file) === 0) ? true : false; + } + } + else + { + $handle = @fopen($file, 'r+'); + + if (is_resource($handle)) + { + fclose($handle); + return true; + } + } + } + else + { + // file does not exist test if we can write to the directory + $dir = dirname($file); + + if (file_exists($dir) && is_dir($dir) && phpbb_is_writable($dir)) + { + return true; + } + } + + return false; + } + else + { + return is_writable($file); + } +} + // Compatibility functions if (!function_exists('array_combine')) @@ -1047,7 +1176,7 @@ function tz_select($default = '', $truncate = false) if (is_numeric($offset)) { $selected = ($offset == $default) ? ' selected="selected"' : ''; - $tz_select .= ''; + $tz_select .= ''; } } @@ -1110,7 +1239,7 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $ } // Add 0 to forums array to mark global announcements correctly - $forum_id[] = 0; + // $forum_id[] = 0; if ($config['load_db_lastread'] && $user->data['is_registered']) { @@ -1527,6 +1656,135 @@ function get_complete_topic_tracking($forum_id, $topic_ids, $global_announce_lis return $last_read; } +/** +* Get list of unread topics +* +* @param int $user_id User ID (or false for current user) +* @param string $sql_extra Extra WHERE SQL statement +* @param string $sql_sort ORDER BY SQL sorting statement +* @param string $sql_limit Limits the size of unread topics list, 0 for unlimited query +* +* @return array[int][int] Topic ids as keys, mark_time of topic as value +*/ +function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $sql_limit = 1001) +{ + global $config, $db, $user; + + $user_id = ($user_id === false) ? (int) $user->data['user_id'] : (int) $user_id; + + // Data array we're going to return + $unread_topics = array(); + + if (empty($sql_sort)) + { + $sql_sort = 'ORDER BY t.topic_last_post_time DESC'; + } + + if ($config['load_db_lastread'] && $user->data['is_registered']) + { + // Get list of the unread topics + $last_mark = $user->data['user_lastmark']; + + $sql_array = array( + 'SELECT' => 't.topic_id, t.topic_last_post_time, tt.mark_time as topic_mark_time, ft.mark_time as forum_mark_time', + + 'FROM' => array(TOPICS_TABLE => 't'), + + 'LEFT_JOIN' => array( + array( + 'FROM' => array(TOPICS_TRACK_TABLE => 'tt'), + 'ON' => "tt.user_id = $user_id AND t.topic_id = tt.topic_id AND tt.mark_time > $last_mark", + ), + array( + 'FROM' => array(FORUMS_TRACK_TABLE => 'ft'), + 'ON' => "ft.user_id = $user_id AND t.forum_id = ft.forum_id AND ft.mark_time > $last_mark", + ), + ), + + 'WHERE' => " + ( + (tt.mark_time IS NOT NULL AND t.topic_last_post_time > tt.mark_time) OR + (tt.mark_time IS NULL AND ft.mark_time IS NOT NULL AND t.topic_last_post_time > ft.mark_time) OR + ( + ((tt.mark_time IS NULL AND ft.mark_time IS NULL) OR (tt.mark_time < $last_mark AND ft.mark_time < $last_mark)) + AND t.topic_last_post_time > $last_mark + ) + ) + $sql_extra + $sql_sort", + ); + + $sql = $db->sql_build_query('SELECT', $sql_array); + $result = $db->sql_query_limit($sql, $sql_limit); + + while ($row = $db->sql_fetchrow($result)) + { + $topic_id = (int) $row['topic_id']; + $unread_topics[$topic_id] = ($row['topic_mark_time']) ? (int) $row['topic_mark_time'] : (($row['forum_mark_time']) ? (int) $row['forum_mark_time'] : $last_mark); + } + $db->sql_freeresult($result); + } + else if ($config['load_anon_lastread'] || $user->data['is_registered']) + { + global $tracking_topics; + + if (empty($tracking_topics)) + { + $tracking_topics = request_var($config['cookie_name'] . '_track', '', false, true); + $tracking_topics = ($tracking_topics) ? tracking_unserialize($tracking_topics) : array(); + } + + if (!$user->data['is_registered']) + { + $user_lastmark = (isset($tracking_topics['l'])) ? base_convert($tracking_topics['l'], 36, 10) + $config['board_startdate'] : 0; + } + else + { + $user_lastmark = (int) $user->data['user_lastmark']; + } + + $sql = 'SELECT t.topic_id, t.forum_id, t.topic_last_post_time + FROM ' . TOPICS_TABLE . ' t + WHERE t.topic_last_post_time > ' . $user_lastmark . " + $sql_extra + $sql_sort"; + $result = $db->sql_query_limit($sql, $sql_limit); + + while ($row = $db->sql_fetchrow($result)) + { + $forum_id = (int) $row['forum_id']; + $topic_id = (int) $row['topic_id']; + $topic_id36 = base_convert($topic_id, 10, 36); + + if (isset($tracking_topics['t'][$topic_id36])) + { + $last_read = base_convert($tracking_topics['t'][$topic_id36], 36, 10) + $config['board_startdate']; + + if ($row['topic_last_post_time'] > $last_read) + { + $unread_topics[$topic_id] = $last_read; + } + } + else if (isset($tracking_topics['f'][$forum_id])) + { + $mark_time = base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']; + + if ($row['topic_last_post_time'] > $mark_time) + { + $unread_topics[$topic_id] = $mark_time; + } + } + else + { + $unread_topics[$topic_id] = $user_lastmark; + } + } + $db->sql_freeresult($result); + } + + return $unread_topics; +} + /** * Check for read forums and update topic tracking info accordingly * @@ -1777,7 +2035,7 @@ function generate_pagination($base_url, $num_items, $per_page, $start_item, $add } $on_page = floor($start_item / $per_page) + 1; - $url_delim = (strpos($base_url, '?') === false) ? '?' : '&'; + $url_delim = (strpos($base_url, '?') === false) ? '?' : ((strpos($base_url, '?') === strlen($base_url) - 1) ? '' : '&'); $page_string = ($on_page == 1) ? '1' : '1'; @@ -2056,7 +2314,7 @@ function redirect($url, $return = false, $disable_cd_check = false) $url = str_replace('&', '&', $url); // Determine which type of redirect we need to handle... - $url_parts = parse_url($url); + $url_parts = @parse_url($url); if ($url_parts === false) { @@ -2200,17 +2458,12 @@ function reapply_sid($url) } // Remove previously added sid - if (strpos($url, '?sid=') !== false) + if (strpos($url, 'sid=') !== false) { - $url = preg_replace('/(\?)sid=[a-z0-9]+(&|&)?/', '\1', $url); - } - else if (strpos($url, '&sid=') !== false) - { - $url = preg_replace('/&sid=[a-z0-9]+(&)?/', '\1', $url); - } - else if (strpos($url, '&sid=') !== false) - { - $url = preg_replace('/&sid=[a-z0-9]+(&)?/', '\1', $url); + // All kind of links + $url = preg_replace('/(\?)?(&|&)?sid=[a-z0-9]+/', '', $url); + // if the sid was the first param, make the old second as first ones + $url = preg_replace("/$phpEx(&|&)+?/", "$phpEx?", $url); } return append_sid($url); @@ -2274,6 +2527,18 @@ function build_url($strip_vars = false) $redirect .= ($query) ? '?' . $query : ''; } + // We need to be cautious here. + // On some situations, the redirect path is an absolute URL, sometimes a relative path + // For a relative path, let's prefix it with $phpbb_root_path to point to the correct location, + // else we use the URL directly. + $url_parts = @parse_url($redirect); + + // URL + if ($url_parts !== false && !empty($url_parts['scheme']) && !empty($url_parts['host'])) + { + return str_replace('&', '&', $redirect); + } + return $phpbb_root_path . str_replace('&', '&', $redirect); } @@ -2435,7 +2700,7 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo if ($check && $confirm) { - $user_id = request_var('user_id', 0); + $user_id = request_var('confirm_uid', 0); $session_id = request_var('sess', ''); $confirm_key = request_var('confirm_key', ''); @@ -2457,10 +2722,10 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo } $s_hidden_fields = build_hidden_fields(array( - 'user_id' => $user->data['user_id'], - 'sess' => $user->session_id, - 'sid' => $user->session_id) - ); + 'confirm_uid' => $user->data['user_id'], + 'sess' => $user->session_id, + 'sid' => $user->session_id, + )); // generate activation key $confirm_key = gen_rand_string(10); @@ -2471,7 +2736,7 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo } else { - page_header((!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title]); + page_header(((!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title]), false); } $template->set_filenames(array( @@ -2520,6 +2785,11 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa { global $db, $user, $template, $auth, $phpEx, $phpbb_root_path, $config; + if (!class_exists('phpbb_captcha_factory')) + { + include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); + } + $err = ''; // Make sure user->setup() has been called @@ -2630,38 +2900,15 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa { case LOGIN_ERROR_ATTEMPTS: - // Show confirm image - $sql = 'DELETE FROM ' . CONFIRM_TABLE . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_LOGIN; - $db->sql_query($sql); - - // Generate code - $code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); - $confirm_id = md5(unique_id($user->ip)); - $seed = hexdec(substr(unique_id(), 4, 10)); - - // compute $seed % 0x7fffffff - $seed -= 0x7fffffff * floor($seed / 0x7fffffff); - - $sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'confirm_id' => (string) $confirm_id, - 'session_id' => (string) $user->session_id, - 'confirm_type' => (int) CONFIRM_LOGIN, - 'code' => (string) $code, - 'seed' => (int) $seed) - ); - $db->sql_query($sql); + $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha->init(CONFIRM_LOGIN); + // $captcha->reset(); $template->assign_vars(array( - 'S_CONFIRM_CODE' => true, - 'CONFIRM_ID' => $confirm_id, - 'CONFIRM_IMAGE' => '', - 'L_LOGIN_CONFIRM_EXPLAIN' => sprintf($user->lang['LOGIN_CONFIRM_EXPLAIN'], '', ''), + 'CAPTCHA_TEMPLATE' => $captcha->get_template(), )); $err = $user->lang[$result['error_msg']]; - break; case LOGIN_ERROR_PASSWORD_CONVERT: @@ -2688,28 +2935,18 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa } } - if (!$redirect) - { - // We just use what the session code determined... - // If we are not within the admin directory we use the page dir... - $redirect = ''; - - if (!$admin) - { - $redirect .= ($user->page['page_dir']) ? $user->page['page_dir'] . '/' : ''; - } - - $redirect .= $user->page['page_name'] . (($user->page['query_string']) ? '?' . htmlspecialchars($user->page['query_string']) : ''); - } - // Assign credential for username/password pair $credential = ($admin) ? md5(unique_id()) : false; $s_hidden_fields = array( - 'redirect' => $redirect, 'sid' => $user->session_id, ); + if ($redirect) + { + $s_hidden_fields['redirect'] = $redirect; + } + if ($admin) { $s_hidden_fields['credential'] = $credential; @@ -2722,12 +2959,11 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa 'LOGIN_EXPLAIN' => $l_explain, 'U_SEND_PASSWORD' => ($config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=sendpassword') : '', - 'U_RESEND_ACTIVATION' => ($config['require_activation'] != USER_ACTIVATION_NONE && $config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=resend_act') : '', + 'U_RESEND_ACTIVATION' => ($config['require_activation'] == USER_ACTIVATION_SELF && $config['email_enable']) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=resend_act') : '', 'U_TERMS_USE' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=terms'), 'U_PRIVACY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy'), 'S_DISPLAY_FULL_LOGIN' => ($s_display) ? true : false, - 'S_LOGIN_ACTION' => (!$admin) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login') : append_sid("index.$phpEx", false, true, $user->session_id), // Needs to stay index.$phpEx because we are within the admin directory 'S_HIDDEN_FIELDS' => $s_hidden_fields, 'S_ADMIN_AUTH' => $admin, @@ -2811,7 +3047,7 @@ function login_forum_box($forum_data) $template->assign_var('LOGIN_ERROR', $user->lang['WRONG_PASSWORD']); } - page_header($user->lang['LOGIN']); + page_header($user->lang['LOGIN'], false); $template->assign_vars(array( 'S_HIDDEN_FIELDS' => build_hidden_fields(array('f' => $forum_data['forum_id']))) @@ -2933,6 +3169,14 @@ function add_log() { global $db, $user; + // In phpBB 3.1.x i want to have logging in a class to be able to control it + // For now, we need a quite hakish approach to circumvent logging for some actions + // @todo implement cleanly + if (!empty($GLOBALS['skip_add_log'])) + { + return false; + } + $args = func_get_args(); $mode = array_shift($args); @@ -3200,7 +3444,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline) global $phpEx, $phpbb_root_path, $msg_title, $msg_long_text; // Do not display notices if we suppress them via @ - if (error_reporting() == 0) + if (error_reporting() == 0 && $errno != E_USER_ERROR && $errno != E_USER_WARNING && $errno != E_USER_NOTICE) { return; } @@ -3211,6 +3455,11 @@ function msg_handler($errno, $msg_text, $errfile, $errline) $msg_text = $msg_long_text; } + if (!defined('E_DEPRECATED')) + { + define('E_DEPRECATED', 8192); + } + switch ($errno) { case E_NOTICE: @@ -3243,8 +3492,13 @@ function msg_handler($errno, $msg_text, $errfile, $errline) // remove complete path to installation, with the risk of changing backslashes meant to be there $errfile = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $errfile); $msg_text = str_replace(array(phpbb_realpath($phpbb_root_path), '\\'), array('', '/'), $msg_text); - echo '[phpBB Debug] PHP Notice: in file ' . $errfile . ' on line ' . $errline . ': ' . $msg_text . '
    ' . "\n"; + + // we are writing an image - the user won't see the debug, so let's place it in the log + if (defined('IMAGE_OUTPUT') || defined('IN_CRON')) + { + add_log('critical', 'LOG_IMAGE_GENERATION_ERROR', $errfile, $errline, $msg_text); + } // echo '

    BACKTRACE
    ' . get_backtrace() . '
    ' . "\n"; } @@ -3279,6 +3533,17 @@ function msg_handler($errno, $msg_text, $errfile, $errline) } } + if (defined('DEBUG') || defined('IN_CRON') || defined('IMAGE_OUTPUT')) + { + // let's avoid loops + $db->sql_return_on_error(true); + add_log('critical', 'LOG_GENERAL_ERROR', $msg_title, $msg_text); + $db->sql_return_on_error(false); + } + + // Do not send 200 OK, but service unavailable on errors + header('HTTP/1.1 503 Service Unavailable'); + garbage_collection(); // Try to not call the adm page data... @@ -3357,7 +3622,7 @@ function msg_handler($errno, $msg_text, $errfile, $errline) } else { - page_header($msg_title); + page_header($msg_title, false); } } @@ -3386,6 +3651,11 @@ function msg_handler($errno, $msg_text, $errfile, $errline) exit_handler(); break; + + // PHP4 compatibility + case E_DEPRECATED: + return true; + break; } // If we notice an error not handled here we pass this back to PHP by returning false @@ -3395,16 +3665,17 @@ function msg_handler($errno, $msg_text, $errfile, $errline) /** * Queries the session table to get information about online guests -* @param int $forum_id Limits the search to the forum with this id +* @param int $item_id Limits the search to the item with this id +* @param string $item The name of the item which is stored in the session table as session_{$item}_id * @return int The number of active distinct guest sessions */ -function obtain_guest_count($forum_id = 0) +function obtain_guest_count($item_id = 0, $item = 'forum') { global $db, $config; - if ($forum_id) + if ($item_id) { - $reading_sql = ' AND s.session_forum_id = ' . (int) $forum_id; + $reading_sql = ' AND s.session_' . $item . '_id = ' . (int) $item_id; } else { @@ -3442,17 +3713,18 @@ function obtain_guest_count($forum_id = 0) /** * Queries the session table to get information about online users -* @param int $forum_id Limits the search to the forum with this id +* @param int $item_id Limits the search to the item with this id +* @param string $item The name of the item which is stored in the session table as session_{$item}_id * @return array An array containing the ids of online, hidden and visible users, as well as statistical info */ -function obtain_users_online($forum_id = 0) +function obtain_users_online($item_id = 0, $item = 'forum') { global $db, $config, $user; $reading_sql = ''; - if ($forum_id !== 0) + if ($item_id !== 0) { - $reading_sql = ' AND s.session_forum_id = ' . (int) $forum_id; + $reading_sql = ' AND s.session_' . $item . '_id = ' . (int) $item_id; } $online_users = array( @@ -3466,7 +3738,7 @@ function obtain_users_online($forum_id = 0) if ($config['load_online_guests']) { - $online_users['guests_online'] = obtain_guest_count($forum_id); + $online_users['guests_online'] = obtain_guest_count($item_id, $item); } // a little discrete magic to cache this for 30 seconds @@ -3505,14 +3777,17 @@ function obtain_users_online($forum_id = 0) /** * Uses the result of obtain_users_online to generate a localized, readable representation. * @param mixed $online_users result of obtain_users_online - array with user_id lists for total, hidden and visible users, and statistics -* @param int $forum_id Indicate that the data is limited to one forum and not global. +* @param int $item_id Indicate that the data is limited to one item and not global +* @param string $item The name of the item which is stored in the session table as session_{$item}_id * @return array An array containing the string for output to the template */ -function obtain_users_online_string($online_users, $forum_id = 0) +function obtain_users_online_string($online_users, $item_id = 0, $item = 'forum') { global $config, $db, $user, $auth; $user_online_link = $online_userlist = ''; + // Need caps version of $item for language-strings + $item_caps = strtoupper($item); if (sizeof($online_users['online_users'])) { @@ -3547,18 +3822,18 @@ function obtain_users_online_string($online_users, $forum_id = 0) $online_userlist = $user->lang['NO_ONLINE_USERS']; } - if ($forum_id === 0) + if ($item_id === 0) { $online_userlist = $user->lang['REGISTERED_USERS'] . ' ' . $online_userlist; } else if ($config['load_online_guests']) { - $l_online = ($online_users['guests_online'] === 1) ? $user->lang['BROWSING_FORUM_GUEST'] : $user->lang['BROWSING_FORUM_GUESTS']; + $l_online = ($online_users['guests_online'] === 1) ? $user->lang['BROWSING_' . $item_caps . '_GUEST'] : $user->lang['BROWSING_' . $item_caps . '_GUESTS']; $online_userlist = sprintf($l_online, $online_userlist, $online_users['guests_online']); } else { - $online_userlist = sprintf($user->lang['BROWSING_FORUM'], $online_userlist); + $online_userlist = sprintf($user->lang['BROWSING_' . $item_caps], $online_userlist); } // Build online listing $vars_online = array( @@ -3612,11 +3887,45 @@ function obtain_users_online_string($online_users, $forum_id = 0) ); } +/** +* Get option bitfield from custom data +* +* @param int $bit The bit/value to get +* @param int $data Current bitfield to check +* @return bool Returns true if value of constant is set in bitfield, else false +*/ +function phpbb_optionget($bit, $data) +{ + return ($data & 1 << (int) $bit) ? true : false; +} + +/** +* Set option bitfield +* +* @param int $bit The bit/value to set/unset +* @param bool $set True if option should be set, false if option should be unset. +* @param int $data Current bitfield to change +* +* @return int The new bitfield +*/ +function phpbb_optionset($bit, $set, $data) +{ + if ($set && !($data & 1 << $bit)) + { + $data += 1 << $bit; + } + else if (!$set && ($data & 1 << $bit)) + { + $data -= 1 << $bit; + } + + return $data; +} /** * Generate page header */ -function page_header($page_title = '', $display_online_list = true) +function page_header($page_title = '', $display_online_list = true, $item_id = 0, $item = 'forum') { global $db, $config, $template, $SID, $_SID, $user, $auth, $phpEx, $phpbb_root_path; @@ -3656,10 +3965,14 @@ function page_header($page_title = '', $display_online_list = true) if ($config['load_online'] && $config['load_online_time'] && $display_online_list) { - $f = request_var('f', 0); - $f = max($f, 0); - $online_users = obtain_users_online($f); - $user_online_strings = obtain_users_online_string($online_users, $f); + /** + * Load online data: + * For obtaining another session column use $item and $item_id in the function-parameter, whereby the column is session_{$item}_id. + */ + $item_id = max($item_id, 0); + + $online_users = obtain_users_online($item_id, $item); + $user_online_strings = obtain_users_online_string($online_users, $item_id, $item); $l_online_users = $user_online_strings['l_online_users']; $online_userlist = $user_online_strings['online_userlist']; @@ -3731,6 +4044,26 @@ function page_header($page_title = '', $display_online_list = true) $user_lang = substr($user_lang, 0, strpos($user_lang, '-x-')); } + $forum_id = request_var('f', 0); + $topic_id = request_var('t', 0); + + $s_feed_news = false; + + // Get option for news + if ($config['feed_enable']) + { + $sql = 'SELECT forum_id + FROM ' . FORUMS_TABLE . ' + WHERE ' . $db->sql_bit_and('forum_options', FORUM_OPTION_FEED_NEWS, '<> 0'); + $result = $db->sql_query_limit($sql, 1, 0, 600); + $s_feed_news = (int) $db->sql_fetchfield('forum_id'); + $db->sql_freeresult($result); + } + + // Determine board url - we may need it later + $board_url = generate_board_url() . '/'; + $web_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? $board_url : $phpbb_root_path; + // The following assigns all _common_ variables that may be used at any point in a template. $template->assign_vars(array( 'SITENAME' => $config['sitename'], @@ -3748,11 +4081,13 @@ function page_header($page_title = '', $display_online_list = true) 'S_USER_NEW_PRIVMSG' => $user->data['user_new_privmsg'], 'S_USER_UNREAD_PRIVMSG' => $user->data['user_unread_privmsg'], + 'S_USER_NEW' => $user->data['user_new'], 'SID' => $SID, '_SID' => $_SID, 'SESSION_ID' => $user->session_id, 'ROOT_PATH' => $phpbb_root_path, + 'BOARD_URL' => $board_url, 'L_LOGIN_LOGOUT' => $l_login_logout, 'L_INDEX' => $user->lang['FORUM_INDEX'], @@ -3774,10 +4109,14 @@ function page_header($page_title = '', $display_online_list = true) 'U_SEARCH_SELF' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=egosearch'), 'U_SEARCH_NEW' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=newposts'), 'U_SEARCH_UNANSWERED' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=unanswered'), + 'U_SEARCH_UNREAD' => append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=unreadposts'), 'U_SEARCH_ACTIVE_TOPICS'=> append_sid("{$phpbb_root_path}search.$phpEx", 'search_id=active_topics'), 'U_DELETE_COOKIES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=delete_cookies'), 'U_TEAM' => ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile')) ? '' : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=leaders'), + 'U_TERMS_USE' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=terms'), + 'U_PRIVACY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=privacy'), 'U_RESTORE_PERMISSIONS' => ($user->data['user_perm_from'] && $auth->acl_get('a_switchperm')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=restore_perm') : '', + 'U_FEED' => generate_board_url() . "/feed.$phpEx", 'S_USER_LOGGED_IN' => ($user->data['user_id'] != ANONYMOUS) ? true : false, 'S_AUTOLOGIN_ENABLED' => ($config['allow_autologin']) ? true : false, @@ -3799,22 +4138,44 @@ function page_header($page_title = '', $display_online_list = true) 'S_DISPLAY_MEMBERLIST' => (isset($auth)) ? $auth->acl_get('u_viewprofile') : 0, 'S_NEW_PM' => ($s_privmsg_new) ? 1 : 0, 'S_REGISTER_ENABLED' => ($config['require_activation'] != USER_ACTIVATION_DISABLE) ? true : false, + 'S_FORUM_ID' => $forum_id, + 'S_TOPIC_ID' => $topic_id, - 'T_THEME_PATH' => "{$phpbb_root_path}styles/" . $user->theme['theme_path'] . '/theme', - 'T_TEMPLATE_PATH' => "{$phpbb_root_path}styles/" . $user->theme['template_path'] . '/template', - 'T_SUPER_TEMPLATE_PATH' => (isset($user->theme['template_inherit_path']) && $user->theme['template_inherit_path']) ? "{$phpbb_root_path}styles/" . $user->theme['template_inherit_path'] . '/template' : "{$phpbb_root_path}styles/" . $user->theme['template_path'] . '/template', - 'T_IMAGESET_PATH' => "{$phpbb_root_path}styles/" . $user->theme['imageset_path'] . '/imageset', - 'T_IMAGESET_LANG_PATH' => "{$phpbb_root_path}styles/" . $user->theme['imageset_path'] . '/imageset/' . $user->data['user_lang'], - 'T_IMAGES_PATH' => "{$phpbb_root_path}images/", - 'T_SMILIES_PATH' => "{$phpbb_root_path}{$config['smilies_path']}/", - 'T_AVATAR_PATH' => "{$phpbb_root_path}{$config['avatar_path']}/", - 'T_AVATAR_GALLERY_PATH' => "{$phpbb_root_path}{$config['avatar_gallery_path']}/", - 'T_ICONS_PATH' => "{$phpbb_root_path}{$config['icons_path']}/", - 'T_RANKS_PATH' => "{$phpbb_root_path}{$config['ranks_path']}/", - 'T_UPLOAD_PATH' => "{$phpbb_root_path}{$config['upload_path']}/", - 'T_STYLESHEET_LINK' => (!$user->theme['theme_storedb']) ? "{$phpbb_root_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : "{$phpbb_root_path}style.$phpEx?sid=$user->session_id&id=" . $user->theme['style_id'] . '&lang=' . $user->data['user_lang'], + 'S_LOGIN_ACTION' => (!defined('ADMIN_START')) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login') . '&redirect=' . urlencode(str_replace('&', '&', build_url())) : append_sid("index.$phpEx", false, true, $user->session_id) . '&redirect=' . urlencode(str_replace('&', '&', build_url())), + + 'S_ENABLE_FEEDS' => ($config['feed_enable']) ? 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_NEWS' => ($s_feed_news) ? true : false, + + 'T_THEME_PATH' => "{$web_path}styles/" . $user->theme['theme_path'] . '/theme', + 'T_TEMPLATE_PATH' => "{$web_path}styles/" . $user->theme['template_path'] . '/template', + 'T_SUPER_TEMPLATE_PATH' => (isset($user->theme['template_inherit_path']) && $user->theme['template_inherit_path']) ? "{$web_path}styles/" . $user->theme['template_inherit_path'] . '/template' : "{$web_path}styles/" . $user->theme['template_path'] . '/template', + 'T_IMAGESET_PATH' => "{$web_path}styles/" . $user->theme['imageset_path'] . '/imageset', + 'T_IMAGESET_LANG_PATH' => "{$web_path}styles/" . $user->theme['imageset_path'] . '/imageset/' . $user->data['user_lang'], + 'T_IMAGES_PATH' => "{$web_path}images/", + 'T_SMILIES_PATH' => "{$web_path}{$config['smilies_path']}/", + 'T_AVATAR_PATH' => "{$web_path}{$config['avatar_path']}/", + 'T_AVATAR_GALLERY_PATH' => "{$web_path}{$config['avatar_gallery_path']}/", + 'T_ICONS_PATH' => "{$web_path}{$config['icons_path']}/", + 'T_RANKS_PATH' => "{$web_path}{$config['ranks_path']}/", + 'T_UPLOAD_PATH' => "{$web_path}{$config['upload_path']}/", + 'T_STYLESHEET_LINK' => (!$user->theme['theme_storedb']) ? "{$web_path}styles/" . $user->theme['theme_path'] . '/theme/stylesheet.css' : append_sid("{$phpbb_root_path}style.$phpEx", 'id=' . $user->theme['style_id'] . '&lang=' . $user->data['user_lang']), 'T_STYLESHEET_NAME' => $user->theme['theme_name'], + 'T_THEME_NAME' => $user->theme['theme_path'], + 'T_TEMPLATE_NAME' => $user->theme['template_path'], + 'T_SUPER_TEMPLATE_NAME' => (isset($user->theme['template_inherit_path']) && $user->theme['template_inherit_path']) ? $user->theme['template_inherit_path'] : $user->theme['template_path'], + 'T_IMAGESET_NAME' => $user->theme['imageset_path'], + 'T_IMAGESET_LANG_NAME' => $user->data['user_lang'], + 'T_IMAGES' => 'images', + 'T_SMILIES' => $config['smilies_path'], + 'T_AVATAR' => $config['avatar_path'], + 'T_AVATAR_GALLERY' => $config['avatar_gallery_path'], + 'T_ICONS' => $config['icons_path'], + 'T_RANKS' => $config['ranks_path'], + 'T_UPLOAD' => $config['upload_path'], + 'SITE_LOGO_IMG' => $user->img('site_logo'), 'A_COOKIE_SETTINGS' => addslashes('; path=' . $config['cookie_path'] . ((!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain']) . ((!$config['cookie_secure']) ? '' : '; secure')), @@ -3848,7 +4209,7 @@ function page_footer($run_cron = true) $db->sql_report('display'); } - $debug_output = sprintf('Time : %.3fs | ' . $db->sql_num_queries() . ' Queries | GZIP : ' . (($config['gzip_compress']) ? 'On' : 'Off') . (($user->load) ? ' | Load : ' . $user->load : ''), $totaltime); + $debug_output = sprintf('Time : %.3fs | ' . $db->sql_num_queries() . ' Queries | GZIP : ' . (($config['gzip_compress'] && @extension_loaded('zlib')) ? 'On' : 'Off') . (($user->load) ? ' | Load : ' . $user->load : ''), $totaltime); if ($auth->acl_get('a_') && defined('DEBUG_EXTRA')) { @@ -3876,35 +4237,55 @@ function page_footer($run_cron = true) ); // Call cron-type script + $call_cron = false; if (!defined('IN_CRON') && $run_cron && !$config['board_disable']) + { + $call_cron = true; + $time_now = (!empty($user->time_now) && is_int($user->time_now)) ? $user->time_now : time(); + + // Any old lock present? + if (!empty($config['cron_lock'])) + { + $cron_time = explode(' ', $config['cron_lock']); + + // If 1 hour lock is present we do not call cron.php + if ($cron_time[0] + 3600 >= $time_now) + { + $call_cron = false; + } + } + } + + // Call cron job? + if ($call_cron) { $cron_type = ''; - if (time() - $config['queue_interval'] > $config['last_queue_run'] && !defined('IN_ADMIN') && file_exists($phpbb_root_path . 'cache/queue.' . $phpEx)) + if ($time_now - $config['queue_interval'] > $config['last_queue_run'] && !defined('IN_ADMIN') && file_exists($phpbb_root_path . 'cache/queue.' . $phpEx)) { // Process email queue $cron_type = 'queue'; } - else if (method_exists($cache, 'tidy') && time() - $config['cache_gc'] > $config['cache_last_gc']) + else if (method_exists($cache, 'tidy') && $time_now - $config['cache_gc'] > $config['cache_last_gc']) { // Tidy the cache $cron_type = 'tidy_cache'; } - else if (time() - $config['warnings_gc'] > $config['warnings_last_gc']) + else if ($config['warnings_expire_days'] && ($time_now - $config['warnings_gc'] > $config['warnings_last_gc'])) { $cron_type = 'tidy_warnings'; } - else if (time() - $config['database_gc'] > $config['database_last_gc']) + else if ($time_now - $config['database_gc'] > $config['database_last_gc']) { // Tidy the database $cron_type = 'tidy_database'; } - else if (time() - $config['search_gc'] > $config['search_last_gc']) + else if ($time_now - $config['search_gc'] > $config['search_last_gc']) { // Tidy the search $cron_type = 'tidy_search'; } - else if (time() - $config['session_gc'] > $config['session_last_gc']) + else if ($time_now - $config['session_gc'] > $config['session_last_gc']) { $cron_type = 'tidy_sessions'; } diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php index 79282c0358..d42a81fa35 100644 --- a/phpBB/includes/functions_admin.php +++ b/phpBB/includes/functions_admin.php @@ -17,95 +17,47 @@ if (!defined('IN_PHPBB')) } /** -* Recalculate Binary Tree -function recalc_btree($sql_id, $sql_table, $module_class = '') +* Recalculate Nested Sets +* +* @param int $new_id first left_id (should start with 1) +* @param string $pkey primary key-column (containing the id for the parent_id of the children) +* @param string $table constant or fullname of the table +* @param int $parent_id parent_id of the current set (default = 0) +* @param array $where contains strings to compare closer on the where statement (additional) +* +* @author EXreaction +*/ +function recalc_nested_sets(&$new_id, $pkey, $table, $parent_id = 0, $where = array()) { global $db; - if (!$sql_id || !$sql_table) - { - return; - } - - $sql_where = ($module_class) ? " WHERE module_class = '" . $db->sql_escape($module_class) . "'" : ''; - - // Reset to minimum possible left and right id - $sql = "SELECT MIN(left_id) as min_left_id, MIN(right_id) as min_right_id - FROM $sql_table - $sql_where"; + $sql = 'SELECT * + FROM ' . $table . ' + WHERE parent_id = ' . (int) $parent_id . + ((!empty($where)) ? ' AND ' . implode(' AND ', $where) : '') . ' + ORDER BY left_id ASC'; $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); + while ($row = $db->sql_fetchrow($result)) + { + // First we update the left_id for this module + if ($row['left_id'] != $new_id) + { + $db->sql_query('UPDATE ' . $table . ' SET ' . $db->sql_build_array('UPDATE', array('left_id' => $new_id)) . " WHERE $pkey = {$row[$pkey]}"); + } + $new_id++; + + // Then we go through any children and update their left/right id's + recalc_nested_sets($new_id, $pkey, $table, $row[$pkey], $where); + + // Then we come back and update the right_id for this module + if ($row['right_id'] != $new_id) + { + $db->sql_query('UPDATE ' . $table . ' SET ' . $db->sql_build_array('UPDATE', array('right_id' => $new_id)) . " WHERE $pkey = {$row[$pkey]}"); + } + $new_id++; + } $db->sql_freeresult($result); - - $substract = (int) (min($row['min_left_id'], $row['min_right_id']) - 1); - - if ($substract > 0) - { - $sql = "UPDATE $sql_table - SET left_id = left_id - $substract, right_id = right_id - $substract - $sql_where"; - $db->sql_query($sql); - } - - $sql = "SELECT $sql_id, parent_id, left_id, right_id - FROM $sql_table - $sql_where - ORDER BY left_id ASC, parent_id ASC, $sql_id ASC"; - $f_result = $db->sql_query($sql); - - while ($item_data = $db->sql_fetchrow($f_result)) - { - if ($item_data['parent_id']) - { - $sql = "SELECT left_id, right_id - FROM $sql_table - $sql_where " . (($sql_where) ? 'AND' : 'WHERE') . " - $sql_id = {$item_data['parent_id']}"; - $result = $db->sql_query($sql); - - if (!$row = $db->sql_fetchrow($result)) - { - $sql = "UPDATE $sql_table SET parent_id = 0 WHERE $sql_id = " . $item_data[$sql_id]; - $db->sql_query($sql); - } - $db->sql_freeresult($result); - - $sql = "UPDATE $sql_table - SET left_id = left_id + 2, right_id = right_id + 2 - $sql_where " . (($sql_where) ? 'AND' : 'WHERE') . " - left_id > {$row['right_id']}"; - $db->sql_query($sql); - - $sql = "UPDATE $sql_table - SET right_id = right_id + 2 - $sql_where " . (($sql_where) ? 'AND' : 'WHERE') . " - {$row['left_id']} BETWEEN left_id AND right_id"; - $db->sql_query($sql); - - $item_data['left_id'] = $row['right_id']; - $item_data['right_id'] = $row['right_id'] + 1; - } - else - { - $sql = "SELECT MAX(right_id) AS right_id - FROM $sql_table - $sql_where"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - $item_data['left_id'] = $row['right_id'] + 1; - $item_data['right_id'] = $row['right_id'] + 2; - } - - $sql = "UPDATE $sql_table - SET left_id = {$item_data['left_id']}, right_id = {$item_data['right_id']} - WHERE $sql_id = " . $item_data[$sql_id]; - $db->sql_query($sql); - } - $db->sql_freeresult($f_result); } -*/ /** * Simple version of jumpbox, just lists authed forums @@ -117,7 +69,7 @@ function make_forum_select($select_id = false, $ignore_id = false, $ignore_acl = $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, left_id, right_id + $sql = 'SELECT forum_id, forum_name, parent_id, forum_type, forum_flags, forum_options, left_id, right_id FROM ' . FORUMS_TABLE . ' ORDER BY left_id ASC'; $result = $db->sql_query($sql, 600); @@ -354,12 +306,157 @@ function get_forum_branch($forum_id, $type = 'all', $order = 'descending', $incl return $rows; } +/** +* Copies permissions from one forum to others +* +* @param int $src_forum_id The source forum we want to copy permissions from +* @param array $dest_forum_ids The destination forum(s) we want to copy to +* @param bool $clear_dest_perms True if destination permissions should be deleted +* @param bool $add_log True if log entry should be added +* +* @return bool False on error +* +* @author bantu +*/ +function copy_forum_permissions($src_forum_id, $dest_forum_ids, $clear_dest_perms = true, $add_log = true) +{ + global $db; + + // Only one forum id specified + if (!is_array($dest_forum_ids)) + { + $dest_forum_ids = array($dest_forum_ids); + } + + // Make sure forum ids are integers + $src_forum_id = (int) $src_forum_id; + $dest_forum_ids = array_map('intval', $dest_forum_ids); + + // No source forum or no destination forums specified + if (empty($src_forum_id) || empty($dest_forum_ids)) + { + return false; + } + + // Check if source forum exists + $sql = 'SELECT forum_name + FROM ' . FORUMS_TABLE . ' + WHERE forum_id = ' . $src_forum_id; + $result = $db->sql_query($sql); + $src_forum_name = $db->sql_fetchfield('forum_name'); + $db->sql_freeresult($result); + + // Source forum doesn't exist + if (empty($src_forum_name)) + { + return false; + } + + // Check if destination forums exists + $sql = 'SELECT forum_id, forum_name + FROM ' . FORUMS_TABLE . ' + WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids); + $result = $db->sql_query($sql); + + $dest_forum_ids = $dest_forum_names = array(); + while ($row = $db->sql_fetchrow($result)) + { + $dest_forum_ids[] = (int) $row['forum_id']; + $dest_forum_names[] = $row['forum_name']; + } + $db->sql_freeresult($result); + + // No destination forum exists + if (empty($dest_forum_ids)) + { + return false; + } + + // From the mysql documentation: + // Prior to MySQL 4.0.14, the target table of the INSERT statement cannot appear + // in the FROM clause of the SELECT part of the query. This limitation is lifted in 4.0.14. + // Due to this we stay on the safe side if we do the insertion "the manual way" + + // Rowsets we're going to insert + $users_sql_ary = $groups_sql_ary = array(); + + // Query acl users table for source forum data + $sql = 'SELECT user_id, auth_option_id, auth_role_id, auth_setting + FROM ' . ACL_USERS_TABLE . ' + WHERE forum_id = ' . $src_forum_id; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $row = array( + 'user_id' => (int) $row['user_id'], + 'auth_option_id' => (int) $row['auth_option_id'], + 'auth_role_id' => (int) $row['auth_role_id'], + 'auth_setting' => (int) $row['auth_setting'], + ); + + foreach ($dest_forum_ids as $dest_forum_id) + { + $users_sql_ary[] = $row + array('forum_id' => $dest_forum_id); + } + } + $db->sql_freeresult($result); + + // Query acl groups table for source forum data + $sql = 'SELECT group_id, auth_option_id, auth_role_id, auth_setting + FROM ' . ACL_GROUPS_TABLE . ' + WHERE forum_id = ' . $src_forum_id; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $row = array( + 'group_id' => (int) $row['group_id'], + 'auth_option_id' => (int) $row['auth_option_id'], + 'auth_role_id' => (int) $row['auth_role_id'], + 'auth_setting' => (int) $row['auth_setting'], + ); + + foreach ($dest_forum_ids as $dest_forum_id) + { + $groups_sql_ary[] = $row + array('forum_id' => $dest_forum_id); + } + } + $db->sql_freeresult($result); + + $db->sql_transaction('begin'); + + // Clear current permissions of destination forums + if ($clear_dest_perms) + { + $sql = 'DELETE FROM ' . ACL_USERS_TABLE . ' + WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids); + $db->sql_query($sql); + + $sql = 'DELETE FROM ' . ACL_GROUPS_TABLE . ' + WHERE ' . $db->sql_in_set('forum_id', $dest_forum_ids); + $db->sql_query($sql); + } + + $db->sql_multi_insert(ACL_USERS_TABLE, $users_sql_ary); + $db->sql_multi_insert(ACL_GROUPS_TABLE, $groups_sql_ary); + + if ($add_log) + { + add_log('admin', 'LOG_FORUM_COPIED_PERMISSIONS', $src_forum_name, implode(', ', $dest_forum_names)); + } + + $db->sql_transaction('commit'); + + return true; +} + /** * Get physical file listing */ function filelist($rootdir, $dir = '', $type = 'gif|jpg|jpeg|png') { - $matches = array(); + $matches = array($dir => array()); // Remove initial / if present $rootdir = (substr($rootdir, 0, 1) == '/') ? substr($rootdir, 1) : $rootdir; @@ -940,19 +1037,61 @@ function delete_attachments($mode, $ids, $resync = true) // Update post indicators for posts now no longer having attachments if (sizeof($post_ids)) { - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_attachment = 0 - WHERE ' . $db->sql_in_set('post_id', $post_ids); - $db->sql_query($sql); + // Just check which posts are still having an assigned attachment not orphaned by querying the attachments table + $sql = 'SELECT post_msg_id + FROM ' . ATTACHMENTS_TABLE . ' + WHERE ' . $db->sql_in_set('post_msg_id', $post_ids) . ' + AND in_message = 0 + AND is_orphan = 0'; + $result = $db->sql_query($sql); + + $remaining_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $remaining_ids[] = $row['post_msg_id']; + } + $db->sql_freeresult($result); + + // Now only unset those ids remaining + $post_ids = array_diff($post_ids, $remaining_ids); + + if (sizeof($post_ids)) + { + $sql = 'UPDATE ' . POSTS_TABLE . ' + SET post_attachment = 0 + WHERE ' . $db->sql_in_set('post_id', $post_ids); + $db->sql_query($sql); + } } // Update message table if messages are affected if (sizeof($message_ids)) { - $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' - SET message_attachment = 0 - WHERE ' . $db->sql_in_set('msg_id', $message_ids); - $db->sql_query($sql); + // Just check which messages are still having an assigned attachment not orphaned by querying the attachments table + $sql = 'SELECT post_msg_id + FROM ' . ATTACHMENTS_TABLE . ' + WHERE ' . $db->sql_in_set('post_msg_id', $message_ids) . ' + AND in_message = 1 + AND is_orphan = 0'; + $result = $db->sql_query($sql); + + $remaining_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $remaining_ids[] = $row['post_msg_id']; + } + $db->sql_freeresult($result); + + // Now only unset those ids remaining + $message_ids = array_diff($message_ids, $remaining_ids); + + if (sizeof($message_ids)) + { + $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' + SET message_attachment = 0 + WHERE ' . $db->sql_in_set('msg_id', $message_ids); + $db->sql_query($sql); + } } // Now update the topics. This is a bit trickier, because there could be posts still having attachments within the topic @@ -1098,7 +1237,7 @@ function phpbb_unlink($filename, $mode = 'file', $entry_removed = false) // Because of copying topics or modifications a physical filename could be assigned more than once. If so, do not remove the file itself. $sql = 'SELECT COUNT(attach_id) AS num_entries FROM ' . ATTACHMENTS_TABLE . " - WHERE physical_filename = '" . $db->sql_escape(basename($filename)) . "'"; + WHERE physical_filename = '" . $db->sql_escape(utf8_basename($filename)) . "'"; $result = $db->sql_query($sql); $num_entries = (int) $db->sql_fetchfield('num_entries'); $db->sql_freeresult($result); @@ -1109,7 +1248,7 @@ function phpbb_unlink($filename, $mode = 'file', $entry_removed = false) return false; } - $filename = ($mode == 'thumbnail') ? 'thumb_' . basename($filename) : basename($filename); + $filename = ($mode == 'thumbnail') ? 'thumb_' . utf8_basename($filename) : utf8_basename($filename); return @unlink($phpbb_root_path . $config['upload_path'] . '/' . $filename); } @@ -1193,6 +1332,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, switch ($mode) { case 'topic_moved': + $db->sql_transaction('begin'); switch ($db->sql_layer) { case 'mysql4': @@ -1229,9 +1369,13 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, break; } - break; + + $db->sql_transaction('commit'); + break; case 'topic_approved': + + $db->sql_transaction('begin'); switch ($db->sql_layer) { case 'mysql4': @@ -1267,11 +1411,15 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $db->sql_query($sql); break; } - break; + + $db->sql_transaction('commit'); + break; case 'post_reported': $post_ids = $post_reported = array(); + $db->sql_transaction('begin'); + $sql = 'SELECT p.post_id, p.post_reported FROM ' . POSTS_TABLE . " p $where_sql @@ -1322,7 +1470,9 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, WHERE ' . $db->sql_in_set('post_id', $post_ids); $db->sql_query($sql); } - break; + + $db->sql_transaction('commit'); + break; case 'topic_reported': if ($sync_extra) @@ -1332,6 +1482,8 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $topic_ids = $topic_reported = array(); + $db->sql_transaction('begin'); + $sql = 'SELECT DISTINCT(t.topic_id) FROM ' . POSTS_TABLE . " t $where_sql_and t.post_reported = 1"; @@ -1364,11 +1516,15 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, WHERE ' . $db->sql_in_set('topic_id', $topic_ids); $db->sql_query($sql); } - break; + + $db->sql_transaction('commit'); + break; case 'post_attachment': $post_ids = $post_attachment = array(); + $db->sql_transaction('begin'); + $sql = 'SELECT p.post_id, p.post_attachment FROM ' . POSTS_TABLE . " p $where_sql @@ -1419,7 +1575,9 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, WHERE ' . $db->sql_in_set('post_id', $post_ids); $db->sql_query($sql); } - break; + + $db->sql_transaction('commit'); + break; case 'topic_attachment': if ($sync_extra) @@ -1429,6 +1587,8 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $topic_ids = $topic_attachment = array(); + $db->sql_transaction('begin'); + $sql = 'SELECT DISTINCT(t.topic_id) FROM ' . POSTS_TABLE . " t $where_sql_and t.post_attachment = 1"; @@ -1461,10 +1621,15 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, WHERE ' . $db->sql_in_set('topic_id', $topic_ids); $db->sql_query($sql); } - break; + + $db->sql_transaction('commit'); + + break; case 'forum': + $db->sql_transaction('begin'); + // 1: Get the list of all forums $sql = 'SELECT f.* FROM ' . FORUMS_TABLE . " f @@ -1665,11 +1830,15 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, $db->sql_query($sql); } } - break; + + $db->sql_transaction('commit'); + break; case 'topic': $topic_data = $post_ids = $approved_unapproved_ids = $resync_forums = $delete_topics = $delete_posts = $moved_topics = array(); + $db->sql_transaction('begin'); + $sql = 'SELECT t.topic_id, t.forum_id, t.topic_moved_id, t.topic_approved, ' . (($sync_extra) ? 't.topic_attachment, t.topic_reported, ' : '') . 't.topic_poster, t.topic_time, t.topic_replies, t.topic_replies_real, t.topic_first_post_id, t.topic_first_poster_name, t.topic_first_poster_colour, t.topic_last_post_id, t.topic_last_post_subject, t.topic_last_poster_id, t.topic_last_poster_name, t.topic_last_poster_colour, t.topic_last_post_time FROM ' . TOPICS_TABLE . " t $where_sql"; @@ -1992,6 +2161,8 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, } unset($topic_data); + $db->sql_transaction('commit'); + // if some topics have been resync'ed then resync parent forums // except when we're only syncing a range, we don't want to sync forums during // batch processing. @@ -1999,7 +2170,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false, { sync('forum', 'forum_id', array_values($resync_forums), true, true); } - break; + break; } return; @@ -2185,12 +2356,13 @@ function cache_moderators() // Remove users who have group memberships with DENY moderator permissions $sql = $db->sql_build_query('SELECT', array( - 'SELECT' => 'a.forum_id, ug.user_id', + 'SELECT' => 'a.forum_id, ug.user_id, g.group_id', 'FROM' => array( ACL_OPTIONS_TABLE => 'o', USER_GROUP_TABLE => 'ug', - ACL_GROUPS_TABLE => 'a' + ACL_GROUPS_TABLE => 'a', + GROUPS_TABLE => 'g', ), 'LEFT_JOIN' => array( @@ -2204,6 +2376,8 @@ function cache_moderators() AND ((a.auth_setting = ' . ACL_NEVER . ' AND r.auth_setting IS NULL) OR r.auth_setting = ' . ACL_NEVER . ') AND a.group_id = ug.group_id + AND g.group_id = ug.group_id + AND NOT (ug.group_leader = 1 AND g.group_skip_auth = 1) AND ' . $db->sql_in_set('ug.user_id', $ug_id_ary) . " AND ug.user_pending = 0 AND o.auth_option " . $db->sql_like_expression('m_' . $db->any_char), @@ -2323,7 +2497,7 @@ function cache_moderators() /** * View log */ -function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $limit_days = 0, $sort_by = 'l.log_time DESC') +function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $limit_days = 0, $sort_by = 'l.log_time DESC', $keywords = '') { global $db, $user, $auth, $phpEx, $phpbb_root_path, $phpbb_admin_path; @@ -2343,15 +2517,15 @@ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id if ($topic_id) { - $sql_forum = 'AND l.topic_id = ' . intval($topic_id); + $sql_forum = 'AND l.topic_id = ' . (int) $topic_id; } else if (is_array($forum_id)) { $sql_forum = 'AND ' . $db->sql_in_set('l.forum_id', array_map('intval', $forum_id)); } - else + else if ($forum_id) { - $sql_forum = ($forum_id) ? 'AND l.forum_id = ' . intval($forum_id) : ''; + $sql_forum = 'AND l.forum_id = ' . (int) $forum_id; } break; @@ -2374,11 +2548,40 @@ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id return; } + $keywords = preg_split('#[\s+\-|*()]+#u', utf8_strtolower(preg_quote($keywords, '#')), 0, PREG_SPLIT_NO_EMPTY); + $sql_keywords = ''; + + if (!empty($keywords)) + { + $keywords_pattern = '#' . implode('|', $keywords) . '#ui'; + for ($i = 0, $num_keywords = sizeof($keywords); $i < $num_keywords; $i++) + { + $keywords[$i] = $db->sql_like_expression($db->any_char . $keywords[$i] . $db->any_char); + } + + $operations = array(); + foreach ($user->lang as $key => $value) + { + if (substr($key, 0, 4) == 'LOG_' && preg_match($keywords_pattern, $value)) + { + $operations[] = $key; + } + } + + $sql_keywords = 'AND ('; + if (!empty($operations)) + { + $sql_keywords .= $db->sql_in_set('l.log_operation', $operations) . ' OR '; + } + $sql_keywords .= 'LOWER(l.log_data) ' . implode(' OR LOWER(l.log_data) ', $keywords) . ')'; + } + $sql = "SELECT l.*, u.username, u.username_clean, u.user_colour FROM " . LOG_TABLE . " l, " . USERS_TABLE . " u WHERE l.log_type = $log_type AND u.user_id = l.user_id " . (($limit_days) ? "AND l.log_time >= $limit_days" : '') . " + $sql_keywords $sql_forum ORDER BY $sort_by"; $result = $db->sql_query_limit($sql, $limit, $offset); @@ -2419,7 +2622,8 @@ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id if (!empty($row['log_data'])) { - $log_data_ary = unserialize($row['log_data']); + $log_data_ary = @unserialize($row['log_data']); + $log_data_ary = ($log_data_ary === false) ? array() : $log_data_ary; if (isset($user->lang[$row['log_operation']])) { @@ -2442,7 +2646,7 @@ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action'])); } } - else + else if (!empty($log_data_ary)) { $log[$i]['action'] .= '
    ' . implode('', $log_data_ary); } @@ -2540,9 +2744,11 @@ function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id } $sql = 'SELECT COUNT(l.log_id) AS total_entries - FROM ' . LOG_TABLE . " l + FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . " u WHERE l.log_type = $log_type + AND l.user_id = u.user_id AND l.log_time >= $limit_days + $sql_keywords $sql_forum"; $result = $db->sql_query($sql); $log_count = (int) $db->sql_fetchfield('total_entries'); @@ -2685,7 +2891,7 @@ function view_inactive_users(&$users, &$user_count, $limit = 0, $offset = 0, $li $offset = ($offset - $limit < 0) ? 0 : $offset - $limit; } - $sql = 'SELECT user_id, username, user_regdate, user_lastvisit, user_inactive_time, user_inactive_reason + $sql = 'SELECT * FROM ' . USERS_TABLE . ' WHERE user_type = ' . USER_INACTIVE . (($limit_days) ? " AND user_inactive_time >= $limit_days" : '') . " @@ -3054,4 +3260,43 @@ function add_permission_language() return true; } +/** + * Obtains the latest version information + * + * @param bool $force_update Ignores cached data. Defaults to false. + * @param bool $warn_fail Trigger a warning if obtaining the latest version information fails. Defaults to false. + * @param int $ttl Cache version information for $ttl seconds. Defaults to 86400 (24 hours). + * + * @return string | false Version info on success, false on failure. + */ +function obtain_latest_version_info($force_update = false, $warn_fail = false, $ttl = 86400) +{ + global $cache; + + $info = $cache->get('versioncheck'); + + if ($info === false || $force_update) + { + $errstr = ''; + $errno = 0; + + $info = get_remote_file('www.phpbb.com', '/updatecheck', + ((defined('PHPBB_QA')) ? '30x_qa.txt' : '30x.txt'), $errstr, $errno); + + if ($info === false) + { + $cache->destroy('versioncheck'); + if ($warn_fail) + { + trigger_error($errstr, E_USER_WARNING); + } + return false; + } + + $cache->put('versioncheck', $info, $ttl); + } + + return $info; +} + ?> \ No newline at end of file diff --git a/phpBB/includes/functions_compress.php b/phpBB/includes/functions_compress.php index 881e1ba5cc..590daabf1d 100644 --- a/phpBB/includes/functions_compress.php +++ b/phpBB/includes/functions_compress.php @@ -155,7 +155,12 @@ class compress_zip extends compress */ function compress_zip($mode, $file) { - return $this->fp = @fopen($file, $mode . 'b'); + $this->fp = @fopen($file, $mode . 'b'); + + if (!$this->fp) + { + trigger_error('Unable to open file ' . $file . ' [' . $mode . 'b]'); + } } /** diff --git a/phpBB/includes/functions_content.php b/phpBB/includes/functions_content.php index 3107177137..c265d0ae41 100644 --- a/phpBB/includes/functions_content.php +++ b/phpBB/includes/functions_content.php @@ -250,6 +250,11 @@ function get_context($text, $words, $length = 400) // first replace all whitespaces with single spaces $text = preg_replace('/ +/', ' ', strtr($text, "\t\n\r\x0C ", ' ')); + // we need to turn the entities back into their original form, to not cut the message in between them + $entities = array('<', '>', '[', ']', '.', ':', ':'); + $characters = array('<', '>', '[', ']', '.', ':', ':'); + $text = str_replace($entities, $characters, $text); + $word_indizes = array(); if (sizeof($words)) { @@ -345,13 +350,13 @@ function get_context($text, $words, $length = 400) } } } - return $final_text; + return str_replace($characters, $entities, $final_text); } } if (!sizeof($words) || !sizeof($word_indizes)) { - return (utf8_strlen($text) >= $length + 3) ? utf8_substr($text, 0, $length) . '...' : $text; + return str_replace($characters, $entities, ((utf8_strlen($text) >= $length + 3) ? utf8_substr($text, 0, $length) . '...' : $text)); } } @@ -680,6 +685,12 @@ function censor_text($text) { static $censors; + // Nothing to do? + if ($text === '') + { + return ''; + } + // We moved the word censor checks in here because we call this function quite often - and then only need to do the check once if (!isset($censors) || !is_array($censors)) { @@ -728,7 +739,8 @@ function smiley_text($text, $force_option = false) } else { - return preg_replace('#', $text); + $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path; + return preg_replace('#', $text); } } @@ -836,8 +848,8 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count, // Some basics... $attachment['extension'] = strtolower(trim($attachment['extension'])); - $filename = $phpbb_root_path . $config['upload_path'] . '/' . basename($attachment['physical_filename']); - $thumbnail_filename = $phpbb_root_path . $config['upload_path'] . '/thumb_' . basename($attachment['physical_filename']); + $filename = $phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($attachment['physical_filename']); + $thumbnail_filename = $phpbb_root_path . $config['upload_path'] . '/thumb_' . utf8_basename($attachment['physical_filename']); $upload_icon = ''; @@ -853,17 +865,15 @@ function parse_attachments($forum_id, &$message, &$attachments, &$update_count, } } - $filesize = $attachment['filesize']; - $size_lang = ($filesize >= 1048576) ? $user->lang['MIB'] : (($filesize >= 1024) ? $user->lang['KIB'] : $user->lang['BYTES']); - $filesize = get_formatted_filesize($filesize, false); + $filesize = get_formatted_filesize($attachment['filesize'], false); $comment = bbcode_nl2br(censor_text($attachment['attach_comment'])); $block_array += array( 'UPLOAD_ICON' => $upload_icon, - 'FILESIZE' => $filesize, - 'SIZE_LANG' => $size_lang, - 'DOWNLOAD_NAME' => basename($attachment['real_filename']), + 'FILESIZE' => $filesize['value'], + 'SIZE_LANG' => $filesize['unit'], + 'DOWNLOAD_NAME' => utf8_basename($attachment['real_filename']), 'COMMENT' => $comment, ); diff --git a/phpBB/includes/functions_convert.php b/phpBB/includes/functions_convert.php index 2213df7d0f..82ec114c09 100644 --- a/phpBB/includes/functions_convert.php +++ b/phpBB/includes/functions_convert.php @@ -551,7 +551,7 @@ function _import_check($config_var, $source, $use_target) ); // copy file will prepend $phpBB_root_path - $target = $config[$config_var] . '/' . basename(($use_target === false) ? $source : $use_target); + $target = $config[$config_var] . '/' . utf8_basename(($use_target === false) ? $source : $use_target); if (!empty($convert->convertor[$config_var]) && strpos($source, $convert->convertor[$config_var]) !== 0) { @@ -567,11 +567,11 @@ function _import_check($config_var, $source, $use_target) if ($result['copied']) { - $result['target'] = basename($target); + $result['target'] = utf8_basename($target); } else { - $result['target'] = ($use_target !== false) ? $result['orig_source'] : basename($target); + $result['target'] = ($use_target !== false) ? $result['orig_source'] : utf8_basename($target); } return $result; @@ -600,7 +600,7 @@ function import_attachment($source, $use_target = false) { $thumb_dir = $convert->convertor['thumbnails'][0]; $thumb_prefix = $convert->convertor['thumbnails'][1]; - $thumb_source = $thumb_dir . $thumb_prefix . basename($result['source']); + $thumb_source = $thumb_dir . $thumb_prefix . utf8_basename($result['source']); if (strpos($thumb_source, $convert->convertor['upload_path']) !== 0) { @@ -1698,7 +1698,8 @@ function add_default_groups() 'REGISTERED_COPPA' => array('', 0, 0), 'GLOBAL_MODERATORS' => array('00AA00', 1, 0), 'ADMINISTRATORS' => array('AA0000', 1, 1), - 'BOTS' => array('9E8DA7', 0, 0) + 'BOTS' => array('9E8DA7', 0, 0), + 'NEWLY_REGISTERED' => array('', 0, 0), ); $sql = 'SELECT * @@ -2256,7 +2257,7 @@ function copy_file($src, $trg, $overwrite = false, $die_on_failure = true, $sour if (substr($trg, -1) == '/') { - $trg .= basename($src); + $trg .= utf8_basename($src); } $src_path = relative_base($src, $source_relative_path, __LINE__, __FILE__); $trg_path = $trg; diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php index fdcc118269..cec1becb6e 100644 --- a/phpBB/includes/functions_display.php +++ b/phpBB/includes/functions_display.php @@ -102,6 +102,19 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod $forum_tracking_info = array(); $branch_root_id = $root_data['forum_id']; + + // Check for unread global announcements (index page only) + $ga_unread = false; + if ($root_data['forum_id'] == 0) + { + $unread_ga_list = get_unread_topics($user->data['user_id'], 'AND t.forum_id = 0', '', 1); + + if (!empty($unread_ga_list)) + { + $ga_unread = true; + } + } + while ($row = $db->sql_fetchrow($result)) { $forum_id = $row['forum_id']; @@ -154,6 +167,8 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod $forum_tracking_info[$forum_id] = (isset($tracking_topics['f'][$forum_id])) ? (int) (base_convert($tracking_topics['f'][$forum_id], 36, 10) + $config['board_startdate']) : $user->data['user_lastmark']; } + // Count the difference of real to public topics, so we can display an information to moderators + $row['forum_id_unapproved_topics'] = ($auth->acl_get('m_approve', $forum_id) && ($row['forum_topics_real'] != $row['forum_topics'])) ? $forum_id : 0; $row['forum_topics'] = ($auth->acl_get('m_approve', $forum_id)) ? $row['forum_topics_real'] : $row['forum_topics']; // Display active topics from this forum? @@ -212,6 +227,11 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod $subforums[$parent_id][$row['parent_id']]['children'][] = $forum_id; } + if (!$forum_rows[$parent_id]['forum_id_unapproved_topics'] && $row['forum_id_unapproved_topics']) + { + $forum_rows[$parent_id]['forum_id_unapproved_topics'] = $forum_id; + } + $forum_rows[$parent_id]['forum_topics'] += $row['forum_topics']; // Do not list redirects in LINK Forums as Posts. @@ -248,6 +268,8 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod } else { + // Add 0 to forums array to mark global announcements correctly + $forum_ids[] = 0; markread('topics', $forum_ids); $message = sprintf($user->lang['RETURN_FORUM'], '', ''); } @@ -300,6 +322,12 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod $forum_unread = (isset($forum_tracking_info[$forum_id]) && $row['orig_forum_last_post_time'] > $forum_tracking_info[$forum_id]) ? true : false; + // Mark the first visible forum on index as unread if there's any unread global announcement + if (($forum_id == $forum_ids_moderator[0]) && ($root_data['forum_id'] == 0) && $ga_unread) + { + $forum_unread = true; + } + $folder_image = $folder_alt = $l_subforums = ''; $subforums_list = array(); @@ -428,6 +456,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod 'S_LOCKED_FORUM' => ($row['forum_status'] == ITEM_LOCKED) ? true : false, 'S_LIST_SUBFORUMS' => ($row['display_subforum_list']) ? true : false, 'S_SUBFORUMS' => (sizeof($subforums_list)) ? true : false, + 'S_FEED_ENABLED' => ($config['feed_forum'] && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $row['forum_options'])) ? true : false, 'FORUM_ID' => $row['forum_id'], 'FORUM_NAME' => $row['forum_name'], @@ -451,6 +480,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod 'L_FORUM_FOLDER_ALT' => $folder_alt, 'L_MODERATOR_STR' => $l_moderator, + 'U_UNAPPROVED_TOPICS' => ($row['forum_id_unapproved_topics']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=unapproved_topics&f=' . $row['forum_id_unapproved_topics']) : '', 'U_VIEWFORUM' => $u_viewforum, 'U_LAST_POSTER' => get_username_string('profile', $row['forum_last_poster_id'], $row['forum_last_poster_name'], $row['forum_last_poster_colour']), 'U_LAST_POST' => $last_post_url) @@ -473,8 +503,9 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod 'U_MARK_FORUMS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'hash=' . generate_link_hash('global') . '&f=' . $root_data['forum_id'] . '&mark=forums') : '', 'S_HAS_SUBFORUM' => ($visible_forums) ? true : false, 'L_SUBFORUM' => ($visible_forums == 1) ? $user->lang['SUBFORUM'] : $user->lang['SUBFORUMS'], - 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST')) - ); + 'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'), + 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'TOPICS_UNAPPROVED'), + )); if ($return_moderators) { @@ -514,7 +545,7 @@ function generate_forum_rules(&$forum_data) */ function generate_forum_nav(&$forum_data) { - global $db, $user, $template, $auth; + global $db, $user, $template, $auth, $config; global $phpEx, $phpbb_root_path; if (!$auth->acl_get('f_list', $forum_data['forum_id'])) @@ -561,8 +592,10 @@ function generate_forum_nav(&$forum_data) $template->assign_vars(array( 'FORUM_ID' => $forum_data['forum_id'], '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'])) - ); + '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, + )); return; } @@ -658,14 +691,7 @@ function get_moderators(&$forum_moderators, $forum_id = false) { global $config, $template, $db, $phpbb_root_path, $phpEx, $user, $auth; - // Have we disabled the display of moderators? If so, then return - // from whence we came ... - if (!$config['load_moderators']) - { - return; - } - - $forum_sql = ''; + $forum_id_ary = array(); if ($forum_id !== false) { @@ -674,13 +700,8 @@ function get_moderators(&$forum_moderators, $forum_id = false) $forum_id = array($forum_id); } - // If we don't have a forum then we can't have a moderator - if (!sizeof($forum_id)) - { - return; - } - - $forum_sql = 'AND m.' . $db->sql_in_set('forum_id', $forum_id); + // Exchange key/value pair to be able to faster check for the forum id existence + $forum_id_ary = array_flip($forum_id); } $sql_array = array( @@ -701,17 +722,25 @@ function get_moderators(&$forum_moderators, $forum_id = false) ), ), - 'WHERE' => "m.display_on_index = 1 $forum_sql", + 'WHERE' => 'm.display_on_index = 1', ); + // We query every forum here because for caching we should not have any parameter. $sql = $db->sql_build_query('SELECT', $sql_array); $result = $db->sql_query($sql, 3600); while ($row = $db->sql_fetchrow($result)) { + $f_id = (int) $row['forum_id']; + + if (!isset($forum_id_ary[$f_id])) + { + continue; + } + if (!empty($row['user_id'])) { - $forum_moderators[$row['forum_id']][] = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']); + $forum_moderators[$f_id][] = get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']); } else { @@ -719,11 +748,11 @@ function get_moderators(&$forum_moderators, $forum_id = false) if ($user->data['user_id'] != ANONYMOUS && !$auth->acl_get('u_viewprofile')) { - $forum_moderators[$row['forum_id']][] = '' . $group_name . ''; + $forum_moderators[$f_id][] = '' . $group_name . ''; } else { - $forum_moderators[$row['forum_id']][] = '' . $group_name . ''; + $forum_moderators[$f_id][] = '' . $group_name . ''; } } } @@ -1200,14 +1229,15 @@ function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank * @param string $avatar_width Width of users avatar * @param string $avatar_height Height of users avatar * @param string $alt Optional language string for alt tag within image, can be a language key or text +* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP * * @return string Avatar image */ -function get_user_avatar($avatar, $avatar_type, $avatar_width, $avatar_height, $alt = 'USER_AVATAR') +function get_user_avatar($avatar, $avatar_type, $avatar_width, $avatar_height, $alt = 'USER_AVATAR', $ignore_config = false) { global $user, $config, $phpbb_root_path, $phpEx; - if (empty($avatar) || !$avatar_type) + if (empty($avatar) || !$avatar_type || (!$config['allow_avatar'] && !$ignore_config)) { return ''; } @@ -1217,12 +1247,27 @@ function get_user_avatar($avatar, $avatar_type, $avatar_width, $avatar_height, $ switch ($avatar_type) { case AVATAR_UPLOAD: + if (!$config['allow_avatar_upload'] && !$ignore_config) + { + return ''; + } $avatar_img = $phpbb_root_path . "download/file.$phpEx?avatar="; break; case AVATAR_GALLERY: + if (!$config['allow_avatar_local'] && !$ignore_config) + { + return ''; + } $avatar_img = $phpbb_root_path . $config['avatar_gallery_path'] . '/'; break; + + case AVATAR_REMOTE: + if (!$config['allow_avatar_remote'] && !$ignore_config) + { + return ''; + } + break; } $avatar_img .= $avatar; diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php index 611b0a7bc3..a5889224a1 100644 --- a/phpBB/includes/functions_install.php +++ b/phpBB/includes/functions_install.php @@ -21,6 +21,12 @@ if (!defined('IN_PHPBB')) */ 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')) + { + return false; + } return ((@ini_get('enable_dl') || strtolower(@ini_get('enable_dl')) == 'on') && (!@ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == 'off') && function_exists('dl') && @dl($dll . '.' . PHP_SHLIB_SUFFIX)) ? true : false; } @@ -175,7 +181,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 function dbms_select($default = '', $only_20x_options = false) { global $lang; - + $available_dbms = get_available_dbms(false, false, $only_20x_options); $dbms_options = ''; foreach ($available_dbms as $dbms_name => $details) @@ -396,10 +402,10 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, } else { - $sql = "SELECT FIRST 0 char_length('') - FROM RDB\$DATABASE"; + $sql = 'SELECT 1 FROM RDB$DATABASE + WHERE BIN_AND(10, 1) = 0'; $result = $db->sql_query($sql); - if (!$result) // This can only fail if char_length is not defined + if (!$result) // This can only fail if BIN_AND is not defined { $error[] = $lang['INST_ERR_DB_NO_FIREBIRD']; } @@ -440,7 +446,7 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, unset($final); } break; - + case 'oracle': if ($unicode_check) { @@ -462,7 +468,7 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix, } } break; - + case 'postgres': if ($unicode_check) { diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index 4fd5fd19e0..0fcf33f999 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -27,6 +27,8 @@ class messenger var $mail_priority = MAIL_NORMAL_PRIORITY; var $use_queue = true; + + var $tpl_obj = NULL; var $tpl_msg = array(); var $eol = "\n"; @@ -171,13 +173,13 @@ class messenger /** * Set email template to use */ - function template($template_file, $template_lang = '') + function template($template_file, $template_lang = '', $template_path = '') { global $config, $phpbb_root_path, $user; if (!trim($template_file)) { - trigger_error('No template file set', E_USER_ERROR); + trigger_error('No template file for emailing set.', E_USER_ERROR); } if (!trim($template_lang)) @@ -185,25 +187,28 @@ class messenger $template_lang = basename($config['default_lang']); } - if (empty($this->tpl_msg[$template_lang . $template_file])) + // tpl_msg now holds a template object we can use to parse the template file + if (!isset($this->tpl_msg[$template_lang . $template_file])) { - $tpl_file = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; - $tpl_file .= $template_lang . "/email/$template_file.txt"; + $this->tpl_msg[$template_lang . $template_file] = new template(); + $tpl = &$this->tpl_msg[$template_lang . $template_file]; - if (!file_exists($tpl_file)) + if (!$template_path) { - trigger_error("Could not find email template file [ $tpl_file ]", E_USER_ERROR); + $template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/'; + $template_path .= $template_lang . '/email'; } - if (($data = @file_get_contents($tpl_file)) === false) - { - trigger_error("Failed opening template file [ $tpl_file ]", E_USER_ERROR); - } + $tpl->set_custom_template($template_path, $template_lang . '_email'); - $this->tpl_msg[$template_lang . $template_file] = $data; + $tpl->set_filenames(array( + 'body' => $template_file . '.txt', + )); } - $this->msg = $this->tpl_msg[$template_lang . $template_file]; + $this->tpl_obj = &$this->tpl_msg[$template_lang . $template_file]; + $this->vars = &$this->tpl_obj->_rootref; + $this->tpl_msg = ''; return true; } @@ -213,7 +218,22 @@ class messenger */ function assign_vars($vars) { - $this->vars = (empty($this->vars)) ? $vars : $this->vars + $vars; + if (!is_object($this->tpl_obj)) + { + return; + } + + $this->tpl_obj->assign_vars($vars); + } + + function assign_block_vars($blockname, $vars) + { + if (!is_object($this->tpl_obj)) + { + return; + } + + $this->tpl_obj->assign_block_vars($blockname, $vars); } /** @@ -224,15 +244,32 @@ class messenger global $config, $user; // We add some standard variables we always use, no need to specify them always - $this->vars['U_BOARD'] = (!isset($this->vars['U_BOARD'])) ? generate_board_url() : $this->vars['U_BOARD']; - $this->vars['EMAIL_SIG'] = (!isset($this->vars['EMAIL_SIG'])) ? str_replace('
    ', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])) : $this->vars['EMAIL_SIG']; - $this->vars['SITENAME'] = (!isset($this->vars['SITENAME'])) ? htmlspecialchars_decode($config['sitename']) : $this->vars['SITENAME']; + if (!isset($this->vars['U_BOARD'])) + { + $this->assign_vars(array( + 'U_BOARD' => generate_board_url(), + )); + } - // Escape all quotes, else the eval will fail. - $this->msg = str_replace ("'", "\'", $this->msg); - $this->msg = preg_replace('#\{([a-z0-9\-_]*?)\}#is', "' . ((isset(\$this->vars['\\1'])) ? \$this->vars['\\1'] : '') . '", $this->msg); + if (!isset($this->vars['EMAIL_SIG'])) + { + $this->assign_vars(array( + 'EMAIL_SIG' => str_replace('
    ', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])), + )); + } - eval("\$this->msg = '$this->msg';"); + if (!isset($this->vars['SITENAME'])) + { + $this->assign_vars(array( + 'SITENAME' => htmlspecialchars_decode($config['sitename']), + )); + } + + // Parse message through template + $this->msg = trim($this->tpl_obj->assign_display('body')); + + // Because we use \n for newlines in the body message we need to fix line encoding errors for those admins who uploaded email template files in the wrong encoding + $this->msg = str_replace("\r\n", "\n", $this->msg); // We now try and pull a subject from the email body ... if it exists, // do this here because the subject may contain a variable @@ -356,7 +393,7 @@ class messenger $headers[] = 'X-Priority: ' . $this->mail_priority; $headers[] = 'X-MSMail-Priority: ' . (($this->mail_priority == MAIL_LOW_PRIORITY) ? 'Low' : (($this->mail_priority == MAIL_NORMAL_PRIORITY) ? 'Normal' : 'High')); - $headers[] = 'X-Mailer: PhpBB3'; + $headers[] = 'X-Mailer: phpBB3'; $headers[] = 'X-MimeOLE: phpBB3'; $headers[] = 'X-phpBB-Origin: phpbb://' . str_replace(array('http://', 'https://'), array('', ''), generate_board_url()); @@ -408,6 +445,8 @@ class messenger $this->from = '<' . $config['board_contact'] . '>'; } + $encode_eol = ($config['smtp_delivery']) ? "\r\n" : $this->eol; + // Build to, cc and bcc strings $to = $cc = $bcc = ''; foreach ($this->addresses as $type => $address_ary) @@ -419,7 +458,7 @@ class messenger foreach ($address_ary as $which_ary) { - $$type .= (($$type != '') ? ', ' : '') . (($which_ary['name'] != '') ? '"' . mail_encode($which_ary['name']) . '" <' . $which_ary['email'] . '>' : $which_ary['email']); + $$type .= (($$type != '') ? ', ' : '') . (($which_ary['name'] != '') ? mail_encode($which_ary['name'], $encode_eol) . ' <' . $which_ary['email'] . '>' : $which_ary['email']); } } @@ -438,13 +477,7 @@ class messenger } else { - // We use the EOL character for the OS here because the PHP mail function does not correctly transform line endings. On Windows SMTP is used (SMTP is \r\n), on UNIX a command is used... - // Reference: http://bugs.php.net/bug.php?id=15841 - $headers = implode($this->eol, $headers); - - ob_start(); - $result = $config['email_function_name']($mail_to, mail_encode($this->subject), wordwrap(utf8_wordwrap($this->msg), 997, "\n", true), $headers); - $err_msg = ob_get_clean(); + $result = phpbb_mail($mail_to, $this->subject, $this->msg, $headers, $this->eol, $err_msg); } if (!$result) @@ -687,9 +720,7 @@ class queue } else { - ob_start(); - $result = $config['email_function_name']($to, mail_encode($subject), wordwrap(utf8_wordwrap($msg), 997, "\n", true), implode($this->eol, $headers)); - $err_msg = ob_get_clean(); + $result = phpbb_mail($to, $subject, $msg, $headers, $this->eol, $err_msg); } if (!$result) @@ -1441,13 +1472,15 @@ class smtp_class * is basically doomed with an unreadable subject. * * Please note that this version fully supports RFC 2045 section 6.8. +* +* @param string $eol End of line we are using (optional to be backwards compatible) */ -function mail_encode($str) +function mail_encode($str, $eol = "\r\n") { // define start delimimter, end delimiter and spacer $start = "=?UTF-8?B?"; $end = "?="; - $delimiter = "\r\n "; + $delimiter = "$eol "; // Maximum length is 75. $split_length *must* be a multiple of 4, but <= 75 - strlen($start . $delimiter . $end)!!! $split_length = 60; @@ -1484,4 +1517,25 @@ function mail_encode($str) return substr($str, 0, -strlen($delimiter)); } +/** +* Wrapper for sending out emails with the PHP's mail function +*/ +function phpbb_mail($to, $subject, $msg, $headers, $eol, &$err_msg) +{ + global $config; + + // We use the EOL character for the OS here because the PHP mail function does not correctly transform line endings. On Windows SMTP is used (SMTP is \r\n), on UNIX a command is used... + // Reference: http://bugs.php.net/bug.php?id=15841 + $headers = implode($eol, $headers); + + ob_start(); + // On some PHP Versions mail() *may* fail if there are newlines within the subject. + // Newlines are used as a delimiter for lines in mail_encode() according to RFC 2045 section 6.8. + // Because PHP can't decide what is wanted we revert back to the non-RFC-compliant way of separating by one space (Use '' as parameter to mail_encode() results in SPACE used) + $result = $config['email_function_name']($to, mail_encode($subject, ''), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $headers); + $err_msg = ob_get_clean(); + + return $result; +} + ?> \ No newline at end of file diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index 07c8944992..069740ebda 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -24,6 +24,8 @@ function generate_smilies($mode, $forum_id) global $auth, $db, $user, $config, $template; global $phpEx, $phpbb_root_path; + $start = request_var('start', 0); + if ($mode == 'window') { if ($forum_id) @@ -44,9 +46,26 @@ function generate_smilies($mode, $forum_id) page_header($user->lang['SMILIES']); + $sql = 'SELECT COUNT(smiley_id) AS count + FROM ' . SMILIES_TABLE . ' + GROUP BY smiley_url'; + $result = $db->sql_query($sql, 3600); + + $smiley_count = 0; + while ($row = $db->sql_fetchrow($result)) + { + ++$smiley_count; + } + $db->sql_freeresult($result); + $template->set_filenames(array( 'body' => 'posting_smilies.html') ); + + $template->assign_var('PAGINATION', + generate_pagination(append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&f=' . $forum_id), + $smiley_count, $config['smilies_per_page'], $start, true) + ); } $display_link = false; @@ -64,13 +83,22 @@ function generate_smilies($mode, $forum_id) $db->sql_freeresult($result); } - $last_url = ''; - - $sql = 'SELECT * - FROM ' . SMILIES_TABLE . - (($mode == 'inline') ? ' WHERE display_on_posting = 1 ' : '') . ' - ORDER BY smiley_order'; - $result = $db->sql_query($sql, 3600); + if ($mode == 'window') + { + $sql = 'SELECT smiley_url, MIN(emotion) as emotion, MIN(code) AS code, smiley_width, smiley_height + FROM ' . SMILIES_TABLE . ' + GROUP BY smiley_url, smiley_width, smiley_height + ORDER BY smiley_order'; + $result = $db->sql_query_limit($sql, $config['smilies_per_page'], $start, 3600); + } + else + { + $sql = 'SELECT * + FROM ' . SMILIES_TABLE . ' + WHERE display_on_posting = 1 + ORDER BY smiley_order'; + $result = $db->sql_query($sql, 3600); + } $smilies = array(); while ($row = $db->sql_fetchrow($result)) @@ -84,12 +112,14 @@ function generate_smilies($mode, $forum_id) if (sizeof($smilies)) { + $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path; + foreach ($smilies as $row) { $template->assign_block_vars('smiley', array( 'SMILEY_CODE' => $row['code'], 'A_SMILEY_CODE' => addslashes($row['code']), - 'SMILEY_IMG' => $phpbb_root_path . $config['smilies_path'] . '/' . $row['smiley_url'], + 'SMILEY_IMG' => $root_path . $config['smilies_path'] . '/' . $row['smiley_url'], 'SMILEY_WIDTH' => $row['smiley_width'], 'SMILEY_HEIGHT' => $row['smiley_height'], 'SMILEY_DESC' => $row['emotion']) @@ -656,6 +686,7 @@ function create_thumbnail($source, $destination, $mimetype) break; case IMG_JPG: + @ini_set('gd.jpeg_ignore_warning', 1); $image = @imagecreatefromjpeg($source); break; @@ -668,6 +699,11 @@ function create_thumbnail($source, $destination, $mimetype) break; } + if (empty($image)) + { + return false; + } + if ($type['version'] == 1) { $new_image = imagecreate($new_width, $new_height); @@ -751,7 +787,7 @@ function posting_gen_inline_attachments(&$attachment_data) foreach ($attachment_data as $i => $attachment) { - $s_inline_attachment_options .= ''; + $s_inline_attachment_options .= ''; } $template->assign_var('S_INLINE_ATTACHMENT_OPTIONS', $s_inline_attachment_options); @@ -785,7 +821,7 @@ function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_a foreach ($attachment_data as $count => $attach_row) { $hidden = ''; - $attach_row['real_filename'] = basename($attach_row['real_filename']); + $attach_row['real_filename'] = utf8_basename($attach_row['real_filename']); foreach ($attach_row as $key => $value) { @@ -795,8 +831,8 @@ function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_a $download_link = append_sid("{$phpbb_root_path}download/file.$phpEx", 'mode=view&id=' . (int) $attach_row['attach_id'], true, ($attach_row['is_orphan']) ? $user->session_id : false); $template->assign_block_vars('attach_row', array( - 'FILENAME' => basename($attach_row['real_filename']), - 'A_FILENAME' => addslashes(basename($attach_row['real_filename'])), + 'FILENAME' => utf8_basename($attach_row['real_filename']), + 'A_FILENAME' => addslashes(utf8_basename($attach_row['real_filename'])), 'FILE_COMMENT' => $attach_row['attach_comment'], 'ATTACH_ID' => $attach_row['attach_id'], 'S_IS_ORPHAN' => $attach_row['is_orphan'], @@ -818,7 +854,7 @@ function posting_gen_attachment_entry($attachment_data, &$filename_data, $show_a /** * Load Drafts */ -function load_drafts($topic_id = 0, $forum_id = 0, $id = 0) +function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $msg_id = 0) { global $user, $db, $template, $auth; global $phpbb_root_path, $phpEx; @@ -911,7 +947,7 @@ function load_drafts($topic_id = 0, $forum_id = 0, $id = 0) { // Either display as PM draft if forum_id and topic_id are empty or if access to the forums has been denied afterwards... $link_pm = true; - $insert_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=compose&d={$draft['draft_id']}"); + $insert_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=$id&mode=compose&d={$draft['draft_id']}" . (($pm_action) ? "&action=$pm_action" : '') . (($msg_id) ? "&p=$msg_id" : '')); } $template->assign_block_vars('draftrow', array( @@ -944,6 +980,7 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id WHERE p.topic_id = $topic_id " . ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND p.post_approved = 1' : '') . ' ' . (($mode == 'post_review') ? " AND p.post_id > $cur_post_id" : '') . ' + ' . (($mode == 'post_review_edit') ? " AND p.post_id = $cur_post_id" : '') . ' ORDER BY p.post_time '; $sql .= ($mode == 'post_review') ? 'ASC' : 'DESC'; $result = $db->sql_query_limit($sql, $config['posts_per_page']); @@ -962,6 +999,12 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id return false; } + // Handle 'post_review_edit' like 'post_review' from now on + if ($mode == 'post_review_edit') + { + $mode = 'post_review'; + } + $sql = $db->sql_build_query('SELECT', array( 'SELECT' => 'u.username, u.user_id, u.user_colour, p.*, z.friend, z.foe', @@ -1514,6 +1557,21 @@ function delete_post($forum_id, $topic_id, $post_id, &$data) break; } + if (($post_mode == 'delete') || ($post_mode == 'delete_last_post') || ($post_mode == 'delete_first_post')) + { + $sql = 'SELECT 1 AS has_attachments + FROM ' . ATTACHMENTS_TABLE . ' + WHERE topic_id = ' . $topic_id; + $result = $db->sql_query_limit($sql, 1); + $has_attachments = (int) $db->sql_fetchfield('has_attachments'); + $db->sql_freeresult($result); + + if (!$has_attachments) + { + $sql_data[TOPICS_TABLE] .= ', topic_attachment = 0'; + } + } + // $sql_data[USERS_TABLE] = ($data['post_postcount']) ? 'user_posts = user_posts - 1' : ''; $db->sql_transaction('begin'); @@ -1565,8 +1623,9 @@ function delete_post($forum_id, $topic_id, $post_id, &$data) /** * Submit Post +* @todo Split up and create lightweight, simple API for this. */ -function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $update_message = true) +function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $update_message = true, $update_search_index = true) { global $db, $auth, $user, $config, $phpEx, $template, $phpbb_root_path; @@ -1618,14 +1677,22 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u } // This variable indicates if the user is able to post or put into the queue - it is used later for all code decisions regarding approval + // The variable name should be $post_approved, because it indicates if the post is approved or not $post_approval = 1; - // Check the permissions for post approval, as well as the queue trigger where users are put on approval with a post count lower than specified. Moderators are not affected. - if ((($config['enable_queue_trigger'] && $user->data['user_posts'] < $config['queue_trigger_posts']) || !$auth->acl_get('f_noapprove', $data['forum_id'])) && !$auth->acl_get('m_approve', $data['forum_id'])) + // Check the permissions for post approval. Moderators are not affected. + if (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) { + // Post not approved, but in queue $post_approval = 0; } + // Mods are able to force approved/unapproved posts. True means the post is approved, false the post is unapproved + if (isset($data['force_approved_state'])) + { + $post_approval = ($data['force_approved_state']) ? 1 : 0; + } + // Start the transaction here $db->sql_transaction('begin'); @@ -2119,7 +2186,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u else { // insert attachment into db - if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . basename($orphan_rows[$attach_row['attach_id']]['physical_filename']))) + if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename']))) { continue; } @@ -2423,7 +2490,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u } // Index message contents - if ($update_message && $data['enable_indexing']) + if ($update_search_index && $data['enable_indexing']) { // Select the search method and do some additional checks to ensure it can actually be utilised $search_type = basename($config['search_type']); @@ -2475,7 +2542,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u // Mark this topic as read // We do not use post_time here, this is intended (post_time can have a date in the past if editing a message) - markread('topic', $data['forum_id'], $data['topic_id'], time()); + markread('topic', (($topic_type == POST_GLOBAL) ? 0 : $data['forum_id']), $data['topic_id'], time()); // if ($config['load_db_lastread'] && $user->data['is_registered']) @@ -2483,7 +2550,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u $sql = 'SELECT mark_time FROM ' . FORUMS_TRACK_TABLE . ' WHERE user_id = ' . $user->data['user_id'] . ' - AND forum_id = ' . $data['forum_id']; + AND forum_id = ' . (($topic_type == POST_GLOBAL) ? 0 : $data['forum_id']); $result = $db->sql_query($sql); $f_mark_time = (int) $db->sql_fetchfield('mark_time'); $db->sql_freeresult($result); @@ -2496,14 +2563,23 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u if (($config['load_db_lastread'] && $user->data['is_registered']) || $config['load_anon_lastread'] || $user->data['is_registered']) { // Update forum info - $sql = 'SELECT forum_last_post_time - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $data['forum_id']; + if ($topic_type == POST_GLOBAL) + { + $sql = 'SELECT MAX(topic_last_post_time) as forum_last_post_time + FROM ' . TOPICS_TABLE . ' + WHERE forum_id = 0'; + } + else + { + $sql = 'SELECT forum_last_post_time + FROM ' . FORUMS_TABLE . ' + WHERE forum_id = ' . $data['forum_id']; + } $result = $db->sql_query($sql); $forum_last_post_time = (int) $db->sql_fetchfield('forum_last_post_time'); $db->sql_freeresult($result); - update_forum_tracking_info($data['forum_id'], $forum_last_post_time, $f_mark_time, false); + update_forum_tracking_info((($topic_type == POST_GLOBAL) ? 0 : $data['forum_id']), $forum_last_post_time, $f_mark_time, false); } // Send Notifications diff --git a/phpBB/includes/functions_privmsgs.php b/phpBB/includes/functions_privmsgs.php index 05653f7e3b..848218ca83 100644 --- a/phpBB/includes/functions_privmsgs.php +++ b/phpBB/includes/functions_privmsgs.php @@ -1145,8 +1145,7 @@ function write_pm_addresses($check_ary, $author_id, $plaintext = false) { $sql = 'SELECT user_id, username, user_colour FROM ' . USERS_TABLE . ' - WHERE ' . $db->sql_in_set('user_id', $u) . ' - AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')'; + WHERE ' . $db->sql_in_set('user_id', $u); $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) @@ -1356,6 +1355,12 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true) while ($row = $db->sql_fetchrow($result)) { + // Additionally, do not include the sender if he is in the group he wants to send to. ;) + if ($row['user_id'] === $user->data['user_id']) + { + continue; + } + $field = ($data['address_list']['g'][$row['group_id']] == 'to') ? 'to' : 'bcc'; $recipients[$row['user_id']] = $field; } @@ -1405,7 +1410,8 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true) 'bbcode_bitfield' => $data['bbcode_bitfield'], 'bbcode_uid' => $data['bbcode_uid'], 'to_address' => implode(':', $to), - 'bcc_address' => implode(':', $bcc) + 'bcc_address' => implode(':', $bcc), + 'message_reported' => 0, ); break; @@ -1545,7 +1551,7 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true) else { // insert attachment into db - if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . basename($orphan_rows[$attach_row['attach_id']]['physical_filename']))) + if (!@file_exists($phpbb_root_path . $config['upload_path'] . '/' . utf8_basename($orphan_rows[$attach_row['attach_id']]['physical_filename']))) { continue; } @@ -1691,14 +1697,34 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode { global $db, $user, $config, $template, $phpbb_root_path, $phpEx, $auth, $bbcode; + // Select all receipts and the author from the pm we currently view, to only display their pm-history + $sql = 'SELECT author_id, user_id + FROM ' . PRIVMSGS_TO_TABLE . " + WHERE msg_id = $msg_id + AND folder_id <> " . PRIVMSGS_HOLD_BOX; + $result = $db->sql_query($sql); + + $recipients = array(); + while ($row = $db->sql_fetchrow($result)) + { + $recipients[] = (int) $row['user_id']; + $recipients[] = (int) $row['author_id']; + } + $db->sql_freeresult($result); + $recipients = array_unique($recipients); + // Get History Messages (could be newer) $sql = 'SELECT t.*, p.*, u.* FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . ' t, ' . USERS_TABLE . ' u WHERE t.msg_id = p.msg_id AND p.author_id = u.user_id - AND t.folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ") + AND t.folder_id NOT IN (' . PRIVMSGS_NO_BOX . ', ' . PRIVMSGS_HOLD_BOX . ') + AND ' . $db->sql_in_set('t.author_id', $recipients, false, true) . " AND t.user_id = $user_id"; + // We no longer need those. + unset($recipients); + if (!$message_row['root_level']) { $sql .= " AND (p.root_level = $msg_id OR (p.root_level = 0 AND p.msg_id = $msg_id))"; @@ -1781,7 +1807,7 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode $decoded_message = false; - if ($in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS && $author_id != $user->data['user_id']) + if ($in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) { $decoded_message = $message; decode_message($decoded_message, $row['bbcode_uid']); @@ -1824,10 +1850,10 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode 'MSG_ID' => $row['msg_id'], 'U_VIEW_MESSAGE' => "$url&f=$folder_id&p=" . $row['msg_id'], - 'U_QUOTE' => (!$in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS && $author_id != $user->data['user_id']) ? "$url&mode=compose&action=quote&f=" . $folder_id . "&p=" . $row['msg_id'] : '', + 'U_QUOTE' => (!$in_post_mode && $auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&mode=compose&action=quote&f=" . $folder_id . "&p=" . $row['msg_id'] : '', 'U_POST_REPLY_PM' => ($author_id != $user->data['user_id'] && $author_id != ANONYMOUS && $auth->acl_get('u_sendpm')) ? "$url&mode=compose&action=reply&f=$folder_id&p=" . $row['msg_id'] : '') ); - unset($rowset[$id]); + unset($rowset[$i]); $prev_id = $id; } @@ -1863,4 +1889,93 @@ function set_user_message_limit() $user->data['message_limit'] = (!$message_limit) ? $config['pm_max_msgs'] : $message_limit; } +/** +* Generates an array of coloured recipient names from a list of PMs - (groups & users) +* +* @param array $pm_by_id An array of rows from PRIVMSGS_TABLE, keys are the msg_ids. +* +* @return array 2D Array: array(msg_id => array('username or group string', ...), ...) +* Usernames are generated with {@link get_username_string get_username_string} +* Groups are coloured and have a link to the membership page +*/ +function get_recipient_strings($pm_by_id) +{ + global $user, $db; + + $address_list = $recipient_list = $address = array(); + + $_types = array('u', 'g'); + + foreach ($pm_by_id as $message_id => $row) + { + $address[$message_id] = rebuild_header(array('to' => $row['to_address'], 'bcc' => $row['bcc_address'])); + + foreach ($_types as $ug_type) + { + if (isset($address[$message_id][$ug_type]) && sizeof($address[$message_id][$ug_type])) + { + foreach ($address[$message_id][$ug_type] as $ug_id => $in_to) + { + $recipient_list[$ug_type][$ug_id] = array('name' => $user->lang['NA'], 'colour' => ''); + } + } + } + } + + foreach ($_types as $ug_type) + { + if (!empty($recipient_list[$ug_type])) + { + if ($ug_type == 'u') + { + $sql = 'SELECT user_id as id, username as name, user_colour as colour + FROM ' . USERS_TABLE . ' + WHERE '; + } + else + { + $sql = 'SELECT group_id as id, group_name as name, group_colour as colour, group_type + FROM ' . GROUPS_TABLE . ' + WHERE '; + } + $sql .= $db->sql_in_set(($ug_type == 'u') ? 'user_id' : 'group_id', array_map('intval', array_keys($recipient_list[$ug_type]))); + + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + if ($ug_type == 'g') + { + $row['name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['name']] : $row['name']; + } + + $recipient_list[$ug_type][$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']); + } + $db->sql_freeresult($result); + } + } + + foreach ($address as $message_id => $adr_ary) + { + foreach ($adr_ary as $type => $id_ary) + { + foreach ($id_ary as $ug_id => $_id) + { + if ($type == 'u') + { + $address_list[$message_id][] = get_username_string('full', $ug_id, $recipient_list[$type][$ug_id]['name'], $recipient_list[$type][$ug_id]['colour']); + } + else + { + $user_colour = ($recipient_list[$type][$ug_id]['colour']) ? ' style="font-weight: bold; color:#' . $recipient_list[$type][$ug_id]['colour'] . '"' : ''; + $link = ''; + $address_list[$message_id][] = $link . $recipient_list[$type][$ug_id]['name'] . (($link) ? '' : ''); + } + } + } + } + + return $address_list; +} + ?> \ No newline at end of file diff --git a/phpBB/includes/functions_profile_fields.php b/phpBB/includes/functions_profile_fields.php index 26a1feb126..9e356414a9 100644 --- a/phpBB/includes/functions_profile_fields.php +++ b/phpBB/includes/functions_profile_fields.php @@ -90,18 +90,6 @@ class custom_profile */ function validate_profile_field($field_type, &$field_value, $field_data) { - switch ($field_type) - { - case FIELD_INT: - case FIELD_DROPDOWN: - $field_value = (int) $field_value; - break; - - case FIELD_BOOL: - $field_value = (bool) $field_value; - break; - } - switch ($field_type) { case FIELD_DATE: @@ -133,6 +121,8 @@ class custom_profile break; case FIELD_BOOL: + $field_value = (bool) $field_value; + if (!$field_value && $field_data['field_required']) { return 'FIELD_REQUIRED'; @@ -140,10 +130,12 @@ class custom_profile break; case FIELD_INT: - if (empty($field_value) && !$field_data['field_required']) + if (trim($field_value) === '' && !$field_data['field_required']) { return false; } + + $field_value = (int) $field_value; if ($field_value < $field_data['field_minlen']) { @@ -156,6 +148,8 @@ class custom_profile break; case FIELD_DROPDOWN: + $field_value = (int) $field_value; + if ($field_value == $field_data['field_novalue'] && $field_data['field_required']) { return 'FIELD_REQUIRED'; @@ -259,7 +253,7 @@ class custom_profile } /** - * Submit profile field + * Submit profile field for validation * @access public */ function submit_cp_field($mode, $lang_id, &$cp_data, &$cp_error) @@ -349,6 +343,66 @@ class custom_profile $db->sql_freeresult($result); } + /** + * Update profile field data directly + */ + function update_profile_field_data($user_id, &$cp_data) + { + global $db; + + if (!sizeof($cp_data)) + { + return; + } + + switch ($db->sql_layer) + { + case 'oracle': + case 'firebird': + case 'postgres': + $right_delim = $left_delim = '"'; + break; + + case 'sqlite': + case 'mssql': + case 'mssql_odbc': + $right_delim = ']'; + $left_delim = '['; + break; + + case 'mysql': + case 'mysql4': + case 'mysqli': + $right_delim = $left_delim = '`'; + break; + } + + // use new array for the UPDATE; changes in the key do not affect the original array + $cp_data_sql = array(); + foreach ($cp_data as $key => $value) + { + // Firebird is case sensitive with delimiter + $cp_data_sql[$left_delim . (($db->sql_layer == 'firebird' || $db->sql_layer == 'oracle') ? strtoupper($key) : $key) . $right_delim] = $value; + } + + $sql = 'UPDATE ' . PROFILE_FIELDS_DATA_TABLE . ' + SET ' . $db->sql_build_array('UPDATE', $cp_data_sql) . " + WHERE user_id = $user_id"; + $db->sql_query($sql); + + if (!$db->sql_affectedrows()) + { + $cp_data_sql['user_id'] = (int) $user_id; + + $db->sql_return_on_error(true); + + $sql = 'INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $cp_data_sql); + $db->sql_query($sql); + + $db->sql_return_on_error(false); + } + } + /** * Assign fields to template, used for viewprofile, viewtopic and memberlist (if load setting is enabled) * This is directly connected to the user -> mode == grab is to grab the user specific fields, mode == show is for assigning the row to the template @@ -454,7 +508,7 @@ class custom_profile switch ($this->profile_types[$field_type]) { case 'int': - if ($value == '') + if ($value === '') { return NULL; } @@ -584,7 +638,7 @@ class custom_profile } } - return (is_null($value)) ? '' : (int) $value; + return (is_null($value) || $value === '') ? '' : (int) $value; } else { diff --git a/phpBB/includes/functions_template.php b/phpBB/includes/functions_template.php index 42a5eb3248..1d3a4d74f8 100644 --- a/phpBB/includes/functions_template.php +++ b/phpBB/includes/functions_template.php @@ -128,9 +128,9 @@ class template_compile $php_blocks = $matches[1]; $code = preg_replace('#.*?#s', '', $code); - preg_match_all('##', $code, $matches); + preg_match_all('##', $code, $matches); $include_blocks = $matches[1]; - $code = preg_replace('##', '', $code); + $code = preg_replace('##', '', $code); preg_match_all('##', $code, $matches); $includephp_blocks = $matches[1]; @@ -193,8 +193,39 @@ class template_compile case 'INCLUDE': $temp = array_shift($include_blocks); + + // Dynamic includes + // Cheap match rather than a full blown regexp, we already know + // the format of the input so just use string manipulation. + if ($temp[0] == '{') + { + $file = false; + + if ($temp[1] == '$') + { + $var = substr($temp, 2, -1); + //$file = $this->template->_tpldata['DEFINE']['.'][$var]; + $temp = "\$this->_tpldata['DEFINE']['.']['$var']"; + } + else + { + $var = substr($temp, 1, -1); + //$file = $this->template->_rootref[$var]; + $temp = "\$this->_rootref['$var']"; + } + } + else + { + $file = $temp; + } + $compile_blocks[] = 'compile_tag_include($temp) . ' ?>'; - $this->template->_tpl_include($temp, false); + + // No point in checking variable includes + if ($file) + { + $this->template->_tpl_include($file, false); + } break; case 'INCLUDEPHP': @@ -220,15 +251,22 @@ class template_compile $template_php .= (!$no_echo) ? (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : '') : (($trim_check_text != '') ? $text_blocks[$i] : '') . ((isset($compile_blocks[$i])) ? $compile_blocks[$i] : ''); } + // Remove unused opening/closing tags + $template_php = str_replace(' ?>([\r\n])#', '?>\1\1', $template_php); + // There will be a number of occasions where we switch into and out of // PHP mode instantaneously. Rather than "burden" the parser with this // we'll strip out such occurences, minimising such switching if ($no_echo) { - return "\$$echo_var .= '" . str_replace(' ?>_tpl_include($tag_args); }"; + } + return "\$this->_tpl_include('$tag_args');"; } @@ -603,7 +647,7 @@ class template_compile */ function compile_tag_include_php($tag_args) { - return "include('" . $tag_args . "');"; + return "\$this->_php_include('$tag_args');"; } /** diff --git a/phpBB/includes/functions_transfer.php b/phpBB/includes/functions_transfer.php index c345f81e1d..046abede8e 100644 --- a/phpBB/includes/functions_transfer.php +++ b/phpBB/includes/functions_transfer.php @@ -316,15 +316,15 @@ class ftp extends transfer return 'ERR_CONNECTING_SERVER'; } - // attempt to turn pasv mode on - @ftp_pasv($this->connection, true); - // login to the server if (!@ftp_login($this->connection, $this->username, $this->password)) { return 'ERR_UNABLE_TO_LOGIN'; } + // attempt to turn pasv mode on + @ftp_pasv($this->connection, true); + // change to the root directory if (!$this->_chdir($this->root_path)) { @@ -462,6 +462,20 @@ class ftp extends transfer { $list = @ftp_nlist($this->connection, $dir); + // See bug #46295 - Some FTP daemons don't like './' + if ($dir === './') + { + // Let's try some alternatives + $list = (empty($list)) ? @ftp_nlist($this->connection, '.') : $list; + $list = (empty($list)) ? @ftp_nlist($this->connection, '') : $list; + } + + // Return on error + if ($list === false) + { + return false; + } + // Remove path if prepended foreach ($list as $key => $item) { @@ -469,7 +483,7 @@ class ftp extends transfer $item = str_replace('\\', '/', $item); $dir = str_replace('\\', '/', $dir); - if (strpos($item, $dir) === 0) + if (!empty($dir) && strpos($item, $dir) === 0) { $item = substr($item, strlen($dir)); } @@ -723,13 +737,32 @@ class ftp_fsock extends transfer $list = array(); while (!@feof($this->data_connection)) { - $list[] = preg_replace('#[\r\n]#', '', @fgets($this->data_connection, 512)); + $filename = preg_replace('#[\r\n]#', '', @fgets($this->data_connection, 512)); + + if ($filename !== '') + { + $list[] = $filename; + } } $this->_close_data_connection(); // Clear buffer $this->_check_command(); + // See bug #46295 - Some FTP daemons don't like './' + if ($dir === './' && empty($list)) + { + // Let's try some alternatives + $list = $this->_ls('.'); + + if (empty($list)) + { + $list = $this->_ls(''); + } + + return $list; + } + // Remove path if prepended foreach ($list as $key => $item) { @@ -737,7 +770,7 @@ class ftp_fsock extends transfer $item = str_replace('\\', '/', $item); $dir = str_replace('\\', '/', $dir); - if (strpos($item, $dir) === 0) + if (!empty($dir) && strpos($item, $dir) === 0) { $item = substr($item, strlen($dir)); } @@ -826,7 +859,7 @@ class ftp_fsock extends transfer $result = @fgets($this->connection, 512); $response .= $result; } - while (substr($response, 3, 1) != ' '); + while (substr($result, 3, 1) !== ' '); if (!preg_match('#^[123]#', $response)) { diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php index 1ad6223aa1..a7abb06674 100644 --- a/phpBB/includes/functions_upload.php +++ b/phpBB/includes/functions_upload.php @@ -58,7 +58,7 @@ class filespec $this->filename = $upload_ary['tmp_name']; $this->filesize = $upload_ary['size']; - $name = trim(htmlspecialchars(basename($upload_ary['name']))); + $name = trim(utf8_htmlspecialchars(utf8_basename($upload_ary['name']))); $this->realname = $this->uploadname = (STRIP) ? stripslashes($name) : $name; $this->mimetype = $upload_ary['type']; @@ -290,7 +290,7 @@ class filespec $upload_mode = (@ini_get('open_basedir') || @ini_get('safe_mode') || strtolower(@ini_get('safe_mode')) == 'on') ? 'move' : 'copy'; $upload_mode = ($this->local) ? 'local' : $upload_mode; - $this->destination_file = $this->destination_path . '/' . basename($this->realname); + $this->destination_file = $this->destination_path . '/' . utf8_basename($this->realname); // Check if the file already exist, else there is something wrong... if (file_exists($this->destination_file) && !$overwrite) @@ -313,12 +313,9 @@ class filespec if (!@move_uploaded_file($this->filename, $this->destination_file)) { $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file); - return false; } } - @unlink($this->filename); - break; case 'move': @@ -328,12 +325,9 @@ class filespec if (!@copy($this->filename, $this->destination_file)) { $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file); - return false; } } - @unlink($this->filename); - break; case 'local': @@ -341,14 +335,21 @@ class filespec if (!@copy($this->filename, $this->destination_file)) { $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'GENERAL_UPLOAD_ERROR'], $this->destination_file); - return false; } - @unlink($this->filename); break; } + // Remove temporary filename + @unlink($this->filename); + + if (sizeof($this->error)) + { + return false; + } + phpbb_chmod($this->destination_file, $chmod); + return true; } // Try to get real filesize from destination folder @@ -417,10 +418,9 @@ class filespec // Filesize is too big or it's 0 if it was larger than the maxsize in the upload form if ($this->upload->max_filesize && ($this->get('filesize') > $this->upload->max_filesize || $this->filesize == 0)) { - $size_lang = ($this->upload->max_filesize >= 1048576) ? $user->lang['MIB'] : (($this->upload->max_filesize >= 1024) ? $user->lang['KIB'] : $user->lang['BYTES'] ); $max_filesize = get_formatted_filesize($this->upload->max_filesize, false); - $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'WRONG_FILESIZE'], $max_filesize, $size_lang); + $this->error[] = sprintf($user->lang[$this->upload->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']); return false; } @@ -635,7 +635,7 @@ class fileupload if ($filedata === false) { - $_FILES[$form_name]['name'] = basename($source_file); + $_FILES[$form_name]['name'] = utf8_basename($source_file); $_FILES[$form_name]['size'] = 0; $mimetype = ''; @@ -747,7 +747,7 @@ class fileupload $ext = array_pop($url['path']); $url['path'] = implode('', $url['path']); - $upload_ary['name'] = basename($url['path']) . (($ext) ? '.' . $ext : ''); + $upload_ary['name'] = utf8_basename($url['path']) . (($ext) ? '.' . $ext : ''); $filename = $url['path']; $filesize = 0; @@ -855,10 +855,9 @@ class fileupload break; case 2: - $size_lang = ($this->max_filesize >= 1048576) ? $user->lang['MIB'] : (($this->max_filesize >= 1024) ? $user->lang['KIB'] : $user->lang['BYTES']); $max_filesize = get_formatted_filesize($this->max_filesize, false); - $error = sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize, $size_lang); + $error = sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']); break; case 3: @@ -891,10 +890,9 @@ class fileupload // Filesize is too big or it's 0 if it was larger than the maxsize in the upload form if ($this->max_filesize && ($file->get('filesize') > $this->max_filesize || $file->get('filesize') == 0)) { - $size_lang = ($this->max_filesize >= 1048576) ? $user->lang['MIB'] : (($this->max_filesize >= 1024) ? $user->lang['KIB'] : $user->lang['BYTES']); $max_filesize = get_formatted_filesize($this->max_filesize, false); - $file->error[] = sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize, $size_lang); + $file->error[] = sprintf($user->lang[$this->error_prefix . 'WRONG_FILESIZE'], $max_filesize['value'], $max_filesize['unit']); } // check Filename diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php index 027db39751..7255d138ab 100644 --- a/phpBB/includes/functions_user.php +++ b/phpBB/includes/functions_user.php @@ -171,7 +171,7 @@ function user_add($user_row, $cp_data = false) 'user_password' => (isset($user_row['user_password'])) ? $user_row['user_password'] : '', 'user_pass_convert' => 0, 'user_email' => strtolower($user_row['user_email']), - 'user_email_hash' => crc32(strtolower($user_row['user_email'])) . strlen($user_row['user_email']), + 'user_email_hash' => phpbb_email_hash($user_row['user_email']), 'group_id' => $user_row['group_id'], 'user_type' => $user_row['user_type'], ); @@ -187,7 +187,9 @@ function user_add($user_row, $cp_data = false) 'user_ip' => '', 'user_regdate' => time(), 'user_passchg' => time(), - 'user_options' => 895, + 'user_options' => 230271, + // We do not set the new flag here - registration scripts need to specify it + 'user_new' => 0, 'user_inactive_reason' => 0, 'user_inactive_time' => 0, @@ -275,8 +277,38 @@ function user_add($user_row, $cp_data = false) // Now make it the users default group... group_set_user_default($user_row['group_id'], array($user_id), false); + // Add to newly registered users group if user_new is 1 + if ($config['new_member_post_limit'] && $sql_ary['user_new']) + { + $sql = 'SELECT group_id + FROM ' . GROUPS_TABLE . " + WHERE group_name = 'NEWLY_REGISTERED' + AND group_type = " . GROUP_SPECIAL; + $result = $db->sql_query($sql); + $add_group_id = (int) $db->sql_fetchfield('group_id'); + $db->sql_freeresult($result); + + if ($add_group_id) + { + // Because these actions only fill the log unneccessarily we skip the add_log() entry with a little hack. :/ + $GLOBALS['skip_add_log'] = true; + + // Add user to "newly registered users" group and set to default group if admin specified so. + if ($config['new_member_group_default']) + { + group_user_add($add_group_id, $user_id, false, false, true); + } + else + { + group_user_add($add_group_id, $user_id); + } + + unset($GLOBALS['skip_add_log']); + } + } + // set the newest user and adjust the user count if the user is a normal user and no activation mail is sent - if ($user_row['user_type'] == USER_NORMAL) + if ($user_row['user_type'] == USER_NORMAL || $user_row['user_type'] == USER_FOUNDER) { set_config('newest_user_id', $user_id, true); set_config('newest_username', $user_row['username'], true); @@ -421,6 +453,11 @@ function user_delete($mode, $user_id, $post_username = false) WHERE topic_last_poster_id = $user_id"; $db->sql_query($sql); + $sql = 'UPDATE ' . ATTACHMENTS_TABLE . ' + SET poster_id = ' . ANONYMOUS . " + WHERE poster_id = $user_id"; + $db->sql_query($sql); + // Since we change every post by this author, we need to count this amount towards the anonymous user // Update the post count for the anonymous user @@ -501,6 +538,23 @@ function user_delete($mode, $user_id, $post_username = false) $cache->destroy('sql', MODERATOR_CACHE_TABLE); + // Delete user log entries about this user + $sql = 'DELETE FROM ' . LOG_TABLE . ' + WHERE reportee_id = ' . $user_id; + $db->sql_query($sql); + + // Change user_id to anonymous for this users triggered events + $sql = 'UPDATE ' . LOG_TABLE . ' + SET user_id = ' . ANONYMOUS . ' + WHERE user_id = ' . $user_id; + $db->sql_query($sql); + + // Delete the user_id from the zebra table + $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' + WHERE user_id = ' . $user_id . ' + OR zebra_id = ' . $user_id; + $db->sql_query($sql); + // Delete the user_id from the banlist $sql = 'DELETE FROM ' . BANLIST_TABLE . ' WHERE ban_userid = ' . $user_id; @@ -904,7 +958,8 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas } } } - else + + if (empty($banlist_ary)) { trigger_error('NO_IPS_DEFINED'); } @@ -977,7 +1032,17 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas } while ($row = $db->sql_fetchrow($result)); - $banlist_ary = array_unique(array_diff($banlist_ary, $banlist_ary_tmp)); + $banlist_ary_tmp = array_intersect($banlist_ary, $banlist_ary_tmp); + + if (sizeof($banlist_ary_tmp)) + { + // One or more entities are already banned/excluded, delete the existing bans, so they can be re-inserted with the given new length + $sql = 'DELETE FROM ' . BANLIST_TABLE . ' + WHERE ' . $db->sql_in_set($type, $banlist_ary_tmp) . ' + AND ban_exclude = ' . (int) $ban_exclude; + $db->sql_query($sql); + } + unset($banlist_ary_tmp); } $db->sql_freeresult($result); @@ -1060,9 +1125,16 @@ function user_ban($mode, $ban, $ban_len, $ban_len_other, $ban_exclude, $ban_reas // Update log $log_entry = ($ban_exclude) ? 'LOG_BAN_EXCLUDE_' : 'LOG_BAN_'; - // Add to moderator and admin log + // Add to moderator log, admin log and user notes add_log('admin', $log_entry . strtoupper($mode), $ban_reason, $ban_list_log); add_log('mod', 0, 0, $log_entry . strtoupper($mode), $ban_reason, $ban_list_log); + if ($mode == 'user') + { + foreach ($banlist_ary as $user_id) + { + add_log('user', $user_id, $log_entry . strtoupper($mode), $ban_reason, $ban_list_log); + } + } $cache->destroy('sql', BANLIST_TABLE); @@ -1101,7 +1173,7 @@ function user_unban($mode, $ban) switch ($mode) { case 'user': - $sql = 'SELECT u.username AS unban_info + $sql = 'SELECT u.username AS unban_info, u.user_id FROM ' . USERS_TABLE . ' u, ' . BANLIST_TABLE . ' b WHERE ' . $db->sql_in_set('b.ban_id', $unban_sql) . ' AND u.user_id = b.ban_userid'; @@ -1122,9 +1194,14 @@ function user_unban($mode, $ban) $result = $db->sql_query($sql); $l_unban_list = ''; + $user_ids_ary = array(); while ($row = $db->sql_fetchrow($result)) { $l_unban_list .= (($l_unban_list != '') ? ', ' : '') . $row['unban_info']; + if ($mode == 'user') + { + $user_ids_ary[] = $row['user_id']; + } } $db->sql_freeresult($result); @@ -1132,9 +1209,16 @@ function user_unban($mode, $ban) WHERE ' . $db->sql_in_set('ban_id', $unban_sql); $db->sql_query($sql); - // Add to moderator and admin log + // Add to moderator log, admin log and user notes add_log('admin', 'LOG_UNBAN_' . strtoupper($mode), $l_unban_list); add_log('mod', 0, 0, 'LOG_UNBAN_' . strtoupper($mode), $l_unban_list); + if ($mode == 'user') + { + foreach ($user_ids_ary as $user_id) + { + add_log('user', $user_id, 'LOG_UNBAN_' . strtoupper($mode), $l_unban_list); + } + } } $cache->destroy('sql', BANLIST_TABLE); @@ -1643,7 +1727,7 @@ function validate_email($email, $allowed_email = false) { $sql = 'SELECT user_email_hash FROM ' . USERS_TABLE . " - WHERE user_email_hash = " . (crc32($email) . strlen($email)); + WHERE user_email_hash = " . $db->sql_escape(phpbb_email_hash($email)); $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); @@ -2077,8 +2161,8 @@ function avatar_gallery($category, $avatar_select, $items_per_column, $block_var if (preg_match('#^[^&\'"<>]+\.(?:gif|png|jpe?g)$#i', $sub_file)) { $avatar_list[$file][$avatar_row_count][$avatar_col_count] = array( - 'file' => "$file/$sub_file", - 'filename' => $sub_file, + 'file' => rawurlencode($file) . '/' . rawurlencode($sub_file), + 'filename' => rawurlencode($sub_file), 'name' => ucfirst(str_replace('_', ' ', preg_replace('#^(.*)\..*$#', '\1', $sub_file))), ); $avatar_col_count++; @@ -2365,24 +2449,9 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow global $phpbb_root_path, $config, $db, $user, $file_upload; $error = array(); - $attribute_ary = array( - 'group_colour' => 'string', - 'group_rank' => 'int', - 'group_avatar' => 'string', - 'group_avatar_type' => 'int', - 'group_avatar_width' => 'int', - 'group_avatar_height' => 'int', - 'group_receive_pm' => 'int', - 'group_legend' => 'int', - 'group_message_limit' => 'int', - 'group_max_recipients' => 'int', - - 'group_founder_manage' => 'int', - ); - - // Those are group-only attributes - $group_only_ary = array('group_receive_pm', 'group_legend', 'group_message_limit', 'group_max_recipients', 'group_founder_manage'); + // Attributes which also affect the users table + $user_attribute_ary = array('group_colour', 'group_rank', 'group_avatar', 'group_avatar_type', 'group_avatar_width', 'group_avatar_height'); // Check data. Limit group name length. if (!utf8_strlen($name) || utf8_strlen($name) > 60) @@ -2420,14 +2489,8 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow if (sizeof($group_attributes)) { - foreach ($attribute_ary as $attribute => $_type) - { - if (isset($group_attributes[$attribute])) - { - settype($group_attributes[$attribute], $_type); - $sql_ary[$attribute] = $group_attributes[$attribute]; - } - } + // Merge them with $sql_ary to properly update the group + $sql_ary = array_merge($sql_ary, $group_attributes); } // Setting the log message before we set the group id (if group gets added) @@ -2452,6 +2515,7 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow { remove_default_avatar($group_id, $user_ary); } + if (isset($sql_ary['group_rank']) && !$sql_ary['group_rank']) { remove_default_rank($group_id, $user_ary); @@ -2467,6 +2531,32 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow SET group_name = '" . $db->sql_escape($sql_ary['group_name']) . "' WHERE group_id = $group_id"; $db->sql_query($sql); + + // One special case is the group skip auth setting. If this was changed we need to purge permissions for this group + if (isset($group_attributes['group_skip_auth'])) + { + // Get users within this group... + $sql = 'SELECT user_id + FROM ' . USER_GROUP_TABLE . ' + WHERE group_id = ' . $group_id . ' + AND user_pending = 0'; + $result = $db->sql_query($sql); + + $user_id_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $user_id_ary[] = $row['user_id']; + } + $db->sql_freeresult($result); + + if (!empty($user_id_ary)) + { + global $auth; + + // Clear permissions cache of relevant users + $auth->acl_clear_prefetch($user_id_ary); + } + } } else { @@ -2477,6 +2567,7 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow if (!$group_id) { $group_id = $db->sql_nextid(); + if (isset($sql_ary['group_avatar_type']) && $sql_ary['group_avatar_type'] == AVATAR_UPLOAD) { group_correct_avatar($group_id, $sql_ary['group_avatar']); @@ -2487,18 +2578,21 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow $sql_ary = array(); if (sizeof($group_attributes)) { - foreach ($attribute_ary as $attribute => $_type) + // Go through the user attributes array, check if a group attribute matches it and then set it. ;) + foreach ($user_attribute_ary as $attribute) { - if (isset($group_attributes[$attribute]) && !in_array($attribute, $group_only_ary)) + if (!isset($group_attributes[$attribute])) { - // If we are about to set an avatar, we will not overwrite user avatars if no group avatar is set... - if (strpos($attribute, 'group_avatar') === 0 && !$group_attributes[$attribute]) - { - continue; - } - - $sql_ary[$attribute] = $group_attributes[$attribute]; + continue; } + + // If we are about to set an avatar, we will not overwrite user avatars if no group avatar is set... + if (strpos($attribute, 'group_avatar') === 0 && !$group_attributes[$attribute]) + { + continue; + } + + $sql_ary[$attribute] = $group_attributes[$attribute]; } } @@ -2702,7 +2796,7 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false, if ($default) { - group_set_user_default($group_id, $user_id_ary, $group_attributes); + group_user_attributes('default', $group_id, $user_id_ary, false, $group_name, $group_attributes); } $db->sql_transaction('commit'); @@ -2715,7 +2809,7 @@ function group_user_add($group_id, $user_id_ary = false, $username_ary = false, $group_name = get_group_name($group_id); } - $log = ($leader) ? 'LOG_MODS_ADDED' : 'LOG_USERS_ADDED'; + $log = ($leader) ? 'LOG_MODS_ADDED' : (($pending) ? 'LOG_USERS_PENDING' : 'LOG_USERS_ADDED'); add_log('admin', $log, $group_name, implode(', ', $username_ary)); @@ -2826,7 +2920,7 @@ function group_user_del($group_id, $user_id_ary = false, $username_ary = false, { if (isset($sql_where_ary[$gid]) && sizeof($sql_where_ary[$gid])) { - remove_default_rank($gid, $sql_where_ary[$gid]); + remove_default_rank($group_id, $sql_where_ary[$gid]); remove_default_avatar($group_id, $sql_where_ary[$gid]); group_set_user_default($gid, $sql_where_ary[$gid], $default_data_ary); } @@ -2848,7 +2942,10 @@ function group_user_del($group_id, $user_id_ary = false, $username_ary = false, $log = 'LOG_GROUP_REMOVE'; - add_log('admin', $log, $group_name, implode(', ', $username_ary)); + if ($group_name) + { + add_log('admin', $log, $group_name, implode(', ', $username_ary)); + } group_update_listings($group_id); @@ -3038,6 +3135,27 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna break; case 'default': + // We only set default group for approved members of the group + $sql = 'SELECT user_id + FROM ' . USER_GROUP_TABLE . " + WHERE group_id = $group_id + AND user_pending = 0 + AND " . $db->sql_in_set('user_id', $user_id_ary); + $result = $db->sql_query($sql); + + $user_id_ary = $username_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $user_id_ary[] = $row['user_id']; + } + $db->sql_freeresult($result); + + $result = user_get_id_name($user_id_ary, $username_ary); + if (!sizeof($user_id_ary) || $result !== false) + { + return 'NO_USERS'; + } + $sql = 'SELECT user_id, group_id FROM ' . USERS_TABLE . ' WHERE ' . $db->sql_in_set('user_id', $user_id_ary, false, true); $result = $db->sql_query($sql); @@ -3126,7 +3244,7 @@ function group_validate_groupname($group_id, $group_name) */ function group_set_user_default($group_id, $user_id_ary, $group_attributes = false, $update_listing = false) { - global $db; + global $cache, $db; if (empty($user_id_ary)) { @@ -3226,6 +3344,9 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal { group_update_listings($group_id); } + + // Because some tables/caches use usercolour-specific data we need to purge this here. + $cache->destroy('sql', MODERATOR_CACHE_TABLE); } /** @@ -3242,7 +3363,7 @@ function get_group_name($group_id) $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - if (!$row) + if (!$row || ($row['group_type'] == GROUP_SPECIAL && empty($user->lang))) { return ''; } @@ -3385,4 +3506,77 @@ function group_update_listings($group_id) } } + + +/** +* Funtion to make a user leave the NEWLY_REGISTERED system group. +* @access public +* @param $user_id The id of the user to remove from the group +*/ +function remove_newly_registered($user_id, $user_data = false) +{ + global $db; + + if ($user_data === false) + { + $sql = 'SELECT * + FROM ' . USERS_TABLE . ' + WHERE user_id = ' . $user_id; + $result = $db->sql_query($sql); + $user_row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if (!$user_row) + { + return false; + } + else + { + $user_data = $user_row; + } + } + + if (empty($user_data['user_new'])) + { + return false; + } + + $sql = 'SELECT group_id + FROM ' . GROUPS_TABLE . " + WHERE group_name = 'NEWLY_REGISTERED' + AND group_type = " . GROUP_SPECIAL; + $result = $db->sql_query($sql); + $group_id = (int) $db->sql_fetchfield('group_id'); + $db->sql_freeresult($result); + + if (!$group_id) + { + return false; + } + + // We need to call group_user_del here, because this function makes sure everything is correctly changed. + // A downside for a call within the session handler is that the language is not set up yet - so no log entry + group_user_del($group_id, $user_id); + + // Set user_new to 0 to let this not be triggered again + $sql = 'UPDATE ' . USERS_TABLE . ' + SET user_new = 0 + WHERE user_id = ' . $user_id; + $db->sql_query($sql); + + // The new users group was the users default group? + if ($user_data['group_id'] == $group_id) + { + // Which group is now the users default one? + $sql = 'SELECT group_id + FROM ' . USERS_TABLE . ' + WHERE user_id = ' . $user_id; + $result = $db->sql_query($sql); + $user_data['group_id'] = $db->sql_fetchfield('group_id'); + $db->sql_freeresult($result); + } + + return $user_data['group_id']; +} + ?> \ No newline at end of file diff --git a/phpBB/includes/mcp/info/mcp_pm_reports.php b/phpBB/includes/mcp/info/mcp_pm_reports.php new file mode 100644 index 0000000000..103f560597 --- /dev/null +++ b/phpBB/includes/mcp/info/mcp_pm_reports.php @@ -0,0 +1,39 @@ + 'mcp_pm_reports', + 'title' => 'MCP_PM_REPORTS', + 'version' => '1.0.0', + 'modes' => array( + 'pm_reports' => array('title' => 'MCP_PM_REPORTS_OPEN', 'auth' => 'aclf_m_report', 'cat' => array('MCP_REPORTS')), + 'pm_reports_closed' => array('title' => 'MCP_PM_REPORTS_CLOSED', 'auth' => 'aclf_m_report', 'cat' => array('MCP_REPORTS')), + 'pm_report_details' => array('title' => 'MCP_PM_REPORT_DETAILS', 'auth' => 'aclf_m_report', 'cat' => array('MCP_REPORTS')), + ), + ); + } + + function install() + { + } + + function uninstall() + { + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index b70601b479..acb7aa4ac0 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -416,11 +416,14 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id) // If the topic no longer exist, we will update the topic watch table. // To not let it error out on users watching both topics, we just return on an error... + // Same for Bookmarks $db->sql_return_on_error(true); $db->sql_query('UPDATE ' . TOPICS_WATCH_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); + $db->sql_query('UPDATE ' . BOOKMARKS_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); $db->sql_return_on_error(false); $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); + $db->sql_query('DELETE FROM ' . BOOKMARKS_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids)); // Link to the new topic $return_link .= (($return_link) ? '

    ' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); diff --git a/phpBB/includes/mcp/mcp_front.php b/phpBB/includes/mcp/mcp_front.php index 05c1b796ac..50e14b9336 100644 --- a/phpBB/includes/mcp/mcp_front.php +++ b/phpBB/includes/mcp/mcp_front.php @@ -34,7 +34,7 @@ function mcp_front_view($id, $mode, $action) $forum_id = request_var('f', 0); $template->assign_var('S_SHOW_UNAPPROVED', (!empty($forum_list)) ? true : false); - + if (!empty($forum_list)) { $sql = 'SELECT COUNT(post_id) AS total @@ -119,7 +119,12 @@ function mcp_front_view($id, $mode, $action) $db->sql_freeresult($result); } + $s_hidden_fields = build_hidden_fields(array( + 'redirect' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=main' . (($forum_id) ? '&f=' . $forum_id : '')) + )); + $template->assign_vars(array( + 'S_HIDDEN_FIELDS' => $s_hidden_fields, 'S_MCP_QUEUE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue"), )); @@ -152,6 +157,7 @@ function mcp_front_view($id, $mode, $action) $sql = 'SELECT COUNT(r.report_id) AS total FROM ' . REPORTS_TABLE . ' r, ' . POSTS_TABLE . ' p WHERE r.post_id = p.post_id + AND r.pm_id = 0 AND r.report_closed = 0 AND p.forum_id IN (0, ' . implode(', ', $forum_list) . ')'; $result = $db->sql_query($sql); @@ -181,6 +187,7 @@ function mcp_front_view($id, $mode, $action) ), 'WHERE' => 'r.post_id = p.post_id + AND r.pm_id = 0 AND r.report_closed = 0 AND r.reason_id = rr.reason_id AND p.topic_id = t.topic_id @@ -243,6 +250,96 @@ function mcp_front_view($id, $mode, $action) } } + // Latest 5 reported PMs + if ($module->loaded('pm_reports') && $auth->acl_getf_global('m_report')) + { + $template->assign_var('S_SHOW_PM_REPORTS', true); + $user->add_lang(array('ucp')); + + $sql = 'SELECT COUNT(r.report_id) AS total + FROM ' . REPORTS_TABLE . ' r, ' . PRIVMSGS_TABLE . ' p + WHERE r.post_id = 0 + AND r.pm_id = p.msg_id + AND r.report_closed = 0'; + $result = $db->sql_query($sql); + $total = (int) $db->sql_fetchfield('total'); + $db->sql_freeresult($result); + + if ($total) + { + include($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); + + $sql = $db->sql_build_query('SELECT', array( + 'SELECT' => 'r.report_id, r.report_time, p.msg_id, p.message_subject, p.message_time, p.to_address, p.bcc_address, u.username, u.username_clean, u.user_colour, u.user_id, u2.username as author_name, u2.username_clean as author_name_clean, u2.user_colour as author_colour, u2.user_id as author_id', + + 'FROM' => array( + REPORTS_TABLE => 'r', + REPORTS_REASONS_TABLE => 'rr', + USERS_TABLE => array('u', 'u2'), + PRIVMSGS_TABLE => 'p' + ), + + 'WHERE' => 'r.pm_id = p.msg_id + AND r.post_id = 0 + AND r.report_closed = 0 + AND r.reason_id = rr.reason_id + AND r.user_id = u.user_id + AND p.author_id = u2.user_id', + + 'ORDER_BY' => 'p.message_time DESC' + )); + $result = $db->sql_query_limit($sql, 5); + + $pm_by_id = $pm_list = array(); + while ($row = $db->sql_fetchrow($result)) + { + $pm_by_id[(int) $row['msg_id']] = $row; + $pm_list[] = (int) $row['msg_id']; + } + + $address_list = get_recipient_strings($pm_by_id); + + foreach ($pm_list as $message_id) + { + $row = $pm_by_id[$message_id]; + + $template->assign_block_vars('pm_report', array( + 'U_PM_DETAILS' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'r=' . $row['report_id'] . "&i=pm_reports&mode=pm_report_details"), + + 'REPORTER_FULL' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour']), + 'REPORTER' => get_username_string('username', $row['user_id'], $row['username'], $row['user_colour']), + 'REPORTER_COLOUR' => get_username_string('colour', $row['user_id'], $row['username'], $row['user_colour']), + 'U_REPORTER' => get_username_string('profile', $row['user_id'], $row['username'], $row['user_colour']), + + 'PM_AUTHOR_FULL' => get_username_string('full', $row['author_id'], $row['author_name'], $row['author_colour']), + 'PM_AUTHOR' => get_username_string('username', $row['author_id'], $row['author_name'], $row['author_colour']), + 'PM_AUTHOR_COLOUR' => get_username_string('colour', $row['author_id'], $row['author_name'], $row['author_colour']), + 'U_PM_AUTHOR' => get_username_string('profile', $row['author_id'], $row['author_name'], $row['author_colour']), + + 'PM_SUBJECT' => $row['message_subject'], + 'REPORT_TIME' => $user->format_date($row['report_time']), + 'PM_TIME' => $user->format_date($row['message_time']), + 'RECIPIENTS' => implode(', ', $address_list[$row['msg_id']]), + )); + } + } + + if ($total == 0) + { + $template->assign_vars(array( + 'L_PM_REPORTS_TOTAL' => $user->lang['PM_REPORTS_ZERO_TOTAL'], + 'S_HAS_PM_REPORTS' => false) + ); + } + else + { + $template->assign_vars(array( + 'L_PM_REPORTS_TOTAL' => ($total == 1) ? $user->lang['PM_REPORT_TOTAL'] : sprintf($user->lang['PM_REPORTS_TOTAL'], $total), + 'S_HAS_PM_REPORTS' => true) + ); + } + } + // Latest 5 logs if ($module->loaded('logs')) { diff --git a/phpBB/includes/mcp/mcp_logs.php b/phpBB/includes/mcp/mcp_logs.php index a6b1935c88..429e19b668 100644 --- a/phpBB/includes/mcp/mcp_logs.php +++ b/phpBB/includes/mcp/mcp_logs.php @@ -164,15 +164,18 @@ class mcp_logs $sql_where = ($sort_days) ? (time() - ($sort_days * 86400)) : 0; $sql_sort = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); + $keywords = utf8_normalize_nfc(request_var('keywords', '', true)); + $keywords_param = !empty($keywords) ? '&keywords=' . urlencode(htmlspecialchars_decode($keywords)) : ''; + // Grab log data $log_data = array(); $log_count = 0; - view_log('mod', $log_data, $log_count, $config['topics_per_page'], $start, $forum_list, $topic_id, 0, $sql_where, $sql_sort); + view_log('mod', $log_data, $log_count, $config['topics_per_page'], $start, $forum_list, $topic_id, 0, $sql_where, $sql_sort, $keywords); $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", $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, true), 'L_TITLE' => $user->lang['MCP_LOGS'], @@ -182,13 +185,14 @@ class mcp_logs 'S_SELECT_SORT_KEY' => $s_sort_key, 'S_SELECT_SORT_DAYS' => $s_limit_days, 'S_LOGS' => ($log_count > 0), + 'S_KEYWORDS' => $keywords, ) ); foreach ($log_data as $row) { $data = array(); - + $checks = array('viewtopic', 'viewforum'); foreach ($checks as $check) { diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index 0dfe3b0086..6c2ac0b521 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -1064,7 +1064,9 @@ function mcp_fork_topic($topic_ids) 'topic_bumper' => (int) $topic_row['topic_bumper'], 'poll_title' => (string) $topic_row['poll_title'], 'poll_start' => (int) $topic_row['poll_start'], - 'poll_length' => (int) $topic_row['poll_length'] + 'poll_length' => (int) $topic_row['poll_length'], + 'poll_max_options' => (int) $topic_row['poll_max_options'], + 'poll_vote_change' => (int) $topic_row['poll_vote_change'], ); $db->sql_query('INSERT INTO ' . TOPICS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); @@ -1166,8 +1168,8 @@ function mcp_fork_topic($topic_ids) 'in_message' => 0, 'is_orphan' => (int) $attach_row['is_orphan'], 'poster_id' => (int) $attach_row['poster_id'], - 'physical_filename' => (string) basename($attach_row['physical_filename']), - 'real_filename' => (string) basename($attach_row['real_filename']), + 'physical_filename' => (string) utf8_basename($attach_row['physical_filename']), + 'real_filename' => (string) utf8_basename($attach_row['real_filename']), 'download_count' => (int) $attach_row['download_count'], 'attach_comment' => (string) $attach_row['attach_comment'], 'extension' => (string) $attach_row['extension'], diff --git a/phpBB/includes/mcp/mcp_notes.php b/phpBB/includes/mcp/mcp_notes.php index 7480b24a46..757860e1af 100644 --- a/phpBB/includes/mcp/mcp_notes.php +++ b/phpBB/includes/mcp/mcp_notes.php @@ -193,9 +193,12 @@ class mcp_notes $sql_where = ($st) ? (time() - ($st * 86400)) : 0; $sql_sort = $sort_by_sql[$sk] . ' ' . (($sd == 'd') ? 'DESC' : 'ASC'); + $keywords = utf8_normalize_nfc(request_var('keywords', '', true)); + $keywords_param = !empty($keywords) ? '&keywords=' . urlencode(htmlspecialchars_decode($keywords)) : ''; + $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); + view_log('user', $log_data, $log_count, $config['posts_per_page'], $start, 0, 0, $user_id, $sql_where, $sql_sort, $keywords); if ($log_count) { @@ -219,11 +222,12 @@ class mcp_notes 'S_SELECT_SORT_DIR' => $s_sort_dir, 'S_SELECT_SORT_KEY' => $s_sort_key, 'S_SELECT_SORT_DAYS' => $s_limit_days, + 'S_KEYWORDS' => $keywords, 'L_TITLE' => $user->lang['MCP_NOTES_USER'], 'PAGE_NUMBER' => on_page($log_count, $config['posts_per_page'], $start), - 'PAGINATION' => generate_pagination($this->u_action . "&st=$st&sk=$sk&sd=$sd", $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), '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_pm_reports.php b/phpBB/includes/mcp/mcp_pm_reports.php new file mode 100644 index 0000000000..72f77fae7c --- /dev/null +++ b/phpBB/includes/mcp/mcp_pm_reports.php @@ -0,0 +1,323 @@ +p_master = &$p_master; + } + + function main($id, $mode) + { + global $auth, $db, $user, $template, $cache; + global $config, $phpbb_root_path, $phpEx, $action; + + include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx); + include_once($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx); + + $start = request_var('start', 0); + + $this->page_title = 'MCP_PM_REPORTS'; + + switch ($action) + { + case 'close': + case 'delete': + include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx); + + $report_id_list = request_var('report_id_list', array(0)); + + if (!sizeof($report_id_list)) + { + trigger_error('NO_REPORT_SELECTED'); + } + + if (!function_exists('close_report')) + { + include($phpbb_root_path . 'includes/mcp/mcp_reports.' . $phpEx); + } + + close_report($report_id_list, $mode, $action, true); + + break; + } + + switch ($mode) + { + case 'pm_report_details': + + $user->add_lang(array('posting', 'viewforum', 'viewtopic', 'ucp')); + + $report_id = request_var('r', 0); + + $sql = 'SELECT r.pm_id, r.user_id, r.report_id, r.report_closed, report_time, r.report_text, rr.reason_title, rr.reason_description, u.username, u.username_clean, u.user_colour + FROM ' . REPORTS_TABLE . ' r, ' . REPORTS_REASONS_TABLE . ' rr, ' . USERS_TABLE . ' u + WHERE r.report_id = ' . $report_id . ' + AND rr.reason_id = r.reason_id + AND r.user_id = u.user_id + AND r.post_id = 0 + ORDER BY report_closed ASC'; + $result = $db->sql_query_limit($sql, 1); + $report = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if (!$report_id || !$report) + { + trigger_error('NO_REPORT'); + } + + $pm_id = $report['pm_id']; + $report_id = $report['report_id']; + + $pm_info = get_pm_data(array($pm_id)); + + if (!sizeof($pm_info)) + { + trigger_error('NO_REPORT_SELECTED'); + } + + $pm_info = $pm_info[$pm_id]; + + write_pm_addresses(array('to' => $pm_info['to_address'], 'bcc' => $pm_info['bcc_address']), (int) $pm_info['author_id']); + + $reason = array('title' => $report['reason_title'], 'description' => $report['reason_description']); + if (isset($user->lang['report_reasons']['TITLE'][strtoupper($reason['title'])]) && isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($reason['title'])])) + { + $reason['description'] = $user->lang['report_reasons']['DESCRIPTION'][strtoupper($reason['title'])]; + $reason['title'] = $user->lang['report_reasons']['TITLE'][strtoupper($reason['title'])]; + } + + // Process message, leave it uncensored + $message = $pm_info['message_text']; + + if ($pm_info['bbcode_bitfield']) + { + include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx); + $bbcode = new bbcode($pm_info['bbcode_bitfield']); + $bbcode->bbcode_second_pass($message, $pm_info['bbcode_uid'], $pm_info['bbcode_bitfield']); + } + + $message = bbcode_nl2br($message); + $message = smiley_text($message); + + if ($pm_info['message_attachment'] && $auth->acl_get('u_pm_download')) + { + $sql = 'SELECT * + FROM ' . ATTACHMENTS_TABLE . ' + WHERE post_msg_id = ' . $pm_id . ' + AND in_message = 1 + ORDER BY filetime DESC'; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + $attachments[] = $row; + } + $db->sql_freeresult($result); + + if (sizeof($attachments)) + { + $update_count = array(); + parse_attachments(0, $message, $attachments, $update_count); + } + + // Display not already displayed Attachments for this post, we already parsed them. ;) + if (!empty($attachments)) + { + $template->assign_var('S_HAS_ATTACHMENTS', true); + + foreach ($attachments as $attachment) + { + $template->assign_block_vars('attachment', array( + 'DISPLAY_ATTACHMENT' => $attachment) + ); + } + } + } + + $template->assign_vars(array( + 'S_MCP_REPORT' => true, + 'S_PM' => true, + 'S_CLOSE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=pm_reports&mode=pm_report_details&r=' . $report_id), + 'S_CAN_VIEWIP' => $auth->acl_getf_global('m_info'), + 'S_POST_REPORTED' => $pm_info['message_reported'], + 'S_USER_NOTES' => true, + + 'U_MCP_REPORT' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=pm_reports&mode=pm_report_details&r=' . $report_id), + 'U_MCP_REPORTER_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $report['user_id']), + 'U_MCP_USER_NOTES' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $pm_info['author_id']), + 'U_MCP_WARN_REPORTER' => ($auth->acl_get('m_warn')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_user&u=' . $report['user_id']) : '', + 'U_MCP_WARN_USER' => ($auth->acl_get('m_warn')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_user&u=' . $pm_info['author_id']) : '', + + 'EDIT_IMG' => $user->img('icon_post_edit', $user->lang['EDIT_POST']), + 'MINI_POST_IMG' => $user->img('icon_post_target', 'POST'), + + 'RETURN_REPORTS' => sprintf($user->lang['RETURN_REPORTS'], '', ''), + 'REPORTED_IMG' => $user->img('icon_topic_reported', $user->lang['POST_REPORTED']), + 'REPORT_DATE' => $user->format_date($report['report_time']), + 'REPORT_ID' => $report_id, + 'REPORT_REASON_TITLE' => $reason['title'], + 'REPORT_REASON_DESCRIPTION' => $reason['description'], + 'REPORT_TEXT' => $report['report_text'], + + 'POST_AUTHOR_FULL' => get_username_string('full', $pm_info['author_id'], $pm_info['username'], $pm_info['user_colour']), + 'POST_AUTHOR_COLOUR' => get_username_string('colour', $pm_info['author_id'], $pm_info['username'], $pm_info['user_colour']), + 'POST_AUTHOR' => get_username_string('username', $pm_info['author_id'], $pm_info['username'], $pm_info['user_colour']), + 'U_POST_AUTHOR' => get_username_string('profile', $pm_info['author_id'], $pm_info['username'], $pm_info['user_colour']), + + 'REPORTER_FULL' => get_username_string('full', $report['user_id'], $report['username'], $report['user_colour']), + 'REPORTER_COLOUR' => get_username_string('colour', $report['user_id'], $report['username'], $report['user_colour']), + 'REPORTER_NAME' => get_username_string('username', $report['user_id'], $report['username'], $report['user_colour']), + 'U_VIEW_REPORTER_PROFILE' => get_username_string('profile', $report['user_id'], $report['username'], $report['user_colour']), + + 'POST_PREVIEW' => $message, + 'POST_SUBJECT' => ($pm_info['message_subject']) ? $pm_info['message_subject'] : $user->lang['NO_SUBJECT'], + 'POST_DATE' => $user->format_date($pm_info['message_time']), + 'POST_IP' => $pm_info['author_ip'], + 'POST_IPADDR' => ($auth->acl_getf_global('m_info') && request_var('lookup', '')) ? @gethostbyaddr($pm_info['author_ip']) : '', + 'POST_ID' => $pm_info['msg_id'], + + 'U_LOOKUP_IP' => ($auth->acl_getf_global('m_info')) ? $this->u_action . '&r=' . $report_id . '&pm=' . $pm_id . '&lookup=' . $pm_info['author_ip'] . '#ip' : '', + )); + + $this->tpl_name = 'mcp_post'; + + break; + + case 'pm_reports': + case 'pm_reports_closed': + $user->add_lang(array('ucp')); + + $sort_days = $total = 0; + $sort_key = $sort_dir = ''; + $sort_by_sql = $sort_order_sql = array(); + mcp_sorting($mode, $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total); + + $limit_time_sql = ($sort_days) ? 'AND r.report_time >= ' . (time() - ($sort_days * 86400)) : ''; + + if ($mode == 'pm_reports') + { + $report_state = 'p.message_reported = 1 AND r.report_closed = 0'; + } + else + { + $report_state = 'r.report_closed = 1'; + } + + $sql = 'SELECT r.report_id + FROM ' . PRIVMSGS_TABLE . ' p, ' . REPORTS_TABLE . ' r ' . (($sort_order_sql[0] == 'u') ? ', ' . USERS_TABLE . ' u' : '') . (($sort_order_sql[0] == 'r') ? ', ' . USERS_TABLE . ' ru' : '') . " + WHERE $report_state + AND r.pm_id = p.msg_id + " . (($sort_order_sql[0] == 'u') ? 'AND u.user_id = p.author_id' : '') . ' + ' . (($sort_order_sql[0] == 'r') ? 'AND ru.user_id = r.user_id' : '') . " + AND r.post_id = 0 + $limit_time_sql + ORDER BY $sort_order_sql"; + $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); + + $i = 0; + $report_ids = array(); + while ($row = $db->sql_fetchrow($result)) + { + $report_ids[] = $row['report_id']; + $row_num[$row['report_id']] = $i++; + } + $db->sql_freeresult($result); + + if (sizeof($report_ids)) + { + $sql = 'SELECT p.*, u.username, u.username_clean, u.user_colour, r.user_id as reporter_id, ru.username as reporter_name, ru.user_colour as reporter_colour, r.report_time, r.report_id + FROM ' . REPORTS_TABLE . ' r, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . ' u, ' . USERS_TABLE . ' ru + WHERE ' . $db->sql_in_set('r.report_id', $report_ids) . " + AND r.pm_id = p.msg_id + AND p.author_id = u.user_id + AND ru.user_id = r.user_id + ORDER BY $sort_order_sql"; + $result = $db->sql_query($sql); + + $pm_list = $pm_by_id = array(); + while ($row = $db->sql_fetchrow($result)) + { + $pm_by_id[(int) $row['msg_id']] = $row; + $pm_list[] = (int) $row['msg_id']; + } + $db->sql_freeresult($result); + + if (sizeof($pm_list)) + { + $address_list = get_recipient_strings($pm_by_id); + + foreach ($pm_list as $message_id) + { + $row = $pm_by_id[$message_id]; + $template->assign_block_vars('postrow', array( + 'U_VIEW_DETAILS' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=pm_reports&mode=pm_report_details&r={$row['report_id']}"), + + 'PM_AUTHOR_FULL' => get_username_string('full', $row['author_id'], $row['username'], $row['user_colour']), + 'PM_AUTHOR_COLOUR' => get_username_string('colour', $row['author_id'], $row['username'], $row['user_colour']), + 'PM_AUTHOR' => get_username_string('username', $row['author_id'], $row['username'], $row['user_colour']), + 'U_PM_AUTHOR' => get_username_string('profile', $row['author_id'], $row['username'], $row['user_colour']), + + 'REPORTER_FULL' => get_username_string('full', $row['reporter_id'], $row['reporter_name'], $row['reporter_colour']), + 'REPORTER_COLOUR' => get_username_string('colour', $row['reporter_id'], $row['reporter_name'], $row['reporter_colour']), + 'REPORTER' => get_username_string('username', $row['reporter_id'], $row['reporter_name'], $row['reporter_colour']), + 'U_REPORTER' => get_username_string('profile', $row['reporter_id'], $row['reporter_name'], $row['reporter_colour']), + + 'PM_SUBJECT' => ($row['message_subject']) ? $row['message_subject'] : $user->lang['NO_SUBJECT'], + 'PM_TIME' => $user->format_date($row['message_time']), + 'REPORT_ID' => $row['report_id'], + 'REPORT_TIME' => $user->format_date($row['report_time']), + + 'RECIPIENTS' => implode(', ', $address_list[$row['msg_id']]), + )); + } + } + } + + // Now display the page + $template->assign_vars(array( + 'L_EXPLAIN' => ($mode == 'pm_reports') ? $user->lang['MCP_PM_REPORTS_OPEN_EXPLAIN'] : $user->lang['MCP_PM_REPORTS_CLOSED_EXPLAIN'], + 'L_TITLE' => ($mode == 'pm_reports') ? $user->lang['MCP_PM_REPORTS_OPEN'] : $user->lang['MCP_PM_REPORTS_CLOSED'], + + 'S_PM' => true, + 'S_MCP_ACTION' => $this->u_action, + 'S_CLOSED' => ($mode == 'pm_reports_closed') ? true : false, + + 'PAGINATION' => generate_pagination($this->u_action . "&st=$sort_days&sk=$sort_key&sd=$sort_dir", $total, $config['topics_per_page'], $start), + 'PAGE_NUMBER' => on_page($total, $config['topics_per_page'], $start), + 'TOTAL' => $total, + 'TOTAL_REPORTS' => ($total == 1) ? $user->lang['LIST_REPORT'] : sprintf($user->lang['LIST_REPORTS'], $total), + ) + ); + + $this->tpl_name = 'mcp_reports'; + break; + } + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/mcp/mcp_queue.php b/phpBB/includes/mcp/mcp_queue.php index 6209a27bf7..3783aadab5 100644 --- a/phpBB/includes/mcp/mcp_queue.php +++ b/phpBB/includes/mcp/mcp_queue.php @@ -491,11 +491,9 @@ function approve_post($post_id_list, $id, $mode) // If Post -> total_posts = total_posts+1, forum_posts = forum_posts+1, topic_replies = topic_replies+1 $total_topics = $total_posts = 0; - $forum_topics_posts = $topic_approve_sql = $topic_replies_sql = $post_approve_sql = $topic_id_list = $forum_id_list = $approve_log = array(); + $topic_approve_sql = $post_approve_sql = $topic_id_list = $forum_id_list = $approve_log = array(); $user_posts_sql = $post_approved_list = array(); - $update_forum_information = false; - foreach ($post_info as $post_id => $post_data) { if ($post_data['post_approved']) @@ -523,16 +521,7 @@ function approve_post($post_id_list, $id, $mode) { if ($post_data['forum_id']) { - if (!isset($forum_topics_posts[$post_data['forum_id']])) - { - $forum_topics_posts[$post_data['forum_id']] = array( - 'forum_posts' => 0, - 'forum_topics' => 0 - ); - } - $total_topics++; - $forum_topics_posts[$post_data['forum_id']]['forum_topics']++; } $topic_approve_sql[] = $post_data['topic_id']; @@ -553,45 +542,21 @@ function approve_post($post_id_list, $id, $mode) ); } - if ($post_data['topic_replies_real'] > 0) - { - if (!isset($topic_replies_sql[$post_data['topic_id']])) - { - $topic_replies_sql[$post_data['topic_id']] = 0; - } - $topic_replies_sql[$post_data['topic_id']]++; - } - if ($post_data['forum_id']) { - if (!isset($forum_topics_posts[$post_data['forum_id']])) - { - $forum_topics_posts[$post_data['forum_id']] = array( - 'forum_posts' => 0, - 'forum_topics' => 0 - ); - } - $total_posts++; - $forum_topics_posts[$post_data['forum_id']]['forum_posts']++; // Increment by topic_replies if we approve a topic... // This works because we do not adjust the topic_replies when re-approving a topic after an edit. if ($post_data['topic_first_post_id'] == $post_id && $post_data['topic_replies']) { $total_posts += $post_data['topic_replies']; - $forum_topics_posts[$post_data['forum_id']]['forum_posts'] += $post_data['topic_replies']; } } $post_approve_sql[] = $post_id; - - // If the post is newer than the last post information stored we need to update the forum information - if ($post_data['post_time'] >= $post_data['forum_last_post_time']) - { - $update_forum_information = true; - } } + $post_id_list = array_values(array_diff($post_id_list, $post_approved_list)); for ($i = 0, $size = sizeof($post_approved_list); $i < $size; $i++) { @@ -614,37 +579,13 @@ function approve_post($post_id_list, $id, $mode) $db->sql_query($sql); } + unset($topic_approve_sql, $post_approve_sql); + foreach ($approve_log as $log_data) { add_log('mod', $log_data['forum_id'], $log_data['topic_id'], ($log_data['type'] == 'topic') ? 'LOG_TOPIC_APPROVED' : 'LOG_POST_APPROVED', $log_data['post_subject']); } - if (sizeof($topic_replies_sql)) - { - foreach ($topic_replies_sql as $topic_id => $num_replies) - { - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_replies = topic_replies + $num_replies - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - } - } - - if (sizeof($forum_topics_posts)) - { - foreach ($forum_topics_posts as $forum_id => $row) - { - $sql = 'UPDATE ' . FORUMS_TABLE . ' - SET '; - $sql .= ($row['forum_topics']) ? "forum_topics = forum_topics + {$row['forum_topics']}" : ''; - $sql .= ($row['forum_topics'] && $row['forum_posts']) ? ', ' : ''; - $sql .= ($row['forum_posts']) ? "forum_posts = forum_posts + {$row['forum_posts']}" : ''; - $sql .= " WHERE forum_id = $forum_id"; - - $db->sql_query($sql); - } - } - if (sizeof($user_posts_sql)) { // Try to minimize the query count by merging users with the same post count additions @@ -673,14 +614,9 @@ function approve_post($post_id_list, $id, $mode) { set_config_count('num_posts', $total_posts, true); } - unset($topic_approve_sql, $topic_replies_sql, $post_approve_sql); - update_post_information('topic', array_keys($topic_id_list)); - - if ($update_forum_information) - { - update_post_information('forum', array_keys($forum_id_list)); - } + sync('topic', 'topic_id', array_keys($topic_id_list), true); + sync('forum', 'forum_id', array_keys($forum_id_list), true, true); unset($topic_id_list, $forum_id_list); $messenger = new messenger(); @@ -859,89 +795,63 @@ function disapprove_post($post_id_list, $id, $mode) if (confirm_box(true)) { + $disapprove_log = $disapprove_log_topics = $disapprove_log_posts = array(); + $topic_replies_real = $post_disapprove_list = array(); - // If Topic -> forum_topics_real -= 1 - // If Post -> topic_replies_real -= 1 - - $num_disapproved = 0; - $forum_topics_real = $topic_id_list = $forum_id_list = $topic_replies_real_sql = $post_disapprove_sql = $disapprove_log = array(); - + // Build a list of posts to be unapproved and get the related topics real replies count foreach ($post_info as $post_id => $post_data) { - $topic_id_list[$post_data['topic_id']] = 1; - - if ($post_data['forum_id']) + $post_disapprove_list[$post_id] = $post_data['topic_id']; + if (!isset($topic_replies_real[$post_data['topic_id']])) { - $forum_id_list[$post_data['forum_id']] = 1; + $topic_replies_real[$post_data['topic_id']] = $post_data['topic_replies_real']; } + } - // Topic or Post. ;) - /** - * @todo this probably is a different method than the one used by delete_posts, does this cause counter inconsistency? - */ - if ($post_data['topic_first_post_id'] == $post_id && $post_data['topic_last_post_id'] == $post_id) + // Now we build the log array + foreach ($post_disapprove_list as $post_id => $topic_id) + { + // If the count of disapproved posts for the topic is greater + // than topic's real replies count, the whole topic is disapproved/deleted + if (sizeof(array_keys($post_disapprove_list, $topic_id)) > $topic_replies_real[$topic_id]) { - if ($post_data['forum_id']) + // Don't write the log more than once for every topic + if (!isset($disapprove_log_topics[$topic_id])) { - if (!isset($forum_topics_real[$post_data['forum_id']])) - { - $forum_topics_real[$post_data['forum_id']] = 0; - } - $forum_topics_real[$post_data['forum_id']]++; - $num_disapproved++; + // Build disapproved topics log + $disapprove_log_topics[$topic_id] = array( + 'type' => 'topic', + 'post_subject' => $post_info[$post_id]['topic_title'], + 'forum_id' => $post_info[$post_id]['forum_id'], + 'topic_id' => 0, // useless to log a topic id, as it will be deleted + ); } - - $disapprove_log[] = array( - 'type' => 'topic', - 'post_subject' => $post_data['post_subject'], - 'forum_id' => $post_data['forum_id'], - 'topic_id' => 0, // useless to log a topic id, as it will be deleted - ); } else { - if (!isset($topic_replies_real_sql[$post_data['topic_id']])) - { - $topic_replies_real_sql[$post_data['topic_id']] = 0; - } - $topic_replies_real_sql[$post_data['topic_id']]++; - - $disapprove_log[] = array( + // Build disapproved posts log + $disapprove_log_posts[] = array( 'type' => 'post', - 'post_subject' => $post_data['post_subject'], - 'forum_id' => $post_data['forum_id'], - 'topic_id' => $post_data['topic_id'], + 'post_subject' => $post_info[$post_id]['post_subject'], + 'forum_id' => $post_info[$post_id]['forum_id'], + 'topic_id' => $post_info[$post_id]['topic_id'], ); - } - $post_disapprove_sql[] = $post_id; - } - - unset($post_data); - - if (sizeof($forum_topics_real)) - { - foreach ($forum_topics_real as $forum_id => $topics_real) - { - $sql = 'UPDATE ' . FORUMS_TABLE . " - SET forum_topics_real = forum_topics_real - $topics_real - WHERE forum_id = $forum_id"; - $db->sql_query($sql); } } - if (sizeof($topic_replies_real_sql)) - { - foreach ($topic_replies_real_sql as $topic_id => $num_replies) - { - $sql = 'UPDATE ' . TOPICS_TABLE . " - SET topic_replies_real = topic_replies_real - $num_replies - WHERE topic_id = $topic_id"; - $db->sql_query($sql); - } - } + // Get disapproved posts/topics counts separately + $num_disapproved_topics = sizeof($disapprove_log_topics); + $num_disapproved_posts = sizeof($disapprove_log_posts); - if (sizeof($post_disapprove_sql)) + // Build the whole log + $disapprove_log = array_merge($disapprove_log_topics, $disapprove_log_posts); + + // Unset unneeded arrays + unset($post_data, $disapprove_log_topics, $disapprove_log_posts); + + // Let's do the job - delete disapproved posts + if (sizeof($post_disapprove_list)) { if (!function_exists('delete_posts')) { @@ -949,22 +859,15 @@ function disapprove_post($post_id_list, $id, $mode) } // We do not check for permissions here, because the moderator allowed approval/disapproval should be allowed to delete the disapproved posts - delete_posts('post_id', $post_disapprove_sql); + // Note: function delete_posts triggers related forums/topics sync, + // so we don't need to call update_post_information later and to adjust real topic replies or forum topics count manually + delete_posts('post_id', array_keys($post_disapprove_list)); foreach ($disapprove_log as $log_data) { add_log('mod', $log_data['forum_id'], $log_data['topic_id'], ($log_data['type'] == 'topic') ? 'LOG_TOPIC_DISAPPROVED' : 'LOG_POST_DISAPPROVED', $log_data['post_subject'], $disapprove_reason); } } - unset($post_disapprove_sql, $topic_replies_real_sql); - - update_post_information('topic', array_keys($topic_id_list)); - - if (sizeof($forum_id_list)) - { - update_post_information('forum', array_keys($forum_id_list)); - } - unset($topic_id_list, $forum_id_list); $messenger = new messenger(); @@ -993,7 +896,7 @@ function disapprove_post($post_id_list, $id, $mode) { // Load up the language pack $lang = array(); - @include($phpbb_root_path . '/language/' . $post_data['user_lang'] . '/mcp.' . $phpEx); + @include($phpbb_root_path . '/language/' . basename($post_data['user_lang']) . '/mcp.' . $phpEx); // If we find the reason in this language pack use it if (isset($lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang])) @@ -1032,13 +935,13 @@ function disapprove_post($post_id_list, $id, $mode) $messenger->save_queue(); - if (sizeof($forum_topics_real)) + if ($num_disapproved_topics) { - $success_msg = ($num_disapproved == 1) ? 'TOPIC_DISAPPROVED_SUCCESS' : 'TOPICS_DISAPPROVED_SUCCESS'; + $success_msg = ($num_disapproved_topics == 1) ? 'TOPIC_DISAPPROVED_SUCCESS' : 'TOPICS_DISAPPROVED_SUCCESS'; } else { - $success_msg = (sizeof($post_id_list) == 1) ? 'POST_DISAPPROVED_SUCCESS' : 'POSTS_DISAPPROVED_SUCCESS'; + $success_msg = ($num_disapproved_posts == 1) ? 'POST_DISAPPROVED_SUCCESS' : 'POSTS_DISAPPROVED_SUCCESS'; } } else diff --git a/phpBB/includes/mcp/mcp_reports.php b/phpBB/includes/mcp/mcp_reports.php index 27d841c81b..270b0055d9 100644 --- a/phpBB/includes/mcp/mcp_reports.php +++ b/phpBB/includes/mcp/mcp_reports.php @@ -77,6 +77,7 @@ class mcp_reports WHERE ' . (($report_id) ? 'r.report_id = ' . $report_id : "r.post_id = $post_id") . ' AND rr.reason_id = r.reason_id AND r.user_id = u.user_id + AND r.pm_id = 0 ORDER BY report_closed ASC'; $result = $db->sql_query_limit($sql, 1); $report = $db->sql_fetchrow($result); @@ -149,13 +150,11 @@ class mcp_reports if ($post_info['post_attachment'] && $auth->acl_get('u_download') && $auth->acl_get('f_download', $post_info['forum_id'])) { - $extensions = $cache->obtain_attach_extensions($post_info['forum_id']); - $sql = 'SELECT * FROM ' . ATTACHMENTS_TABLE . ' WHERE post_msg_id = ' . $post_id . ' AND in_message = 0 - ORDER BY filetime DESC, post_msg_id ASC'; + ORDER BY filetime DESC'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) @@ -258,7 +257,7 @@ class mcp_reports } unset($forum_list_read); - if ($topic_id && $forum_id) + if ($topic_id) { $topic_info = get_topic_data(array($topic_id)); @@ -267,12 +266,15 @@ class mcp_reports trigger_error('TOPIC_NOT_EXIST'); } - $topic_info = $topic_info[$topic_id]; - $forum_id = $topic_info['forum_id']; - } - else if ($topic_id && !$forum_id) - { - $topic_id = 0; + if ($forum_id != $topic_info[$topic_id]['forum_id']) + { + $topic_id = 0; + } + else + { + $topic_info = $topic_info[$topic_id]; + $forum_id = (int) $topic_info['forum_id']; + } } $forum_list = array(); @@ -329,7 +331,7 @@ class mcp_reports mcp_sorting($mode, $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id, $topic_id); $forum_topics = ($total == -1) ? $forum_info['forum_topics'] : $total; - $limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : ''; + $limit_time_sql = ($sort_days) ? 'AND r.report_time >= ' . (time() - ($sort_days * 86400)) : ''; if ($mode == 'reports') { @@ -346,9 +348,10 @@ class mcp_reports $report_state AND r.post_id = p.post_id " . (($sort_order_sql[0] == 'u') ? 'AND u.user_id = p.poster_id' : '') . ' - ' . (($sort_order_sql[0] == 'r') ? 'AND ru.user_id = p.poster_id' : '') . ' + ' . (($sort_order_sql[0] == 'r') ? 'AND ru.user_id = r.user_id' : '') . ' ' . (($topic_id) ? 'AND p.topic_id = ' . $topic_id : '') . " AND t.topic_id = p.topic_id + AND r.pm_id = 0 $limit_time_sql ORDER BY $sort_order_sql"; $result = $db->sql_query_limit($sql, $config['topics_per_page'], $start); @@ -371,6 +374,7 @@ class mcp_reports AND r.post_id = p.post_id AND u.user_id = p.poster_id AND ru.user_id = r.user_id + AND r.pm_id = 0 ORDER BY ' . $sort_order_sql; $result = $db->sql_query($sql); @@ -438,35 +442,54 @@ class mcp_reports /** * Closes a report */ -function close_report($report_id_list, $mode, $action) +function close_report($report_id_list, $mode, $action, $pm = false) { - global $db, $template, $user, $config; + global $db, $template, $user, $config, $auth; global $phpEx, $phpbb_root_path; - $sql = 'SELECT r.post_id - FROM ' . REPORTS_TABLE . ' r - WHERE ' . $db->sql_in_set('r.report_id', $report_id_list); + $pm_where = ($pm) ? ' AND r.post_id = 0 ' : ' AND r.pm_id = 0 '; + $id_column = ($pm) ? 'pm_id' : 'post_id'; + $module = ($pm) ? 'pm_reports' : 'reports'; + $pm_prefix = ($pm) ? 'PM_' : ''; + + $sql = "SELECT r.$id_column + FROM " . REPORTS_TABLE . ' r + WHERE ' . $db->sql_in_set('r.report_id', $report_id_list) . $pm_where; $result = $db->sql_query($sql); $post_id_list = array(); while ($row = $db->sql_fetchrow($result)) { - $post_id_list[] = $row['post_id']; + $post_id_list[] = $row[$id_column]; } $post_id_list = array_unique($post_id_list); - if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_report'))) + if ($pm) { - trigger_error('NOT_AUTHORISED'); + if (!$auth->acl_getf_global('m_report')) + { + trigger_error('NOT_AUTHORISED'); + } + } + else + { + if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_report'))) + { + trigger_error('NOT_AUTHORISED'); + } } if ($action == 'delete' && strpos($user->data['session_page'], 'mode=report_details') !== false) { $redirect = request_var('redirect', build_url(array('mode', 'r', 'quickmod')) . '&mode=reports'); } + elseif ($action == 'delete' && strpos($user->data['session_page'], 'mode=pm_report_details') !== false) + { + $redirect = request_var('redirect', build_url(array('mode', 'r', 'quickmod')) . '&mode=pm_reports'); + } else if ($action == 'close' && !request_var('r', 0)) { - $redirect = request_var('redirect', build_url(array('mode', 'p', 'quickmod')) . '&mode=reports'); + $redirect = request_var('redirect', build_url(array('mode', 'p', 'quickmod')) . '&mode=' . $module); } else { @@ -477,7 +500,7 @@ function close_report($report_id_list, $mode, $action) $topic_ids = array(); $s_hidden_fields = build_hidden_fields(array( - 'i' => 'reports', + 'i' => $module, 'mode' => $mode, 'report_id_list' => $report_id_list, 'action' => $action, @@ -486,13 +509,13 @@ function close_report($report_id_list, $mode, $action) if (confirm_box(true)) { - $post_info = get_post_data($post_id_list, 'm_report'); + $post_info = ($pm) ? get_pm_data($post_id_list) : get_post_data($post_id_list, 'm_report'); - $sql = 'SELECT r.report_id, r.post_id, r.report_closed, r.user_id, r.user_notify, u.username, u.username_clean, u.user_email, u.user_jabber, u.user_lang, u.user_notify_type - FROM ' . REPORTS_TABLE . ' r, ' . USERS_TABLE . ' u + $sql = "SELECT r.report_id, r.$id_column, r.report_closed, r.user_id, r.user_notify, u.username, u.username_clean, u.user_email, u.user_jabber, u.user_lang, u.user_notify_type + FROM " . REPORTS_TABLE . ' r, ' . USERS_TABLE . ' u WHERE ' . $db->sql_in_set('r.report_id', $report_id_list) . ' ' . (($action == 'close') ? 'AND r.report_closed = 0' : '') . ' - AND r.user_id = u.user_id'; + AND r.user_id = u.user_id' . $pm_where; $result = $db->sql_query($sql); $reports = $close_report_posts = $close_report_topics = $notify_reporters = $report_id_list = array(); @@ -503,8 +526,12 @@ function close_report($report_id_list, $mode, $action) if (!$report['report_closed']) { - $close_report_posts[] = $report['post_id']; - $close_report_topics[] = $post_info[$report['post_id']]['topic_id']; + $close_report_posts[] = $report[$id_column]; + + if (!$pm) + { + $close_report_topics[] = $post_info[$report['post_id']]['topic_id']; + } } if ($report['user_notify'] && !$report['report_closed']) @@ -519,7 +546,7 @@ function close_report($report_id_list, $mode, $action) $close_report_posts = array_unique($close_report_posts); $close_report_topics = array_unique($close_report_topics); - if (sizeof($close_report_posts)) + if (!$pm && sizeof($close_report_posts)) { // Get a list of topics that still contain reported posts $sql = 'SELECT DISTINCT topic_id @@ -558,18 +585,33 @@ function close_report($report_id_list, $mode, $action) if (sizeof($close_report_posts)) { - $sql = 'UPDATE ' . POSTS_TABLE . ' - SET post_reported = 0 - WHERE ' . $db->sql_in_set('post_id', $close_report_posts); - $db->sql_query($sql); - - if (sizeof($close_report_topics)) + if ($pm) { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_reported = 0 - WHERE ' . $db->sql_in_set('topic_id', $close_report_topics) . ' - OR ' . $db->sql_in_set('topic_moved_id', $close_report_topics); + $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' + SET message_reported = 0 + WHERE ' . $db->sql_in_set('msg_id', $close_report_posts); $db->sql_query($sql); + + if ($action == 'delete') + {echo "aha"; + delete_pm(ANONYMOUS, $close_report_posts, PRIVMSGS_INBOX); + } + } + else + { + $sql = 'UPDATE ' . POSTS_TABLE . ' + SET post_reported = 0 + WHERE ' . $db->sql_in_set('post_id', $close_report_posts); + $db->sql_query($sql); + + if (sizeof($close_report_topics)) + { + $sql = 'UPDATE ' . TOPICS_TABLE . ' + SET topic_reported = 0 + WHERE ' . $db->sql_in_set('topic_id', $close_report_topics) . ' + OR ' . $db->sql_in_set('topic_moved_id', $close_report_topics); + $db->sql_query($sql); + } } } @@ -579,7 +621,14 @@ function close_report($report_id_list, $mode, $action) foreach ($reports as $report) { - add_log('mod', $post_info[$report['post_id']]['forum_id'], $post_info[$report['post_id']]['topic_id'], 'LOG_REPORT_' . strtoupper($action) . 'D', $post_info[$report['post_id']]['post_subject']); + if ($pm) + { + add_log('mod', 0, 0, 'LOG_PM_REPORT_' . strtoupper($action) . 'D', $post_info[$report['pm_id']]['message_subject']); + } + else + { + add_log('mod', $post_info[$report['post_id']]['forum_id'], $post_info[$report['post_id']]['topic_id'], 'LOG_REPORT_' . strtoupper($action) . 'D', $post_info[$report['post_id']]['post_subject']); + } } $messenger = new messenger(); @@ -594,39 +643,53 @@ function close_report($report_id_list, $mode, $action) continue; } - $post_id = $reporter['post_id']; + $post_id = $reporter[$id_column]; - $messenger->template('report_' . $action . 'd', $reporter['user_lang']); + $messenger->template((($pm) ? 'pm_report_' : 'report_') . $action . 'd', $reporter['user_lang']); $messenger->to($reporter['user_email'], $reporter['username']); $messenger->im($reporter['user_jabber'], $reporter['username']); - $messenger->assign_vars(array( - 'USERNAME' => htmlspecialchars_decode($reporter['username']), - 'CLOSER_NAME' => htmlspecialchars_decode($user->data['username']), - 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_info[$post_id]['post_subject'])), - 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_info[$post_id]['topic_title']))) - ); + if ($pm) + { + $messenger->assign_vars(array( + 'USERNAME' => htmlspecialchars_decode($reporter['username']), + 'CLOSER_NAME' => htmlspecialchars_decode($user->data['username']), + 'PM_SUBJECT' => htmlspecialchars_decode(censor_text($post_info[$post_id]['message_subject'])), + )); + } + else + { + $messenger->assign_vars(array( + 'USERNAME' => htmlspecialchars_decode($reporter['username']), + 'CLOSER_NAME' => htmlspecialchars_decode($user->data['username']), + 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_info[$post_id]['post_subject'])), + 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_info[$post_id]['topic_title']))) + ); + } $messenger->send($reporter['user_notify_type']); } } - foreach ($post_info as $post) + if (!$pm) { - $forum_ids[$post['forum_id']] = $post['forum_id']; - $topic_ids[$post['topic_id']] = $post['topic_id']; + foreach ($post_info as $post) + { + $forum_ids[$post['forum_id']] = $post['forum_id']; + $topic_ids[$post['topic_id']] = $post['topic_id']; + } } - + unset($notify_reporters, $post_info, $reports); $messenger->save_queue(); - $success_msg = (sizeof($report_id_list) == 1) ? 'REPORT_' . strtoupper($action) . 'D_SUCCESS' : 'REPORTS_' . strtoupper($action) . 'D_SUCCESS'; + $success_msg = (sizeof($report_id_list) == 1) ? "{$pm_prefix}REPORT_" . strtoupper($action) . 'D_SUCCESS' : "{$pm_prefix}REPORTS_" . strtoupper($action) . 'D_SUCCESS'; } else { - confirm_box(false, $user->lang[strtoupper($action) . '_REPORT' . ((sizeof($report_id_list) == 1) ? '' : 'S') . '_CONFIRM'], $s_hidden_fields); + confirm_box(false, $user->lang[strtoupper($action) . "_{$pm_prefix}REPORT" . ((sizeof($report_id_list) == 1) ? '' : 'S') . '_CONFIRM'], $s_hidden_fields); } $redirect = request_var('redirect', "index.$phpEx"); @@ -639,15 +702,21 @@ function close_report($report_id_list, $mode, $action) else { meta_refresh(3, $redirect); + $return_forum = ''; - if (sizeof($forum_ids == 1)) - { - $return_forum = sprintf($user->lang['RETURN_FORUM'], '', '') . '

    '; - } $return_topic = ''; - if (sizeof($topic_ids == 1)) + + if (!$pm) { - $return_topic = sprintf($user->lang['RETURN_TOPIC'], '', '') . '

    '; + if (sizeof($forum_ids) === 1) + { + $return_forum = sprintf($user->lang['RETURN_FORUM'], '', '') . '

    '; + } + + if (sizeof($topic_ids) === 1) + { + $return_topic = sprintf($user->lang['RETURN_TOPIC'], '', '') . '

    '; + } } trigger_error($user->lang[$success_msg] . '

    ' . $return_forum . $return_topic . sprintf($user->lang['RETURN_PAGE'], "", '')); diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 576d20b466..e73cccce1e 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -301,8 +301,9 @@ function mcp_topic_view($id, $mode, $action) 'POSTS_PER_PAGE' => $posts_per_page, 'ACTION' => $action, - 'REPORTED_IMG' => $user->img('icon_topic_reported', 'POST_REPORTED', false, true), - 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED', false, true), + 'REPORTED_IMG' => $user->img('icon_topic_reported', 'POST_REPORTED'), + 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED'), + 'INFO_IMG' => $user->img('icon_post_info', 'VIEW_INFO'), 'S_MCP_ACTION' => "$url&i=$id&mode=$mode&action=$action&start=$start", 'S_FORUM_SELECT' => ($to_forum_id) ? make_forum_select($to_forum_id, false, false, true, true, true) : make_forum_select($topic_info['forum_id'], false, false, true, true, true), @@ -503,6 +504,45 @@ function split_topic($action, $topic_id, $to_forum_id, $subject) // Update forum statistics set_config_count('num_topics', 1, true); + // Add new topic to bookmarks + $bookmarks = array(); + $sql = 'SELECT user_id + FROM ' . BOOKMARKS_TABLE . ' + WHERE topic_id = ' . $topic_id; + $result = $db->sql_query($sql); + while ($row = $db->sql_fetchrow($result)) + { + $bookmarks[] = array( + 'user_id' => (int) $row['user_id'], + 'topic_id' => $to_topic_id, + ); + } + $db->sql_freeresult($result); + if (sizeof($bookmarks)) + { + $db->sql_multi_insert(BOOKMARKS_TABLE, $bookmarks); + } + + // Add new topic to watch-list + $notifications = array(); + $sql = 'SELECT user_id, notify_status + FROM ' . TOPICS_WATCH_TABLE . ' + WHERE topic_id = ' . $topic_id; + $result = $db->sql_query($sql); + while ($row = $db->sql_fetchrow($result)) + { + $notifications[] = array( + 'user_id' => (int) $row['user_id'], + 'topic_id' => $to_topic_id, + 'notify_status' => (int) $row['notify_status'], + ); + } + $db->sql_freeresult($result); + if (sizeof($notifications)) + { + $db->sql_multi_insert(TOPICS_WATCH_TABLE, $notifications); + } + // Link back to both topics $return_link = sprintf($user->lang['RETURN_TOPIC'], '', '') . '

    ' . sprintf($user->lang['RETURN_NEW_TOPIC'], '', ''); } @@ -596,17 +636,65 @@ function merge_posts($topic_id, $to_topic_id) if ($row) { + // Add new topic to bookmarks + $bookmarks = array(); + $sql = 'SELECT user_id + FROM ' . BOOKMARKS_TABLE . ' + WHERE topic_id = ' . (int) $topic_id; + $result = $db->sql_query($sql); + while ($row = $db->sql_fetchrow($result)) + { + $bookmarks[] = array( + 'user_id' => (int) $row['user_id'], + 'topic_id' => (int) $to_topic_id, + ); + } + $db->sql_freeresult($result); + if (sizeof($bookmarks)) + { + // To not let it error out on users, who already bookmarked the topic, we just return on an error... + $db->sql_return_on_error(true); + $db->sql_multi_insert(BOOKMARKS_TABLE, $bookmarks); + $db->sql_return_on_error(false); + } + + // Add new topic to notifications + $notifications = array(); + $sql = 'SELECT user_id, notify_status + FROM ' . TOPICS_WATCH_TABLE . ' + WHERE topic_id = ' . (int) $topic_id; + $result = $db->sql_query($sql); + while ($row = $db->sql_fetchrow($result)) + { + $notifications[] = array( + 'user_id' => (int) $row['user_id'], + 'topic_id' => (int) $to_topic_id, + 'notify_status' => (int) $row['notify_status'], + ); + } + $db->sql_freeresult($result); + if (sizeof($notifications)) + { + // To not let it error out on users, who already watch the topic, we just return on an error... + $db->sql_return_on_error(true); + $db->sql_multi_insert(TOPICS_WATCH_TABLE, $notifications); + $db->sql_return_on_error(false); + } + $return_link .= sprintf($user->lang['RETURN_TOPIC'], '', ''); } else { // If the topic no longer exist, we will update the topic watch table. // To not let it error out on users watching both topics, we just return on an error... + // Same for bookmarks $db->sql_return_on_error(true); $db->sql_query('UPDATE ' . TOPICS_WATCH_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE topic_id = ' . (int) $topic_id); + $db->sql_query('UPDATE ' . BOOKMARKS_TABLE . ' SET topic_id = ' . (int) $to_topic_id . ' WHERE topic_id = ' . (int) $topic_id); $db->sql_return_on_error(false); $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . (int) $topic_id); + $db->sql_query('DELETE FROM ' . BOOKMARKS_TABLE . ' WHERE topic_id = ' . (int) $topic_id); } // Link to the new topic diff --git a/phpBB/includes/mcp/mcp_warn.php b/phpBB/includes/mcp/mcp_warn.php index 4ce67e5f9b..63e5b19155 100644 --- a/phpBB/includes/mcp/mcp_warn.php +++ b/phpBB/includes/mcp/mcp_warn.php @@ -204,7 +204,7 @@ class mcp_warn $sql = 'SELECT u.*, p.* FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u - WHERE post_id = $post_id + WHERE p.post_id = $post_id AND u.user_id = p.poster_id"; $result = $db->sql_query($sql); $user_row = $db->sql_fetchrow($result); diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php index ab6fc3f4f3..72c101f7a3 100644 --- a/phpBB/includes/message_parser.php +++ b/phpBB/includes/message_parser.php @@ -115,10 +115,10 @@ class bbcode_firstpass extends bbcode 'attachment' => array('bbcode_id' => 12, 'regexp' => array('#\[attachment=([0-9]+)\](.*?)\[/attachment\]#ise' => "\$this->bbcode_attachment('\$1', '\$2')")), 'b' => array('bbcode_id' => 1, 'regexp' => array('#\[b\](.*?)\[/b\]#ise' => "\$this->bbcode_strong('\$1')")), 'i' => array('bbcode_id' => 2, 'regexp' => array('#\[i\](.*?)\[/i\]#ise' => "\$this->bbcode_italic('\$1')")), - 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\](.*)\[/url\]#iUe' => "\$this->validate_url('\$2', '\$3')")), + 'url' => array('bbcode_id' => 3, 'regexp' => array('#\[url(=(.*))?\]((?s).*)\[/url\]#iUe' => "\$this->validate_url('\$2', '\$3')")), 'img' => array('bbcode_id' => 4, 'regexp' => array('#\[img\](.*)\[/img\]#iUe' => "\$this->bbcode_img('\$1')")), 'size' => array('bbcode_id' => 5, 'regexp' => array('#\[size=([\-\+]?\d+)\](.*?)\[/size\]#ise' => "\$this->bbcode_size('\$1', '\$2')")), - 'color' => array('bbcode_id' => 6, 'regexp' => array('!\[color=(#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!ise' => "\$this->bbcode_color('\$1', '\$2')")), + 'color' => array('bbcode_id' => 6, 'regexp' => array('!\[color=(#[0-9a-f]{3}|#[0-9a-f]{6}|[a-z\-]+)\](.*?)\[/color\]!ise' => "\$this->bbcode_color('\$1', '\$2')")), 'u' => array('bbcode_id' => 7, 'regexp' => array('#\[u\](.*?)\[/u\]#ise' => "\$this->bbcode_underline('\$1')")), 'list' => array('bbcode_id' => 9, 'regexp' => array('#\[list(?:=(?:[a-z0-9]|disc|circle|square))?].*\[/list]#ise' => "\$this->bbcode_parse_list('\$0')")), 'email' => array('bbcode_id' => 10, 'regexp' => array('#\[email=?(.*?)?\](.*?)\[/email\]#ise' => "\$this->validate_email('\$1', '\$2')")), @@ -1062,10 +1062,21 @@ class parse_message extends bbcode_firstpass { global $config, $db, $user; - $mode = ($mode != 'post') ? 'sig' : 'post'; - $this->mode = $mode; + if (!isset($config['max_' . $mode . '_chars'])) + { + $config['max_' . $mode . '_chars'] = 0; + } + if (!isset($config['max_' . $mode . '_smilies'])) + { + $config['max_' . $mode . '_smilies'] = 0; + } + if (!isset($config['max_' . $mode . '_urls'])) + { + $config['max_' . $mode . '_urls'] = 0; + } + $this->allow_img_bbcode = $allow_img_bbcode; $this->allow_flash_bbcode = $allow_flash_bbcode; $this->allow_quote_bbcode = $allow_quote_bbcode; @@ -1089,14 +1100,22 @@ class parse_message extends bbcode_firstpass $replace = array("\\1:"); $this->message = preg_replace($match, $replace, trim($this->message)); - // Message length check. 0 disables this check completely. - if ($config['max_' . $mode . '_chars'] > 0) - { - $msg_len = ($mode == 'post') ? utf8_strlen($this->message) : utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message)); + // Store message length... + $message_length = ($mode == 'post') ? utf8_strlen($this->message) : utf8_strlen(preg_replace('#\[\/?[a-z\*\+\-]+(=[\S]+)?\]#ius', ' ', $this->message)); - if ((!$msg_len && $mode !== 'sig') || $config['max_' . $mode . '_chars'] && $msg_len > $config['max_' . $mode . '_chars']) + // Maximum message length check. 0 disables this check completely. + if ((int) $config['max_' . $mode . '_chars'] > 0 && $message_length > (int) $config['max_' . $mode . '_chars']) + { + $this->warn_msg[] = sprintf($user->lang['TOO_MANY_CHARS_' . strtoupper($mode)], $message_length, (int) $config['max_' . $mode . '_chars']); + return (!$update_this_message) ? $return_message : $this->warn_msg; + } + + // Minimum message length check for post only + if ($mode === 'post') + { + if (!$message_length || $message_length < (int) $config['min_post_chars']) { - $this->warn_msg[] = (!$msg_len) ? $user->lang['TOO_FEW_CHARS'] : sprintf($user->lang['TOO_MANY_CHARS_' . strtoupper($mode)], $msg_len, $config['max_' . $mode . '_chars']); + $this->warn_msg[] = (!$message_length) ? $user->lang['TOO_FEW_CHARS'] : sprintf($user->lang['TOO_FEW_CHARS_LIMIT'], $message_length, (int) $config['min_post_chars']); return (!$update_this_message) ? $return_message : $this->warn_msg; } } @@ -1145,7 +1164,7 @@ class parse_message extends bbcode_firstpass // Check for "empty" message. We do not check here for maximum length, because bbcode, smilies, etc. can add to the length. // The maximum length check happened before any parsings. - if ($mode !== 'sig' && utf8_clean_string($this->message) === '') + if ($mode === 'post' && utf8_clean_string($this->message) === '') { $this->warn_msg[] = $user->lang['TOO_FEW_CHARS']; return (!$update_this_message) ? $return_message : $this->warn_msg; @@ -1298,7 +1317,7 @@ class parse_message extends bbcode_firstpass } // (assertion) - $match[] = '(?<=^|[\n .])' . preg_quote($row['code'], '#') . '(?![^<>]*>)'; + $match[] = preg_quote($row['code'], '#'); $replace[] = '' . $row['code'] . ''; } $db->sql_freeresult($result); @@ -1308,7 +1327,7 @@ class parse_message extends bbcode_firstpass { if ($max_smilies) { - $num_matches = preg_match_all('#' . implode('|', $match) . '#', $this->message, $matches); + $num_matches = preg_match_all('#(?<=^|[\n .])(?:' . implode('|', $match) . ')(?![^<>]*>)#', $this->message, $matches); unset($matches); if ($num_matches !== false && $num_matches > $max_smilies) @@ -1319,14 +1338,14 @@ class parse_message extends bbcode_firstpass } // Make sure the delimiter # is added in front and at the end of every element within $match - $this->message = trim(preg_replace(explode(chr(0), '#' . implode('#' . chr(0) . '#', $match) . '#'), $replace, $this->message)); + $this->message = trim(preg_replace(explode(chr(0), '#(?<=^|[\n .])' . implode('(?![^<>]*>)#' . chr(0) . '#(?<=^|[\n .])', $match) . '(?![^<>]*>)#'), $replace, $this->message)); } } /** * Parse Attachments */ - function parse_attachments($form_name, $mode, $forum_id, $submit, $preview, $refresh, $is_message = false) + function parse_attachments($form_name, $mode, $forum_id, $submit, $preview, $refresh, $is_message = false, $post_msg_id = 0, $topic_id = 0) { global $config, $auth, $user, $phpbb_root_path, $phpEx, $db; @@ -1479,16 +1498,25 @@ class parse_message extends bbcode_firstpass 'filesize' => $filedata['filesize'], 'filetime' => $filedata['filetime'], 'thumbnail' => $filedata['thumbnail'], - 'is_orphan' => 1, + 'is_orphan' => ($post_msg_id) ? 0 : 1, 'in_message' => ($is_message) ? 1 : 0, 'poster_id' => $user->data['user_id'], ); + if ($post_msg_id) + { + $sql_ary['post_msg_id'] = $post_msg_id; + if ($topic_id) + { + $sql_ary['topic_id'] = $topic_id; + } + } + $db->sql_query('INSERT INTO ' . ATTACHMENTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary)); $new_entry = array( 'attach_id' => $db->sql_nextid(), - 'is_orphan' => 1, + 'is_orphan' => ($post_msg_id) ? 0 : 1, 'real_filename' => $filedata['real_filename'], 'attach_comment'=> $this->filename_data['filecomment'], ); @@ -1612,7 +1640,7 @@ class parse_message extends bbcode_firstpass $this->message = $poll['poll_option_text']; $bbcode_bitfield = $this->bbcode_bitfield; - $poll['poll_option_text'] = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false); + $poll['poll_option_text'] = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false, 'poll'); $bbcode_bitfield = base64_encode(base64_decode($bbcode_bitfield) | base64_decode($this->bbcode_bitfield)); $this->message = $tmp_message; @@ -1635,7 +1663,7 @@ class parse_message extends bbcode_firstpass { $this->warn_msg[] = $user->lang['POLL_TITLE_TOO_LONG']; } - $poll['poll_title'] = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false); + $poll['poll_title'] = $this->parse($poll['enable_bbcode'], ($config['allow_post_links']) ? $poll['enable_urls'] : false, $poll['enable_smilies'], $poll['img_status'], false, false, $config['allow_post_links'], false, 'poll'); if (strlen($poll['poll_title']) > 255) { $this->warn_msg[] = $user->lang['POLL_TITLE_COMP_TOO_LONG']; diff --git a/phpBB/includes/questionnaire/questionnaire.php b/phpBB/includes/questionnaire/questionnaire.php new file mode 100644 index 0000000000..1d015576a7 --- /dev/null +++ b/phpBB/includes/questionnaire/questionnaire.php @@ -0,0 +1,471 @@ + +* @copyright (c) 2007-2008 Johannes Schlueter +*/ +class phpbb_questionnaire_data_collector +{ + var $providers; + var $data = null; + var $install_id = ''; + + /** + * Constructor. + * + * @param string + */ + function phpbb_questionnaire_data_collector($install_id) + { + $this->install_id = $install_id; + $this->providers = array(); + } + + function add_data_provider(&$provider) + { + $this->providers[] = &$provider; + } + + /** + * Get data as an array. + * + * @return array All Data + */ + function get_data_raw() + { + if (!$this->data) + { + $this->collect(); + } + + return $this->data; + } + + function get_data_for_form() + { + return base64_encode(serialize($this->get_data_raw())); + } + + /** + * Collect info into the data property. + * + * @return void + */ + function collect() + { + foreach (array_keys($this->providers) as $key) + { + $provider = &$this->providers[$key]; + $this->data[$provider->get_identifier()] = $provider->get_data(); + } + $this->data['install_id'] = $this->install_id; + } +} + +/** interface: get_indentifier(), get_data() */ + +/** +* Questionnaire PHP data provider +* @package phpBB3 +*/ +class phpbb_questionnaire_php_data_provider +{ + function get_identifier() + { + return 'PHP'; + } + + /** + * Get data about the PHP runtime setup. + * + * @return array + */ + function get_data() + { + return array( + 'version' => PHP_VERSION, + 'sapi' => PHP_SAPI, + 'int_size' => defined('PHP_INT_SIZE') ? PHP_INT_SIZE : '', + 'safe_mode' => (int) @ini_get('safe_mode'), + 'open_basedir' => (int) @ini_get('open_basedir'), + 'memory_limit' => @ini_get('memory_limit'), + 'allow_url_fopen' => (int) @ini_get('allow_url_fopen'), + 'allow_url_include' => (int) @ini_get('allow_url_include'), + 'file_uploads' => (int) @ini_get('file_uploads'), + 'upload_max_filesize' => @ini_get('upload_max_filesize'), + 'post_max_size' => @ini_get('post_max_size'), + 'disable_functions' => @ini_get('disable_functions'), + 'disable_classes' => @ini_get('disable_classes'), + 'enable_dl' => (int) @ini_get('enable_dl'), + 'magic_quotes_gpc' => (int) @ini_get('magic_quotes_gpc'), + 'register_globals' => (int) @ini_get('register_globals'), + 'filter.default' => @ini_get('filter.default'), + 'zend.ze1_compatibility_mode' => (int) @ini_get('zend.ze1_compatibility_mode'), + 'unicode.semantics' => (int) @ini_get('unicode.semantics'), + 'zend_thread_safty' => (int) function_exists('zend_thread_id'), + 'extensions' => get_loaded_extensions(), + ); + } +} + +/** +* Questionnaire System data provider +* @package phpBB3 +*/ +class phpbb_questionnaire_system_data_provider +{ + function get_identifier() + { + return 'System'; + } + + /** + * Get data about the general system information, like OS or IP (shortened). + * + * @return array + */ + function get_data() + { + // Start discovering the IPV4 server address, if available + $server_address = '0.0.0.0'; + + if (!empty($_SERVER['SERVER_ADDR'])) + { + $server_address = $_SERVER['SERVER_ADDR']; + } + + // Running on IIS? + if (!empty($_SERVER['LOCAL_ADDR'])) + { + $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. + // 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', + ); + } +} + +/** +* Questionnaire phpBB data provider +* @package phpBB3 +*/ +class phpbb_questionnaire_phpbb_data_provider +{ + var $config; + var $unique_id; + + /** + * Constructor. + * + * @param array $config + */ + function phpbb_questionnaire_phpbb_data_provider($config) + { + // generate a unique id if necessary + if (empty($config['questionnaire_unique_id'])) + { + $this->unique_id = unique_id(); + set_config('questionnaire_unique_id', $this->unique_id); + } + else + { + $this->unique_id = $config['questionnaire_unique_id']; + } + + $this->config = $config; + } + + /** + * Returns a string identifier for this data provider + * + * @return string "phpBB" + */ + function get_identifier() + { + return 'phpBB'; + } + + /** + * Get data about this phpBB installation. + * + * @return array Relevant anonymous config options + */ + function get_data() + { + global $phpbb_root_path, $phpEx; + include("{$phpbb_root_path}config.$phpEx"); + + // Only send certain config vars + $config_vars = array( + 'active_sessions' => true, + 'allow_attachments' => true, + 'allow_autologin' => true, + 'allow_avatar' => true, + 'allow_avatar_local' => true, + 'allow_avatar_remote' => true, + 'allow_avatar_upload' => true, + 'allow_bbcode' => true, + 'allow_birthdays' => true, + 'allow_bookmarks' => true, + 'allow_emailreuse' => true, + 'allow_forum_notify' => true, + 'allow_mass_pm' => true, + 'allow_name_chars' => true, + 'allow_namechange' => true, + 'allow_nocensors' => true, + 'allow_pm_attach' => true, + 'allow_pm_report' => true, + 'allow_post_flash' => true, + 'allow_post_links' => true, + 'allow_privmsg' => true, + 'allow_quick_reply' => true, + 'allow_sig' => true, + 'allow_sig_bbcode' => true, + 'allow_sig_flash' => true, + 'allow_sig_img' => true, + 'allow_sig_links' => true, + 'allow_sig_pm' => true, + 'allow_sig_smilies' => true, + 'allow_smilies' => true, + 'allow_topic_notify' => true, + 'attachment_quota' => true, + 'auth_bbcode_pm' => true, + 'auth_flash_pm' => true, + 'auth_img_pm' => true, + 'auth_method' => true, + 'auth_smilies_pm' => true, + 'avatar_filesize' => true, + 'avatar_max_height' => true, + 'avatar_max_width' => true, + 'avatar_min_height' => true, + 'avatar_min_width' => true, + 'board_dst' => true, + 'board_email_form' => true, + 'board_hide_emails' => true, + 'board_timezone' => true, + 'browser_check' => true, + 'bump_interval' => true, + 'bump_type' => true, + 'cache_gc' => true, + 'captcha_plugin' => true, + 'captcha_gd' => true, + 'captcha_gd_foreground_noise' => true, + 'captcha_gd_x_grid' => true, + 'captcha_gd_y_grid' => true, + 'captcha_gd_wave' => true, + 'captcha_gd_3d_noise' => true, + 'captcha_gd_fonts' => true, + 'confirm_refresh' => true, + 'check_attachment_content' => true, + 'check_dnsbl' => true, + 'chg_passforce' => true, + 'cookie_secure' => true, + 'coppa_enable' => true, + 'database_gc' => true, + 'dbms_version' => true, + 'default_dateformat' => true, + 'display_last_edited' => true, + 'display_order' => true, + 'edit_time' => true, + 'email_check_mx' => true, + 'email_enable' => true, + 'email_function_name' => true, + 'email_package_size' => true, + 'enable_confirm' => true, + 'enable_pm_icons' => true, + 'enable_post_confirm' => true, + 'feed_enable' => true, + 'feed_limit' => 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_item_statistics' => true, + 'flood_interval' => true, + 'force_server_vars' => true, + 'form_token_lifetime' => true, + 'form_token_mintime' => true, + 'form_token_sid_guests' => true, + 'forward_pm' => true, + 'forwarded_for_check' => true, + 'full_folder_action' => true, + 'fulltext_native_common_thres' => true, + 'fulltext_native_load_upd' => true, + 'fulltext_native_max_chars' => true, + 'fulltext_native_min_chars' => true, + 'gzip_compress' => true, + 'hot_threshold' => true, + 'img_create_thumbnail' => true, + 'img_display_inlined' => true, + 'img_imagick' => true, + 'img_link_height' => true, + 'img_link_width' => true, + 'img_max_height' => true, + 'img_max_thumb_width' => true, + 'img_max_width' => true, + 'img_min_thumb_filesize' => true, + 'ip_check' => true, + 'jab_enable' => true, + 'jab_package_size' => true, + 'jab_use_ssl' => true, + 'limit_load' => true, + 'limit_search_load' => true, + 'load_anon_lastread' => true, + 'load_birthdays' => true, + 'load_cpf_memberlist' => true, + 'load_cpf_viewprofile' => true, + 'load_cpf_viewtopic' => true, + 'load_db_lastread' => true, + 'load_db_track' => true, + 'load_jumpbox' => true, + 'load_moderators' => true, + 'load_online' => true, + 'load_online_guests' => true, + 'load_online_time' => true, + 'load_onlinetrack' => true, + 'load_search' => true, + 'load_tplcompile' => true, + 'load_user_activity' => true, + 'max_attachments' => true, + 'max_attachments_pm' => true, + 'max_autologin_time' => true, + 'max_filesize' => true, + 'max_filesize_pm' => true, + 'max_login_attempts' => true, + 'max_name_chars' => true, + 'max_num_search_keywords' => true, + 'max_pass_chars' => true, + 'max_poll_options' => true, + 'max_post_chars' => true, + 'max_post_font_size' => true, + 'max_post_img_height' => true, + 'max_post_img_width' => true, + 'max_post_smilies' => true, + 'max_post_urls' => true, + 'max_quote_depth' => true, + 'max_reg_attempts' => true, + 'max_sig_chars' => true, + 'max_sig_font_size' => true, + 'max_sig_img_height' => true, + 'max_sig_img_width' => true, + 'max_sig_smilies' => true, + 'max_sig_urls' => true, + 'min_name_chars' => true, + 'min_pass_chars' => true, + 'min_post_chars' => true, + 'min_search_author_chars' => true, + 'mime_triggers' => true, + 'new_member_post_limit' => true, + 'new_member_group_default' => true, + 'override_user_style' => true, + 'pass_complex' => true, + 'pm_edit_time' => true, + 'pm_max_boxes' => true, + 'pm_max_msgs' => true, + 'pm_max_recipients' => true, + 'posts_per_page' => true, + 'print_pm' => true, + 'queue_interval' => true, + 'require_activation' => true, + 'referer_validation' => true, + 'search_block_size' => true, + 'search_gc' => true, + 'search_interval' => true, + 'search_anonymous_interval' => true, + 'search_type' => true, + 'search_store_results' => true, + 'secure_allow_deny' => true, + 'secure_allow_empty_referer' => true, + 'secure_downloads' => true, + 'session_gc' => true, + 'session_length' => true, + 'smtp_auth_method' => true, + 'smtp_delivery' => true, + 'topics_per_page' => true, + 'tpl_allow_php' => true, + 'version' => true, + 'warnings_expire_days' => true, + 'warnings_gc' => true, + + 'num_files' => true, + 'num_posts' => true, + 'num_topics' => true, + 'num_users' => true, + 'record_online_users' => true, + ); + + $result = array(); + foreach ($config_vars as $name => $void) + { + if (isset($this->config[$name])) + { + $result['config_' . $name] = $this->config[$name]; + } + } + + $result['dbms'] = $dbms; + $result['acm_type'] = $acm_type; + $result['load_extensions'] = $load_extensions; + $result['user_agent'] = 'Unknown'; + + // Try to get user agent vendor and version + $match = array(); + $user_agent = (!empty($_SERVER['HTTP_USER_AGENT'])) ? (string) $_SERVER['HTTP_USER_AGENT'] : ''; + $agents = array('firefox', 'msie', 'opera', 'chrome', 'safari', 'mozilla', 'seamonkey', 'konqueror', 'netscape', 'gecko', 'navigator', 'mosaic', 'lynx', 'amaya', 'omniweb', 'avant', 'camino', 'flock', 'aol'); + + // We check here 1 by 1 because some strings occur after others (for example Mozilla [...] Firefox/) + foreach ($agents as $agent) + { + if (preg_match('#(' . $agent . ')[/ ]?([0-9.]*)#i', $user_agent, $match)) + { + $result['user_agent'] = $match[1] . ' ' . $match[2]; + break; + } + } + + return $result; + } +} + +?> \ No newline at end of file diff --git a/phpBB/includes/search/fulltext_mysql.php b/phpBB/includes/search/fulltext_mysql.php index e1e7951367..d1c1ff00d1 100644 --- a/phpBB/includes/search/fulltext_mysql.php +++ b/phpBB/includes/search/fulltext_mysql.php @@ -324,16 +324,17 @@ class fulltext_mysql extends search_backend * Performs a search on keywords depending on display specific params. You have to run split_keywords() first. * * @param string $type contains either posts or topics depending on what should be searched for - * @param string &$fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) - * @param string &$terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @param array &$sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string &$sort_key is the key of $sort_by_sql for the selected sorting - * @param string &$sort_dir is either a or d representing ASC and DESC - * @param string &$sort_days specifies the maximum amount of days a post may be old - * @param array &$ex_fid_ary specifies an array of forum ids which should not be searched - * @param array &$m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts - * @param int &$topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array &$author_ary an array of author ids if the author should be ignored during the search the array is empty + * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) + * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) + * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query + * @param string $sort_key is the key of $sort_by_sql for the selected sorting + * @param string $sort_dir is either a or d representing ASC and DESC + * @param string $sort_days specifies the maximum amount of days a post may be old + * @param array $ex_fid_ary specifies an array of forum ids which should not be searched + * @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts + * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched + * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty + * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered * @param int $start indicates the first index of the page * @param int $per_page number of ids each page is supposed to contain @@ -341,7 +342,7 @@ class fulltext_mysql extends search_backend * * @access public */ - function keyword_search($type, &$fields, &$terms, &$sort_by_sql, &$sort_key, &$sort_dir, &$sort_days, &$ex_fid_ary, &$m_approve_fid_ary, &$topic_id, &$author_ary, &$id_ary, $start, $per_page) + function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page) { global $config, $db; @@ -440,14 +441,26 @@ class fulltext_mysql extends search_backend $sql_select = ($type == 'posts') ? $sql_select . 'p.post_id' : 'DISTINCT ' . $sql_select . 't.topic_id'; $sql_from = ($join_topic) ? TOPICS_TABLE . ' t, ' : ''; $field = ($type == 'posts') ? 'post_id' : 'topic_id'; - $sql_author = (sizeof($author_ary) == 1) ? ' = ' . $author_ary[0] : 'IN (' . implode(', ', $author_ary) . ')'; + if (sizeof($author_ary) && $author_name) + { + // first one matches post of registered users, second one guests and deleted users + $sql_author = '(' . $db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; + } + else if (sizeof($author_ary)) + { + $sql_author = ' AND ' . $db->sql_in_set('p.poster_id', $author_ary); + } + else + { + $sql_author = ''; + } $sql_where_options = $sql_sort_join; $sql_where_options .= ($topic_id) ? ' AND p.topic_id = ' . $topic_id : ''; $sql_where_options .= ($join_topic) ? ' AND t.topic_id = p.topic_id' : ''; $sql_where_options .= (sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; $sql_where_options .= $m_approve_fid_sql; - $sql_where_options .= (sizeof($author_ary)) ? ' AND p.poster_id ' . $sql_author : ''; + $sql_where_options .= $sql_author; $sql_where_options .= ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; $sql_where_options .= $sql_match_where; @@ -495,12 +508,25 @@ class fulltext_mysql extends search_backend /** * Performs a search on an author's posts without caring about message contents. Depends on display specific params * - * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered - * @param int $start indicates the first index of the page - * @param int $per_page number of ids each page is supposed to contain - * @return total number of results + * @param string $type contains either posts or topics depending on what should be searched for + * @param boolean $firstpost_only if true, only topic starting posts will be considered + * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query + * @param string $sort_key is the key of $sort_by_sql for the selected sorting + * @param string $sort_dir is either a or d representing ASC and DESC + * @param string $sort_days specifies the maximum amount of days a post may be old + * @param array $ex_fid_ary specifies an array of forum ids which should not be searched + * @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts + * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched + * @param array $author_ary an array of author ids + * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match + * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered + * @param int $start indicates the first index of the page + * @param int $per_page number of ids each page is supposed to contain + * @return boolean|int total number of results + * + * @access public */ - function author_search($type, $firstpost_only, &$sort_by_sql, &$sort_key, &$sort_dir, &$sort_days, &$ex_fid_ary, &$m_approve_fid_ary, &$topic_id, &$author_ary, &$id_ary, $start, $per_page) + function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page) { global $config, $db; @@ -522,7 +548,8 @@ class fulltext_mysql extends search_backend $topic_id, implode(',', $ex_fid_ary), implode(',', $m_approve_fid_ary), - implode(',', $author_ary) + implode(',', $author_ary), + $author_name, ))); // try reading the results from cache @@ -535,7 +562,15 @@ class fulltext_mysql extends search_backend $id_ary = array(); // Create some display specific sql strings - $sql_author = $db->sql_in_set('p.poster_id', $author_ary); + if ($author_name) + { + // first one matches post of registered users, second one guests and deleted users + $sql_author = '(' . $db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; + } + else + { + $sql_author = $db->sql_in_set('p.poster_id', $author_ary); + } $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; $sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : ''; $sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; diff --git a/phpBB/includes/search/fulltext_native.php b/phpBB/includes/search/fulltext_native.php index 8df5ddfbae..5af3929ccd 100644 --- a/phpBB/includes/search/fulltext_native.php +++ b/phpBB/includes/search/fulltext_native.php @@ -392,16 +392,17 @@ class fulltext_native extends search_backend * Performs a search on keywords depending on display specific params. You have to run split_keywords() first. * * @param string $type contains either posts or topics depending on what should be searched for - * @param string &$fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) - * @param string &$terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) - * @param array &$sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string &$sort_key is the key of $sort_by_sql for the selected sorting - * @param string &$sort_dir is either a or d representing ASC and DESC - * @param string &$sort_days specifies the maximum amount of days a post may be old - * @param array &$ex_fid_ary specifies an array of forum ids which should not be searched - * @param array &$m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts - * @param int &$topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array &$author_ary an array of author ids if the author should be ignored during the search the array is empty + * @param string $fields contains either titleonly (topic titles should be searched), msgonly (only message bodies should be searched), firstpost (only subject and body of the first post should be searched) or all (all post bodies and subjects should be searched) + * @param string $terms is either 'all' (use query as entered, words without prefix should default to "have to be in field") or 'any' (ignore search query parts and just return all posts that contain any of the specified words) + * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query + * @param string $sort_key is the key of $sort_by_sql for the selected sorting + * @param string $sort_dir is either a or d representing ASC and DESC + * @param string $sort_days specifies the maximum amount of days a post may be old + * @param array $ex_fid_ary specifies an array of forum ids which should not be searched + * @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts + * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched + * @param array $author_ary an array of author ids if the author should be ignored during the search the array is empty + * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered * @param int $start indicates the first index of the page * @param int $per_page number of ids each page is supposed to contain @@ -409,7 +410,7 @@ class fulltext_native extends search_backend * * @access public */ - function keyword_search($type, &$fields, &$terms, &$sort_by_sql, &$sort_key, &$sort_dir, &$sort_days, &$ex_fid_ary, &$m_approve_fid_ary, &$topic_id, &$author_ary, &$id_ary, $start, $per_page) + function keyword_search($type, $fields, $terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page) { global $config, $db; @@ -432,7 +433,8 @@ class fulltext_native extends search_backend $topic_id, implode(',', $ex_fid_ary), implode(',', $m_approve_fid_ary), - implode(',', $author_ary) + implode(',', $author_ary), + $author_name, ))); // try reading the results from cache @@ -623,7 +625,16 @@ class fulltext_native extends search_backend if (sizeof($author_ary)) { - $sql_where[] = $db->sql_in_set('p.poster_id', $author_ary); + if ($author_name) + { + // first one matches post of registered users, second one guests and deleted users + $sql_author = '(' . $db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; + } + else + { + $sql_author = $db->sql_in_set('p.poster_id', $author_ary); + } + $sql_where[] = $sql_author; } if (sizeof($ex_fid_ary)) @@ -773,14 +784,15 @@ class fulltext_native extends search_backend * * @param string $type contains either posts or topics depending on what should be searched for * @param boolean $firstpost_only if true, only topic starting posts will be considered - * @param array &$sort_by_sql contains SQL code for the ORDER BY part of a query - * @param string &$sort_key is the key of $sort_by_sql for the selected sorting - * @param string &$sort_dir is either a or d representing ASC and DESC - * @param string &$sort_days specifies the maximum amount of days a post may be old - * @param array &$ex_fid_ary specifies an array of forum ids which should not be searched - * @param array &$m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts - * @param int &$topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched - * @param array &$author_ary an array of author ids + * @param array $sort_by_sql contains SQL code for the ORDER BY part of a query + * @param string $sort_key is the key of $sort_by_sql for the selected sorting + * @param string $sort_dir is either a or d representing ASC and DESC + * @param string $sort_days specifies the maximum amount of days a post may be old + * @param array $ex_fid_ary specifies an array of forum ids which should not be searched + * @param array $m_approve_fid_ary specifies an array of forum ids in which the searcher is allowed to view unapproved posts + * @param int $topic_id is set to 0 or a topic id, if it is not 0 then only posts in this topic should be searched + * @param array $author_ary an array of author ids + * @param string $author_name specifies the author match, when ANONYMOUS is also a search-match * @param array &$id_ary passed by reference, to be filled with ids for the page specified by $start and $per_page, should be ordered * @param int $start indicates the first index of the page * @param int $per_page number of ids each page is supposed to contain @@ -788,7 +800,7 @@ class fulltext_native extends search_backend * * @access public */ - function author_search($type, $firstpost_only, &$sort_by_sql, &$sort_key, &$sort_dir, &$sort_days, &$ex_fid_ary, &$m_approve_fid_ary, &$topic_id, &$author_ary, &$id_ary, $start, $per_page) + function author_search($type, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_ary, $author_name, &$id_ary, $start, $per_page) { global $config, $db; @@ -810,7 +822,8 @@ class fulltext_native extends search_backend $topic_id, implode(',', $ex_fid_ary), implode(',', $m_approve_fid_ary), - implode(',', $author_ary) + implode(',', $author_ary), + $author_name, ))); // try reading the results from cache @@ -823,7 +836,15 @@ class fulltext_native extends search_backend $id_ary = array(); // Create some display specific sql strings - $sql_author = $db->sql_in_set('p.poster_id', $author_ary); + if ($author_name) + { + // first one matches post of registered users, second one guests and deleted users + $sql_author = '(' . $db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')'; + } + else + { + $sql_author = $db->sql_in_set('p.poster_id', $author_ary); + } $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $db->sql_in_set('p.forum_id', $ex_fid_ary, true) : ''; $sql_time = ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : ''; $sql_topic_id = ($topic_id) ? ' AND p.topic_id = ' . (int) $topic_id : ''; diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php index 043a637584..dcfde14159 100644 --- a/phpBB/includes/session.php +++ b/phpBB/includes/session.php @@ -213,7 +213,7 @@ class session $this->update_session_page = $update_session_page; $this->browser = (!empty($_SERVER['HTTP_USER_AGENT'])) ? htmlspecialchars((string) $_SERVER['HTTP_USER_AGENT']) : ''; $this->referer = (!empty($_SERVER['HTTP_REFERER'])) ? htmlspecialchars((string) $_SERVER['HTTP_REFERER']) : ''; - $this->forwarded_for = (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? (string) $_SERVER['HTTP_X_FORWARDED_FOR'] : ''; + $this->forwarded_for = (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) ? htmlspecialchars((string) $_SERVER['HTTP_X_FORWARDED_FOR']) : ''; $this->host = $this->extract_current_hostname(); $this->page = $this->extract_current_page($phpbb_root_path); @@ -221,10 +221,10 @@ class session // if the forwarded for header shall be checked we have to validate its contents if ($config['forwarded_for_check']) { - $this->forwarded_for = preg_replace('#, +#', ', ', $this->forwarded_for); + $this->forwarded_for = preg_replace('#[ ]{2,}#', ' ', str_replace(array(',', ' '), ' ', $this->forwarded_for)); // split the list of IPs - $ips = explode(', ', $this->forwarded_for); + $ips = explode(' ', $this->forwarded_for); foreach ($ips as $ip) { // check IPv4 first, the IPv6 is hopefully only going to be used very seldomly @@ -267,7 +267,28 @@ class session // Why no forwarded_for et al? Well, too easily spoofed. With the results of my recent requests // it's pretty clear that in the majority of cases you'll at least be left with a proxy/cache ip. - $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : ''; + $this->ip = (!empty($_SERVER['REMOTE_ADDR'])) ? htmlspecialchars((string) $_SERVER['REMOTE_ADDR']) : ''; + $this->ip = preg_replace('#[ ]{2,}#', ' ', str_replace(array(',', ' '), ' ', $this->ip)); + + // split the list of IPs + $ips = explode(' ', $this->ip); + + // Default IP if REMOTE_ADDR is invalid + $this->ip = '127.0.0.1'; + + foreach ($ips as $ip) + { + // check IPv4 first, the IPv6 is hopefully only going to be used very seldomly + if (!empty($ip) && !preg_match(get_preg_expression('ipv4'), $ip) && !preg_match(get_preg_expression('ipv6'), $ip)) + { + // Just break + break; + } + + // Use the last in chain + $this->ip = $ip; + } + $this->load = false; // Load limit check (if applicable) @@ -396,6 +417,11 @@ class session WHERE session_id = '" . $db->sql_escape($this->session_id) . "'"; $db->sql_query($sql); } + + if ($this->data['user_id'] != ANONYMOUS && !empty($config['new_member_post_limit']) && $this->data['user_new'] && $config['new_member_post_limit'] <= $this->data['user_posts']) + { + $this->leave_newly_registered(); + } } $this->data['is_registered'] = ($this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false; @@ -601,7 +627,7 @@ class session } else { - $ips = explode(', ', $this->forwarded_for); + $ips = explode(' ', $this->forwarded_for); $ips[] = $this->ip; $this->check_ban($this->data['user_id'], $ips); } @@ -891,7 +917,7 @@ class session */ function session_gc() { - global $db, $config; + global $db, $config, $phpbb_root_path, $phpEx; $batch_size = 10; @@ -949,43 +975,18 @@ class session WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time'])); $db->sql_query($sql); } - $this->confirm_gc(); + + // only called from CRON; should be a safe workaround until the infrastructure gets going + if (!class_exists('captcha_factory')) + { + include($phpbb_root_path . "includes/captcha/captcha_factory." . $phpEx); + } + phpbb_captcha_factory::garbage_collect($config['captcha_plugin']); } return; } - function confirm_gc($type = 0) - { - global $db, $config; - - $sql = 'SELECT DISTINCT c.session_id - FROM ' . CONFIRM_TABLE . ' c - LEFT JOIN ' . SESSIONS_TABLE . ' s ON (c.session_id = s.session_id) - WHERE s.session_id IS NULL' . - ((empty($type)) ? '' : ' AND c.confirm_type = ' . (int) $type); - $result = $db->sql_query($sql); - - if ($row = $db->sql_fetchrow($result)) - { - $sql_in = array(); - do - { - $sql_in[] = (string) $row['session_id']; - } - while ($row = $db->sql_fetchrow($result)); - - if (sizeof($sql_in)) - { - $sql = 'DELETE FROM ' . CONFIRM_TABLE . ' - WHERE ' . $db->sql_in_set('session_id', $sql_in); - $db->sql_query($sql); - } - } - $db->sql_freeresult($result); - } - - /** * Sets a cookie * @@ -1360,6 +1361,20 @@ class session WHERE user_id = ' . (int) $user_id; $db->sql_query($sql); + // Update last visit info first before deleting sessions + $sql = 'SELECT session_time, session_page + FROM ' . SESSIONS_TABLE . ' + WHERE session_user_id = ' . (int) $user_id . ' + ORDER BY session_time DESC'; + $result = $db->sql_query_limit($sql, 1); + $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); + // 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 $sql_where = 'session_user_id = ' . (int) $user_id; @@ -1384,6 +1399,8 @@ class session */ function validate_referer($check_script_path = false) { + global $config; + // no referer - nothing to validate, user's fault for turning it off (we only check on POST; so meta can't be the reason) if (empty($this->referer) || empty($this->host)) { @@ -1393,7 +1410,7 @@ class session $host = htmlspecialchars($this->host); $ref = substr($this->referer, strpos($this->referer, '://') + 3); - if (!(stripos($ref, $host) === 0) && (!$config['force_server'] || !(stripos($ref, $config['server_name']) === 0))) + if (!(stripos($ref, $host) === 0) && (!$config['force_server_vars'] || !(stripos($ref, $config['server_name']) === 0))) { return false; } @@ -1451,8 +1468,8 @@ class user extends session var $img_lang; var $img_array = array(); - // Able to add new option (id 7) - var $keyoptions = array('viewimg' => 0, 'viewflash' => 1, 'viewsmilies' => 2, 'viewsigs' => 3, 'viewavatars' => 4, 'viewcensors' => 5, 'attachsig' => 6, 'bbcode' => 8, 'smilies' => 9, 'popuppm' => 10); + // Able to add new options (up to id 31) + var $keyoptions = array('viewimg' => 0, 'viewflash' => 1, 'viewsmilies' => 2, 'viewsigs' => 3, 'viewavatars' => 4, 'viewcensors' => 5, 'attachsig' => 6, 'bbcode' => 8, 'smilies' => 9, 'popuppm' => 10, 'sig_bbcode' => 15, 'sig_smilies' => 16, 'sig_links' => 17); var $keyvalues = array(); /** @@ -1554,7 +1571,7 @@ class user extends session $this->add_lang($lang_set); unset($lang_set); - if (!empty($_GET['style']) && $auth->acl_get('a_styles')) + if (!empty($_GET['style']) && $auth->acl_get('a_styles') && !defined('ADMIN_START')) { global $SID, $_EXTRA_URL; @@ -1776,7 +1793,7 @@ class user extends session // Disable board if the install/ directory is still present // For the brave development army we do not care about this, else we need to comment out this everytime we develop locally - if (!defined('DEBUG_EXTRA') && !defined('ADMIN_START') && !defined('IN_INSTALL') && !defined('IN_LOGIN') && file_exists($phpbb_root_path . 'install')) + if (!defined('DEBUG_EXTRA') && !defined('ADMIN_START') && !defined('IN_INSTALL') && !defined('IN_LOGIN') && file_exists($phpbb_root_path . 'install') && !is_file($phpbb_root_path . 'install')) { // Adjust the message slightly according to the permissions if ($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) @@ -1853,7 +1870,7 @@ class user extends session // Does the user need to change their password? If so, redirect to the // ucp profile reg_details page ... of course do not redirect if we're already in the ucp - if (!defined('IN_ADMIN') && !defined('ADMIN_START') && $config['chg_passforce'] && $this->data['is_registered'] && $auth->acl_get('u_chgpasswd') && $this->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) + if (!defined('IN_ADMIN') && !defined('ADMIN_START') && $config['chg_passforce'] && !empty($this->data['is_registered']) && $auth->acl_get('u_chgpasswd') && $this->data['user_passchg'] < time() - ($config['chg_passforce'] * 86400)) { if (strpos($this->page['query_string'], 'mode=reg_details') === false && $this->page['page_name'] != "ucp.$phpEx") { @@ -2026,6 +2043,34 @@ class user extends session $language_filename = $this->lang_path . $this->lang_name . '/' . (($use_help) ? 'help_' : '') . $lang_file . '.' . $phpEx; } + if (!file_exists($language_filename)) + { + global $config; + + if ($this->lang_name == 'en') + { + // The user's selected language is missing the file, the board default's language is missing the file, and the file doesn't exist in /en. + $language_filename = str_replace($this->lang_path . 'en', $this->lang_path . $this->data['user_lang'], $language_filename); + trigger_error('Language file ' . $language_filename . ' couldn\'t be opened.', E_USER_ERROR); + } + else if ($this->lang_name == basename($config['default_lang'])) + { + // Fall back to the English Language + $this->lang_name = 'en'; + $this->set_lang($lang, $help, $lang_file, $use_db, $use_help); + } + else if ($this->lang_name == $this->data['user_lang']) + { + // Fall back to the board default language + $this->lang_name = basename($config['default_lang']); + $this->set_lang($lang, $help, $lang_file, $use_db, $use_help); + } + + // Reset the lang name + $this->lang_name = (file_exists($this->lang_path . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']); + return; + } + // Do not suppress error if in DEBUG_EXTRA mode $include_result = (defined('DEBUG_EXTRA')) ? (include $language_filename) : (@include $language_filename); @@ -2186,7 +2231,10 @@ class user extends session return $img_data; } - $img_data['src'] = $phpbb_root_path . 'styles/' . rawurlencode($this->theme['imageset_path']) . '/imageset/' . ($this->img_array[$img]['image_lang'] ? $this->img_array[$img]['image_lang'] .'/' : '') . $this->img_array[$img]['image_filename']; + // Use URL if told so + $root_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? generate_board_url() . '/' : $phpbb_root_path; + + $img_data['src'] = $root_path . 'styles/' . rawurlencode($this->theme['imageset_path']) . '/imageset/' . ($this->img_array[$img]['image_lang'] ? $this->img_array[$img]['image_lang'] .'/' : '') . $this->img_array[$img]['image_filename']; $img_data['width'] = $this->img_array[$img]['image_width']; $img_data['height'] = $this->img_array[$img]['image_height']; } @@ -2259,6 +2307,36 @@ class user extends session return $var; } } + + /** + * Funtion to make the user leave the NEWLY_REGISTERED system group. + * @access public + */ + function leave_newly_registered() + { + global $db; + + if (empty($this->data['user_new'])) + { + return false; + } + + if (!function_exists('remove_newly_registered')) + { + global $phpbb_root_path, $phpEx; + + include($phpbb_root_path . 'includes/functions_user.' . $phpEx); + } + if ($group = remove_newly_registered($this->data['user_id'], $this->data)) + { + $this->data['group_id'] = $group; + + } + $this->data['user_permissions'] = ''; + $this->data['user_new'] = 0; + + return true; + } } ?> \ No newline at end of file diff --git a/phpBB/includes/template.php b/phpBB/includes/template.php index 0098c484bd..80434aca4c 100644 --- a/phpBB/includes/template.php +++ b/phpBB/includes/template.php @@ -39,6 +39,8 @@ class template var $files_inherit = array(); var $files_template = array(); var $inherit_root = ''; + var $orig_tpl_storedb; + var $orig_tpl_inherits_id; // this will hash handle names to the compiled/uncompiled code for that handle. var $compiled_code = array(); @@ -55,7 +57,20 @@ class template { $this->root = $phpbb_root_path . 'styles/' . $user->theme['template_path'] . '/template'; $this->cachepath = $phpbb_root_path . 'cache/tpl_' . str_replace('_', '-', $user->theme['template_path']) . '_'; - + + if ($this->orig_tpl_storedb === null) + { + $this->orig_tpl_storedb = $user->theme['template_storedb']; + } + + if ($this->orig_tpl_inherits_id === null) + { + $this->orig_tpl_inherits_id = $user->theme['template_inherits_id']; + } + + $user->theme['template_storedb'] = $this->orig_tpl_storedb; + $user->theme['template_inherits_id'] = $this->orig_tpl_inherits_id; + if ($user->theme['template_inherits_id']) { $this->inherit_root = $phpbb_root_path . 'styles/' . $user->theme['template_inherit_path'] . '/template'; @@ -77,10 +92,20 @@ class template */ function set_custom_template($template_path, $template_name) { - global $phpbb_root_path; + global $phpbb_root_path, $user; + + // Make sure $template_path has no ending slash + if (substr($template_path, -1) == '/') + { + $template_path = substr($template_path, 0, -1); + } $this->root = $template_path; $this->cachepath = $phpbb_root_path . 'cache/ctpl_' . str_replace('_', '-', $template_name) . '_'; + $user->theme['template_storedb'] = false; + $user->theme['template_inherits_id'] = false; + + $this->_rootref = &$this->_tpldata['.'][0]; return true; } @@ -105,13 +130,13 @@ class template $this->filename[$handle] = $filename; $this->files[$handle] = $this->root . '/' . $filename; - + if ($this->inherit_root) { $this->files_inherit[$handle] = $this->inherit_root . '/' . $filename; } } - + return true; } @@ -209,7 +234,7 @@ class template return true; } - + /** * Load a compiled template if possible, if not, recompile it * @access private @@ -220,7 +245,7 @@ class template $filename = $this->cachepath . str_replace('/', '.', $this->filename[$handle]) . '.' . $phpEx; $this->files_template[$handle] = $user->theme['template_id']; - + $recompile = false; if (!file_exists($filename) || @filesize($filename) === 0) { @@ -236,7 +261,7 @@ class template } $recompile = (@filemtime($filename) < filemtime($this->files[$handle])) ? true : false; } - + // Recompile page if the original template is newer, otherwise load the compiled version if (!$recompile) { @@ -249,14 +274,14 @@ class template { include($phpbb_root_path . 'includes/functions_template.' . $phpEx); } - + // Inheritance - we point to another template file for this one. Equality is also used for store_db if (isset($user->theme['template_inherits_id']) && $user->theme['template_inherits_id'] && !file_exists($this->files[$handle])) { $this->files[$handle] = $this->files_inherit[$handle]; $this->files_template[$handle] = $user->theme['template_inherits_id']; } - + $compile = new template_compile($this); // If we don't have a file assigned to this handle, die. @@ -282,7 +307,7 @@ class template $ids[] = $user->theme['template_inherits_id']; } $ids[] = $user->theme['template_id']; - + foreach ($ids as $id) { $sql = 'SELECT * @@ -290,7 +315,7 @@ class template WHERE template_id = ' . $id . " AND (template_filename = '" . $db->sql_escape($this->filename[$handle]) . "' OR template_included " . $db->sql_like_expression($db->any_char . $this->filename[$handle] . ':' . $db->any_char) . ')'; - + $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) { @@ -298,7 +323,7 @@ class template } $db->sql_freeresult($result); } - + if (sizeof($rows)) { foreach ($rows as $row) @@ -326,7 +351,7 @@ class template { $this->files_template[$row['template_filename']] = $user->theme['template_id']; } - + if ($force_reload || $row['template_mtime'] < filemtime($file)) { if ($row['template_filename'] == $this->filename[$handle]) @@ -468,7 +493,7 @@ class template { unset($this->_tpldata[$blockname][($s_row_count - 1)]['S_LAST_ROW']); } - + // Add a new iteration to this block with the variable assignments we were given. $this->_tpldata[$blockname][] = $vararray; } @@ -511,7 +536,7 @@ class template // Nested blocks are not supported return false; } - + // Change key to zero (change first position) if false and to last position if true if ($key === false || $key === true) { @@ -614,6 +639,25 @@ class template eval(' ?>' . $this->compiled_code[$handle] . '_php_include(): File ' . htmlspecialchars($file) . ' does not exist or is empty'; + return; + } + include($file); + } } ?> \ No newline at end of file diff --git a/phpBB/includes/ucp/ucp_confirm.php b/phpBB/includes/ucp/ucp_confirm.php index b91c88b7e8..445f7c7d2a 100644 --- a/phpBB/includes/ucp/ucp_confirm.php +++ b/phpBB/includes/ucp/ucp_confirm.php @@ -3,7 +3,7 @@ * * @package VC * @version $Id$ -* @copyright (c) 2005 phpBB Group +* @copyright (c) 2005 2008 phpBB Group * @license http://opensource.org/licenses/gpl-license.php GNU Public License * */ @@ -37,42 +37,10 @@ class ucp_confirm { global $db, $user, $phpbb_root_path, $config, $phpEx; - // Do we have an id? No, then just exit - $confirm_id = request_var('id', ''); - $type = request_var('type', 0); - - if (!$confirm_id || !$type) - { - exit; - } - - // Try and grab code for this id and session - $sql = 'SELECT code, seed - FROM ' . CONFIRM_TABLE . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND confirm_type = $type"; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - // If we have a row then grab data else create a new id - if (!$row) - { - exit; - } - - if ($config['captcha_gd']) - { - include($phpbb_root_path . 'includes/captcha/captcha_gd.' . $phpEx); - } - else - { - include($phpbb_root_path . 'includes/captcha/captcha_non_gd.' . $phpEx); - } - - $captcha = new captcha(); - $captcha->execute($row['code'], $row['seed']); + include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); + $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha->init(request_var('type', 0)); + $captcha->execute(); garbage_collection(); exit_handler(); diff --git a/phpBB/includes/ucp/ucp_groups.php b/phpBB/includes/ucp/ucp_groups.php index 4e40f0a2a3..ea57246527 100644 --- a/phpBB/includes/ucp/ucp_groups.php +++ b/phpBB/includes/ucp/ucp_groups.php @@ -41,7 +41,7 @@ class ucp_groups switch ($mode) { case 'membership': - + $this->page_title = 'UCP_USERGROUPS_MEMBER'; if ($submit || isset($_POST['change_default'])) @@ -414,7 +414,7 @@ class ucp_groups $this->page_title = 'UCP_USERGROUPS_MANAGE'; $action = (isset($_POST['addusers'])) ? 'addusers' : request_var('action', ''); $group_id = request_var('g', 0); - + include($phpbb_root_path . 'includes/functions_display.' . $phpEx); add_form_key('ucp_groups'); @@ -438,10 +438,10 @@ class ucp_groups { trigger_error($user->lang['NOT_ALLOWED_MANAGE_GROUP'] . $return_page, E_USER_WARNING); } - + $group_name = $group_row['group_name']; $group_type = $group_row['group_type']; - + $avatar_img = (!empty($group_row['group_avatar'])) ? get_user_avatar($group_row['group_avatar'], $group_row['group_avatar_type'], $group_row['group_avatar_width'], $group_row['group_avatar_height'], 'GROUP_AVATAR') : ''; $template->assign_vars(array( @@ -450,7 +450,7 @@ class ucp_groups 'GROUP_COLOUR' => (isset($group_row['group_colour'])) ? $group_row['group_colour'] : '', 'GROUP_DESC_DISP' => generate_text_for_display($group_row['group_desc'], $group_row['group_desc_uid'], $group_row['group_desc_bitfield'], $group_row['group_desc_options']), 'GROUP_TYPE' => $group_row['group_type'], - + 'AVATAR' => $avatar_img, 'AVATAR_IMAGE' => $avatar_img, 'AVATAR_WIDTH' => (isset($group_row['group_avatar_width'])) ? $group_row['group_avatar_width'] : '', @@ -604,13 +604,26 @@ class ucp_groups // Only set the rank, colour, etc. if it's changed or if we're adding a new // group. This prevents existing group members being updated if no changes // were made. - + $group_attributes = array(); - $test_variables = array('rank', 'colour', 'avatar', 'avatar_type', 'avatar_width', 'avatar_height', 'receive_pm', 'legend', 'message_limit', 'max_recipients'); - foreach ($test_variables as $test) + $test_variables = array( + 'rank' => 'int', + 'colour' => 'string', + 'avatar' => 'string', + 'avatar_type' => 'int', + 'avatar_width' => 'int', + 'avatar_height' => 'int', + 'receive_pm' => 'int', + 'legend' => 'int', + 'message_limit' => 'int', + 'max_recipients'=> 'int', + ); + + foreach ($test_variables as $test => $type) { - if ($action == 'add' || (isset($submit_ary[$test]) && $group_row['group_' . $test] != $submit_ary[$test])) + if (isset($submit_ary[$test]) && ($action == 'add' || $group_row['group_' . $test] != $submit_ary[$test])) { + settype($submit_ary[$test], $type); $group_attributes['group_' . $test] = $group_row['group_' . $test] = $submit_ary[$test]; } } @@ -675,29 +688,33 @@ class ucp_groups $display_gallery = (isset($_POST['display_gallery'])) ? true : false; - if ($config['allow_avatar_local'] && $display_gallery) + if ($config['allow_avatar'] && $config['allow_avatar_local'] && $display_gallery) { avatar_gallery($category, $avatar_select, 4); } - - $avatars_enabled = ($can_upload || ($config['allow_avatar_local'] || $config['allow_avatar_remote'])) ? true : false; + + $avatars_enabled = ($config['allow_avatar'] && (($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) || ($config['allow_avatar_local'] || $config['allow_avatar_remote']))) ? true : false; $template->assign_vars(array( 'S_EDIT' => true, 'S_INCLUDE_SWATCH' => true, - 'S_CAN_UPLOAD' => $can_upload, - 'S_FORM_ENCTYPE' => ($can_upload) ? ' enctype="multipart/form-data"' : '', + 'S_FORM_ENCTYPE' => ($config['allow_avatar'] && $can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) ? ' enctype="multipart/form-data"' : '', 'S_ERROR' => (sizeof($error)) ? true : false, 'S_SPECIAL_GROUP' => ($group_type == GROUP_SPECIAL) ? true : false, 'S_AVATARS_ENABLED' => $avatars_enabled, - 'S_DISPLAY_GALLERY' => ($config['allow_avatar_local'] && !$display_gallery) ? true : false, + 'S_DISPLAY_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local'] && !$display_gallery) ? true : false, 'S_IN_GALLERY' => ($config['allow_avatar_local'] && $display_gallery) ? true : false, + 'S_UPLOAD_AVATAR_FILE' => ($config['allow_avatar'] && $config['allow_avatar_upload'] && $can_upload) ? true : false, + 'S_UPLOAD_AVATAR_URL' => ($config['allow_avatar'] && $config['allow_avatar_remote_upload'] && $can_upload) ? true : false, + 'S_LINK_AVATAR' => ($config['allow_avatar'] && $config['allow_avatar_remote']) ? true : false, + 'S_DISPLAY_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local']) ? true : false, + 'ERROR_MSG' => (sizeof($error)) ? implode('
    ', $error) : '', 'GROUP_RECEIVE_PM' => (isset($group_row['group_receive_pm']) && $group_row['group_receive_pm']) ? ' checked="checked"' : '', 'GROUP_MESSAGE_LIMIT' => (isset($group_row['group_message_limit'])) ? $group_row['group_message_limit'] : 0, 'GROUP_MAX_RECIPIENTS' => (isset($group_row['group_max_recipients'])) ? $group_row['group_max_recipients'] : 0, - + 'GROUP_DESC' => $group_desc_data['text'], 'S_DESC_BBCODE_CHECKED' => $group_desc_data['allow_bbcode'], 'S_DESC_URLS_CHECKED' => $group_desc_data['allow_urls'], @@ -839,6 +856,7 @@ class ucp_groups 'PAGINATION' => generate_pagination($this->u_action . "&action=$action&g=$group_id", $total_members, $config['topics_per_page'], $start), 'U_ACTION' => $this->u_action . "&g=$group_id", + 'S_UCP_ACTION' => $this->u_action . "&g=$group_id", 'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&form=ucp&field=usernames'), )); @@ -896,7 +914,7 @@ class ucp_groups if (!sizeof($mark_ary)) { $start = 0; - + do { $sql = 'SELECT user_id @@ -948,6 +966,9 @@ class ucp_groups ); } + // redirect to last screen + redirect($this->u_action . '&action=list&g=' . $group_id); + break; case 'deleteusers': @@ -994,6 +1015,9 @@ class ucp_groups ); } + // redirect to last screen + redirect($this->u_action . '&action=list&g=' . $group_id); + break; case 'addusers': @@ -1027,7 +1051,7 @@ class ucp_groups $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name']; $default = request_var('default', 0); - + if (confirm_box(true)) { // Add user/s to group diff --git a/phpBB/includes/ucp/ucp_pm.php b/phpBB/includes/ucp/ucp_pm.php index b4ac0c11da..6ac02c7d0a 100644 --- a/phpBB/includes/ucp/ucp_pm.php +++ b/phpBB/includes/ucp/ucp_pm.php @@ -119,7 +119,13 @@ class ucp_pm if (!$auth->acl_get('u_sendpm')) { - trigger_error('NO_AUTH_SEND_MESSAGE'); + // trigger_error('NO_AUTH_SEND_MESSAGE'); + $template->assign_vars(array( + 'S_NO_AUTH_SEND_MESSAGE' => true, + )); + + $tpl_file = 'ucp_pm_viewfolder'; + break; } include($phpbb_root_path . 'includes/ucp/ucp_pm_compose.' . $phpEx); diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php index 008d8d6c88..1d428ce92e 100644 --- a/phpBB/includes/ucp/ucp_pm_compose.php +++ b/phpBB/includes/ucp/ucp_pm_compose.php @@ -46,6 +46,9 @@ function compose_pm($id, $mode, $action) $draft_id = request_var('d', 0); $lastclick = request_var('lastclick', 0); + // Reply to all triggered (quote/reply) + $reply_to_all = request_var('reply_to_all', 0); + // Do NOT use request_var or specialchars here $address_list = isset($_REQUEST['address_list']) ? $_REQUEST['address_list'] : array(); @@ -85,6 +88,10 @@ function compose_pm($id, $mode, $action) redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm')); } + // Since viewtopic.php language entries are used in several modes, + // we include the language file here + $user->add_lang('viewtopic'); + // Output PM_TO box if message composing if ($action != 'edit') { @@ -310,13 +317,14 @@ function compose_pm($id, $mode, $action) if (($action == 'reply' || $action == 'quote' || $action == 'quotepost') && !sizeof($address_list) && !$refresh && !$submit && !$preview) { - if ($action == 'quotepost') + // Add the original author as the recipient if quoting a post or only replying and not having checked "reply to all" + if ($action == 'quotepost' || !$reply_to_all) { $address_list = array('u' => array($post['author_id'] => 'to')); } else { - // We try to include every previously listed member from the TO Header + // We try to include every previously listed member from the TO Header - Reply to all $address_list = rebuild_header(array('to' => $post['to_address'])); // Add the author (if he is already listed then this is no shame (it will be overwritten)) @@ -439,7 +447,7 @@ function compose_pm($id, $mode, $action) $max_recipients = (!$max_recipients) ? $config['pm_max_recipients'] : $max_recipients; // If this is a quote/reply "to all"... we may increase the max_recpients to the number of original recipients - if (($action == 'reply' || $action == 'quote') && $max_recipients) + if (($action == 'reply' || $action == 'quote') && $max_recipients && $reply_to_all) { // We try to include every previously listed member from the TO Header $list = rebuild_header(array('to' => $post['to_address'])); @@ -631,7 +639,7 @@ function compose_pm($id, $mode, $action) // Load Drafts if ($load && $drafts) { - load_drafts(0, 0, $id); + load_drafts(0, 0, $id, $action, $msg_id); } if ($submit || $preview || $refresh) @@ -661,7 +669,22 @@ function compose_pm($id, $mode, $action) } // Parse Attachments - before checksum is calculated - $message_parser->parse_attachments('fileupload', $action, 0, $submit, $preview, $refresh, true); + if ($action == 'edit') + { + $message_parser->parse_attachments('fileupload', $action, 0, $submit, $preview, $refresh, true, $msg_id); + if (sizeof($message_parser->attachment_data)) + { + // Update attachment indicators for pms having attachments now, as a precaution if the pm does not get stored by submit + $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' + SET message_attachment = 1 + WHERE msg_id = ' . $msg_id; + $db->sql_query($sql); + } + } + else + { + $message_parser->parse_attachments('fileupload', $action, 0, $submit, $preview, $refresh, true); + } if (sizeof($message_parser->warn_msg) && !($remove_u || $remove_g || $add_to || $add_bcc)) { @@ -746,7 +769,6 @@ function compose_pm($id, $mode, $action) // Preview if (!sizeof($error) && $preview) { - $user->add_lang('viewtopic'); $preview_message = $message_parser->format_display($enable_bbcode, $enable_urls, $enable_smilies, false); $preview_signature = $user->data['user_sig']; @@ -1141,8 +1163,14 @@ function handle_message_list_actions(&$address_list, &$error, $remove_u, $remove global $refresh, $submit, $preview; - $refresh = $preview = true; + $refresh = true; $submit = false; + + // Preview is only true if there was also a message entered + if (request_var('message', '')) + { + $preview = true; + } } // Add User/Group [TO] diff --git a/phpBB/includes/ucp/ucp_pm_options.php b/phpBB/includes/ucp/ucp_pm_options.php index 2d2ff23cab..e80c0672cf 100644 --- a/phpBB/includes/ucp/ucp_pm_options.php +++ b/phpBB/includes/ucp/ucp_pm_options.php @@ -109,6 +109,10 @@ function message_options($id, $mode, $global_privmsgs_rules, $global_rule_condit $db->sql_query($sql); $msg = $user->lang['FOLDER_ADDED']; } + else + { + $msg = $user->lang['FOLDER_NAME_EMPTY']; + } } else { diff --git a/phpBB/includes/ucp/ucp_pm_viewfolder.php b/phpBB/includes/ucp/ucp_pm_viewfolder.php index cb96b77754..6493b54e1f 100644 --- a/phpBB/includes/ucp/ucp_pm_viewfolder.php +++ b/phpBB/includes/ucp/ucp_pm_viewfolder.php @@ -115,82 +115,9 @@ function view_folder($id, $mode, $folder_id, $folder) // Build Recipient List if in outbox/sentbox - max two additional queries if ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) { - $recipient_list = $address = array(); - - foreach ($folder_info['rowset'] as $message_id => $row) - { - $address[$message_id] = rebuild_header(array('to' => $row['to_address'], 'bcc' => $row['bcc_address'])); - $_save = array('u', 'g'); - foreach ($_save as $save) - { - if (isset($address[$message_id][$save]) && sizeof($address[$message_id][$save])) - { - foreach (array_keys($address[$message_id][$save]) as $ug_id) - { - $recipient_list[$save][$ug_id] = array('name' => $user->lang['NA'], 'colour' => ''); - } - } - } - } - - $_types = array('u', 'g'); - foreach ($_types as $ug_type) - { - if (!empty($recipient_list[$ug_type])) - { - if ($ug_type == 'u') - { - $sql = 'SELECT user_id as id, username as name, user_colour as colour - FROM ' . USERS_TABLE . ' - WHERE '; - } - else - { - $sql = 'SELECT group_id as id, group_name as name, group_colour as colour, group_type - FROM ' . GROUPS_TABLE . ' - WHERE '; - } - $sql .= $db->sql_in_set(($ug_type == 'u') ? 'user_id' : 'group_id', array_map('intval', array_keys($recipient_list[$ug_type]))); - - $result = $db->sql_query($sql); - - while ($row = $db->sql_fetchrow($result)) - { - if ($ug_type == 'g') - { - $row['name'] = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['name']] : $row['name']; - } - - $recipient_list[$ug_type][$row['id']] = array('name' => $row['name'], 'colour' => $row['colour']); - } - $db->sql_freeresult($result); - } - } - - foreach ($address as $message_id => $adr_ary) - { - foreach ($adr_ary as $type => $id_ary) - { - foreach ($id_ary as $ug_id => $_id) - { - if ($type == 'u') - { - $address_list[$message_id][] = get_username_string('full', $ug_id, $recipient_list[$type][$ug_id]['name'], $recipient_list[$type][$ug_id]['colour']); - } - else - { - $user_colour = ($recipient_list[$type][$ug_id]['colour']) ? ' style="font-weight: bold; color:#' . $recipient_list[$type][$ug_id]['colour'] . '"' : ''; - $link = ''; - $address_list[$message_id][] = $link . $recipient_list[$type][$ug_id]['name'] . (($link) ? '' : ''); - } - } - } - } - unset($recipient_list, $address); + $address_list = get_recipient_strings($folder_info['rowset']); } - $data = array(); - foreach ($folder_info['pm_list'] as $message_id) { $row = &$folder_info['rowset'][$message_id]; @@ -267,7 +194,8 @@ function view_folder($id, $mode, $folder_id, $folder) else { // Build Recipient List if in outbox/sentbox - $address = array(); + $address = $data = array(); + if ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) { foreach ($folder_info['rowset'] as $message_id => $row) @@ -457,12 +385,12 @@ function get_pm_from($folder_id, $folder, $user_id) if ($folder_id == PRIVMSGS_OUTBOX || $folder_id == PRIVMSGS_SENTBOX) { $sort_by_text = array('t' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']); - $sort_by_sql = array('t' => 'p.msg_id', 's' => 'p.message_subject'); + $sort_by_sql = array('t' => 'p.message_time', 's' => array('p.message_subject', 'p.message_time')); } else { $sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']); - $sort_by_sql = array('a' => 'u.username_clean', 't' => 'p.msg_id', 's' => 'p.message_subject'); + $sort_by_sql = array('a' => array('u.username_clean', 'p.message_time'), 't' => 'p.message_time', 's' => array('p.message_subject', 'p.message_time')); } $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; @@ -504,8 +432,9 @@ function get_pm_from($folder_id, $folder, $user_id) 'TOTAL_MESSAGES' => (($pm_count == 1) ? $user->lang['VIEW_PM_MESSAGE'] : sprintf($user->lang['VIEW_PM_MESSAGES'], $pm_count)), 'POST_IMG' => (!$auth->acl_get('u_sendpm')) ? $user->img('button_topic_locked', 'POST_PM_LOCKED') : $user->img('button_pm_new', 'POST_NEW_PM'), + 'L_NO_MESSAGES' => (!$auth->acl_get('u_sendpm')) ? $user->lang['NO_AUTH_SEND_MESSAGE'] : $user->lang['NO_MESSAGES'], - 'L_NO_MESSAGES' => (!$auth->acl_get('u_sendpm')) ? $user->lang['POST_PM_LOCKED'] : $user->lang['NO_MESSAGES'], + 'S_NO_AUTH_SEND_MESSAGE' => !$auth->acl_get('u_sendpm'), 'S_SELECT_SORT_DIR' => $s_sort_dir, 'S_SELECT_SORT_KEY' => $s_sort_key, @@ -532,16 +461,26 @@ function get_pm_from($folder_id, $folder, $user_id) } // Select the sort order - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'ASC' : 'DESC'); + $direction = ($sort_dir == 'd') ? 'ASC' : 'DESC'; $sql_start = max(0, $pm_count - $sql_limit - $start); } else { // Select the sort order - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); + $direction = ($sort_dir == 'd') ? 'DESC' : 'ASC'; $sql_start = $start; } + // Sql sort order + if (is_array($sort_by_sql[$sort_key])) + { + $sql_sort_order = implode(' ' . $direction . ', ', $sort_by_sql[$sort_key]) . ' ' . $direction; + } + else + { + $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . $direction; + } + $sql = 'SELECT t.*, p.root_level, p.message_time, p.message_subject, p.icon_id, p.to_address, p.message_attachment, p.bcc_address, u.username, u.username_clean, u.user_colour FROM ' . PRIVMSGS_TO_TABLE . ' t, ' . PRIVMSGS_TABLE . ' p, ' . USERS_TABLE . " u WHERE t.user_id = $user_id diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php index 5fef30056f..26968e1382 100644 --- a/phpBB/includes/ucp/ucp_pm_viewmessage.php +++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php @@ -29,6 +29,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) $msg_id = (int) $msg_id; $folder_id = (int) $folder_id; $author_id = (int) $message_row['author_id']; + $view = request_var('view', ''); // Not able to view message, it was deleted by the sender if ($message_row['pm_deleted']) @@ -168,6 +169,9 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) $url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm'); + // Number of "to" recipients + $num_recipients = (int) preg_match_all('/:?(u|g)_([0-9]+):?/', $message_row['to_address'], $match); + $template->assign_vars(array( 'MESSAGE_AUTHOR_FULL' => get_username_string('full', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']), 'MESSAGE_AUTHOR_COLOUR' => get_username_string('colour', $author_id, $user_info['username'], $user_info['user_colour'], $user_info['username']), @@ -178,7 +182,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) 'RANK_IMG' => $user_info['rank_image'], 'AUTHOR_AVATAR' => (isset($user_info['avatar'])) ? $user_info['avatar'] : '', 'AUTHOR_JOINED' => $user->format_date($user_info['user_regdate']), - 'AUTHOR_POSTS' => (!empty($user_info['user_posts'])) ? $user_info['user_posts'] : '', + 'AUTHOR_POSTS' => (int) $user_info['user_posts'], 'AUTHOR_FROM' => (!empty($user_info['user_from'])) ? $user_info['user_from'] : '', 'ONLINE_IMG' => (!$config['load_onlinetrack']) ? '' : ((isset($user_info['online']) && $user_info['online']) ? $user->img('icon_user_online', $user->lang['ONLINE']) : $user->img('icon_user_offline', $user->lang['OFFLINE'])), @@ -189,10 +193,11 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) 'EMAIL_IMG' => $user->img('icon_contact_email', $user->lang['SEND_EMAIL']), 'QUOTE_IMG' => $user->img('icon_post_quote', $user->lang['POST_QUOTE_PM']), 'REPLY_IMG' => $user->img('button_pm_reply', $user->lang['POST_REPLY_PM']), + 'REPORT_IMG' => $user->img('icon_post_report', 'REPORT_PM'), 'EDIT_IMG' => $user->img('icon_post_edit', $user->lang['POST_EDIT_PM']), 'MINI_POST_IMG' => $user->img('icon_post_target', $user->lang['PM']), - 'SENT_DATE' => $user->format_date($message_row['message_time']), + 'SENT_DATE' => ($view == 'print') ? $user->format_date($message_row['message_time'], false, true) : $user->format_date($message_row['message_time']), 'SUBJECT' => $message_row['message_subject'], 'MESSAGE' => $message, 'SIGNATURE' => ($message_row['enable_sig']) ? $signature : '', @@ -209,16 +214,21 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row) 'U_DELETE' => ($auth->acl_get('u_pm_delete')) ? "$url&mode=compose&action=delete&f=$folder_id&p=" . $message_row['msg_id'] : '', 'U_EMAIL' => $user_info['email'], + 'U_REPORT' => ($config['allow_pm_report']) ? append_sid("{$phpbb_root_path}report.$phpEx", "pm=" . $message_row['msg_id']) : '', 'U_QUOTE' => ($auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&mode=compose&action=quote&f=$folder_id&p=" . $message_row['msg_id'] : '', 'U_EDIT' => (($message_row['message_time'] > time() - ($config['pm_edit_time'] * 60) || !$config['pm_edit_time']) && $folder_id == PRIVMSGS_OUTBOX && $auth->acl_get('u_pm_edit')) ? "$url&mode=compose&action=edit&f=$folder_id&p=" . $message_row['msg_id'] : '', 'U_POST_REPLY_PM' => ($auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&mode=compose&action=reply&f=$folder_id&p=" . $message_row['msg_id'] : '', + 'U_POST_REPLY_ALL' => ($auth->acl_get('u_sendpm') && $author_id != ANONYMOUS) ? "$url&mode=compose&action=reply&f=$folder_id&reply_to_all=1&p=" . $message_row['msg_id'] : '', 'U_PREVIOUS_PM' => "$url&f=$folder_id&p=" . $message_row['msg_id'] . "&view=previous", 'U_NEXT_PM' => "$url&f=$folder_id&p=" . $message_row['msg_id'] . "&view=next", + 'U_PM_ACTION' => $url . '&mode=compose&f=' . $folder_id . '&p=' . $message_row['msg_id'], + 'S_HAS_ATTACHMENTS' => (sizeof($attachments)) ? true : false, 'S_DISPLAY_NOTICE' => $display_notice && $message_row['message_attachment'], 'S_AUTHOR_DELETED' => ($author_id == ANONYMOUS) ? true : false, 'S_SPECIAL_FOLDER' => in_array($folder_id, array(PRIVMSGS_NO_BOX, PRIVMSGS_OUTBOX)), + 'S_PM_RECIPIENTS' => $num_recipients, 'U_PRINT_PM' => ($config['print_pm'] && $auth->acl_get('u_pm_printpm')) ? "$url&f=$folder_id&p=" . $message_row['msg_id'] . "&view=print" : '', 'U_FORWARD_PM' => ($config['forward_pm'] && $auth->acl_get('u_sendpm') && $auth->acl_get('u_pm_forward')) ? "$url&mode=compose&action=forward&f=$folder_id&p=" . $message_row['msg_id'] : '') diff --git a/phpBB/includes/ucp/ucp_prefs.php b/phpBB/includes/ucp/ucp_prefs.php index 9b705fba6c..cc8565e69d 100644 --- a/phpBB/includes/ucp/ucp_prefs.php +++ b/phpBB/includes/ucp/ucp_prefs.php @@ -282,7 +282,7 @@ class ucp_prefs 'S_AVATARS' => $data['avatars'], 'S_DISABLE_CENSORS' => $data['wordcensor'], - 'S_CHANGE_CENSORS' => ($auth->acl_get('u_chgcensors')) ? true : false, + 'S_CHANGE_CENSORS' => ($auth->acl_get('u_chgcensors') && $config['allow_nocensors']) ? true : false, 'S_TOPIC_SORT_DAYS' => $s_limit_topic_days, 'S_TOPIC_SORT_KEY' => $s_sort_topic_key, diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php index 30752d8c8a..e24acd89fc 100644 --- a/phpBB/includes/ucp/ucp_profile.php +++ b/phpBB/includes/ucp/ucp_profile.php @@ -110,7 +110,7 @@ class ucp_profile 'username' => ($auth->acl_get('u_chgname') && $config['allow_namechange']) ? $data['username'] : $user->data['username'], 'username_clean' => ($auth->acl_get('u_chgname') && $config['allow_namechange']) ? utf8_clean_string($data['username']) : $user->data['username_clean'], 'user_email' => ($auth->acl_get('u_chgemail')) ? $data['email'] : $user->data['user_email'], - 'user_email_hash' => ($auth->acl_get('u_chgemail')) ? crc32($data['email']) . strlen($data['email']) : $user->data['user_email_hash'], + 'user_email_hash' => ($auth->acl_get('u_chgemail')) ? phpbb_email_hash($data['email']) : $user->data['user_email_hash'], 'user_password' => ($auth->acl_get('u_chgpasswd') && $data['new_password']) ? phpbb_hash($data['new_password']) : $user->data['user_password'], 'user_passchg' => ($auth->acl_get('u_chgpasswd') && $data['new_password']) ? time() : 0, ); @@ -380,25 +380,7 @@ class ucp_profile $db->sql_query($sql); // Update Custom Fields - if (sizeof($cp_data)) - { - $sql = 'UPDATE ' . PROFILE_FIELDS_DATA_TABLE . ' - SET ' . $db->sql_build_array('UPDATE', $cp_data) . ' - WHERE user_id = ' . $user->data['user_id']; - $db->sql_query($sql); - - if (!$db->sql_affectedrows()) - { - $cp_data['user_id'] = (int) $user->data['user_id']; - - $db->sql_return_on_error(true); - - $sql = 'INSERT INTO ' . PROFILE_FIELDS_DATA_TABLE . ' ' . $db->sql_build_array('INSERT', $cp_data); - $db->sql_query($sql); - - $db->sql_return_on_error(false); - } - } + $cp->update_profile_field_data($user->data['user_id'], $cp_data); meta_refresh(3, $this->u_action); $message = $user->lang['PROFILE_UPDATED'] . '

    ' . sprintf($user->lang['RETURN_UCP'], '', ''); @@ -474,9 +456,9 @@ class ucp_profile include($phpbb_root_path . 'includes/functions_posting.' . $phpEx); include($phpbb_root_path . 'includes/functions_display.' . $phpEx); - $enable_bbcode = ($config['allow_sig_bbcode']) ? ((request_var('disable_bbcode', !$user->optionget('bbcode'))) ? false : true) : false; - $enable_smilies = ($config['allow_sig_smilies']) ? ((request_var('disable_smilies', !$user->optionget('smilies'))) ? false : true) : false; - $enable_urls = ($config['allow_sig_links']) ? ((request_var('disable_magic_url', false)) ? false : true) : false; + $enable_bbcode = ($config['allow_sig_bbcode']) ? (bool) $user->optionget('sig_bbcode') : false; + $enable_smilies = ($config['allow_sig_smilies']) ? (bool) $user->optionget('sig_smilies') : false; + $enable_urls = ($config['allow_sig_links']) ? (bool) $user->optionget('sig_links') : false; $signature = utf8_normalize_nfc(request_var('signature', (string) $user->data['user_sig'], true)); @@ -486,6 +468,10 @@ class ucp_profile { include($phpbb_root_path . 'includes/message_parser.' . $phpEx); + $enable_bbcode = ($config['allow_sig_bbcode']) ? ((request_var('disable_bbcode', false)) ? false : true) : false; + $enable_smilies = ($config['allow_sig_smilies']) ? ((request_var('disable_smilies', false)) ? false : true) : false; + $enable_urls = ($config['allow_sig_links']) ? ((request_var('disable_magic_url', false)) ? false : true) : false; + if (!sizeof($error)) { $message_parser = new parse_message($signature); @@ -505,8 +491,13 @@ class ucp_profile if (!sizeof($error) && $submit) { + $user->optionset('sig_bbcode', $enable_bbcode); + $user->optionset('sig_smilies', $enable_smilies); + $user->optionset('sig_links', $enable_urls); + $sql_ary = array( 'user_sig' => (string) $message_parser->message, + 'user_options' => $user->data['user_options'], 'user_sig_bbcode_uid' => (string) $message_parser->bbcode_uid, 'user_sig_bbcode_bitfield' => $message_parser->bbcode_bitfield ); @@ -573,7 +564,7 @@ class ucp_profile $avatar_select = basename(request_var('avatar_select', '')); $category = basename(request_var('category', '')); - $can_upload = ($config['allow_avatar_upload'] && file_exists($phpbb_root_path . $config['avatar_path']) && @is_writable($phpbb_root_path . $config['avatar_path']) && $auth->acl_get('u_chgavatar') && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false; + $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && @is_writable($phpbb_root_path . $config['avatar_path']) && $auth->acl_get('u_chgavatar') && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false; add_form_key('ucp_avatar'); @@ -596,33 +587,44 @@ class ucp_profile $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); } + if (!$config['allow_avatar'] && $user->data['user_avatar_type']) + { + $error[] = $user->lang['AVATAR_NOT_ALLOWED']; + } + else if ((($user->data['user_avatar_type'] == AVATAR_UPLOAD) && !$config['allow_avatar_upload']) || + (($user->data['user_avatar_type'] == AVATAR_REMOTE) && !$config['allow_avatar_remote']) || + (($user->data['user_avatar_type'] == AVATAR_GALLERY) && !$config['allow_avatar_local'])) + { + $error[] = $user->lang['AVATAR_TYPE_NOT_ALLOWED']; + } + $template->assign_vars(array( 'ERROR' => (sizeof($error)) ? implode('
    ', $error) : '', - 'AVATAR' => get_user_avatar($user->data['user_avatar'], $user->data['user_avatar_type'], $user->data['user_avatar_width'], $user->data['user_avatar_height']), + 'AVATAR' => get_user_avatar($user->data['user_avatar'], $user->data['user_avatar_type'], $user->data['user_avatar_width'], $user->data['user_avatar_height'], 'USER_AVATAR', true), 'AVATAR_SIZE' => $config['avatar_filesize'], 'U_GALLERY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&mode=avatar&display_gallery=1'), - 'S_FORM_ENCTYPE' => ($can_upload) ? ' enctype="multipart/form-data"' : '', + 'S_FORM_ENCTYPE' => ($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) ? ' enctype="multipart/form-data"' : '', 'L_AVATAR_EXPLAIN' => sprintf($user->lang['AVATAR_EXPLAIN'], $config['avatar_max_width'], $config['avatar_max_height'], $config['avatar_filesize'] / 1024), )); - if ($display_gallery && $auth->acl_get('u_chgavatar') && $config['allow_avatar_local']) + if ($config['allow_avatar'] && $display_gallery && $auth->acl_get('u_chgavatar') && $config['allow_avatar_local']) { avatar_gallery($category, $avatar_select, 4); } - else + else if ($config['allow_avatar']) { - $avatars_enabled = ($can_upload || ($auth->acl_get('u_chgavatar') && ($config['allow_avatar_local'] || $config['allow_avatar_remote']))) ? true : false; + $avatars_enabled = (($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) || ($auth->acl_get('u_chgavatar') && ($config['allow_avatar_local'] || $config['allow_avatar_remote']))) ? true : false; $template->assign_vars(array( 'AVATAR_WIDTH' => request_var('width', $user->data['user_avatar_width']), 'AVATAR_HEIGHT' => request_var('height', $user->data['user_avatar_height']), 'S_AVATARS_ENABLED' => $avatars_enabled, - 'S_UPLOAD_AVATAR_FILE' => $can_upload, - 'S_UPLOAD_AVATAR_URL' => $can_upload, + 'S_UPLOAD_AVATAR_FILE' => ($can_upload && $config['allow_avatar_upload']) ? true : false, + 'S_UPLOAD_AVATAR_URL' => ($can_upload && $config['allow_avatar_remote_upload']) ? true : false, 'S_LINK_AVATAR' => ($auth->acl_get('u_chgavatar') && $config['allow_avatar_remote']) ? true : false, 'S_DISPLAY_GALLERY' => ($auth->acl_get('u_chgavatar') && $config['allow_avatar_local']) ? true : false) ); diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php index e42ad8369d..8359c223e0 100644 --- a/phpBB/includes/ucp/ucp_register.php +++ b/phpBB/includes/ucp/ucp_register.php @@ -37,13 +37,11 @@ class ucp_register include($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx); - $confirm_id = request_var('confirm_id', ''); - $confirm_refresh = (isset($_POST['confirm_refresh']) && $config['confirm_refresh']) ? ((!empty($_POST['confirm_refresh'])) ? 1 : 0) : false; - $coppa = (isset($_REQUEST['coppa'])) ? ((!empty($_REQUEST['coppa'])) ? 1 : 0) : false; - $agreed = (!empty($_POST['agreed'])) ? 1 : 0; - $submit = (isset($_POST['submit'])) ? true : false; - $change_lang = request_var('change_lang', ''); - $user_lang = request_var('lang', $user->lang_name); + $coppa = (isset($_REQUEST['coppa'])) ? ((!empty($_REQUEST['coppa'])) ? 1 : 0) : false; + $agreed = (!empty($_POST['agreed'])) ? 1 : 0; + $submit = (isset($_POST['submit'])) ? true : false; + $change_lang = request_var('change_lang', ''); + $user_lang = request_var('lang', $user->lang_name); if ($agreed) { @@ -54,7 +52,6 @@ class ucp_register add_form_key('ucp_register_terms'); } - if ($change_lang || $user_lang != $config['default_lang']) { $use_lang = ($change_lang) ? basename($change_lang) : basename($user_lang); @@ -69,8 +66,9 @@ class ucp_register $agreed = (empty($_GET['change_lang'])) ? 0 : $agreed; } - $user->lang_name = $lang = $use_lang; + $user->lang_name = $user_lang = $use_lang; $user->lang = array(); + $user->data['user_lang'] = $user->lang_name; $user->add_lang(array('common', 'ucp')); } else @@ -80,17 +78,19 @@ class ucp_register } } + $cp = new custom_profile(); $error = $cp_data = $cp_error = array(); - if (!$agreed || ($coppa === false && $config['coppa_enable']) || ($coppa && !$config['coppa_enable'])) { $add_lang = ($change_lang) ? '&change_lang=' . urlencode($change_lang) : ''; $add_coppa = ($coppa !== false) ? '&coppa=' . $coppa : ''; - $s_hidden_fields = ($confirm_id) ? array('confirm_id' => $confirm_id) : array(); + $s_hidden_fields = array( + 'change_lang' => $change_lang, + ); // If we change the language, we want to pass on some more possible parameter. if ($change_lang) @@ -100,13 +100,24 @@ class ucp_register 'username' => utf8_normalize_nfc(request_var('username', '', true)), 'email' => strtolower(request_var('email', '')), 'email_confirm' => strtolower(request_var('email_confirm', '')), - 'confirm_code' => request_var('confirm_code', ''), - 'confirm_id' => request_var('confirm_id', ''), 'lang' => $user->lang_name, 'tz' => request_var('tz', (float) $config['board_timezone']), )); + } + // Checking amount of available languages + $sql = 'SELECT lang_id + FROM ' . LANG_TABLE; + $result = $db->sql_query($sql); + + $lang_row = array(); + while ($row = $db->sql_fetchrow($result)) + { + $lang_row[] = $row; + } + $db->sql_freeresult($result); + if ($coppa === false && $config['coppa_enable']) { $now = getdate(); @@ -114,6 +125,7 @@ class ucp_register unset($now); $template->assign_vars(array( + 'S_LANG_OPTIONS' => (sizeof($lang_row) > 1) ? language_select($user_lang) : '', 'L_COPPA_NO' => sprintf($user->lang['UCP_COPPA_BEFORE'], $coppa_birthday), 'L_COPPA_YES' => sprintf($user->lang['UCP_COPPA_ON_AFTER'], $coppa_birthday), @@ -128,6 +140,7 @@ class ucp_register else { $template->assign_vars(array( + 'S_LANG_OPTIONS' => (sizeof($lang_row) > 1) ? language_select($user_lang) : '', 'L_TERMS_OF_USE' => sprintf($user->lang['TERMS_OF_USE_CONTENT'], $config['sitename'], generate_board_url()), 'S_SHOW_COPPA' => false, @@ -137,11 +150,20 @@ class ucp_register ) ); } + unset($lang_row); $this->tpl_name = 'ucp_agreement'; return; } - + + + // The CAPTCHA kicks in here. We can't help that the information gets lost on language change. + if ($config['enable_confirm']) + { + include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); + $captcha =& phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha->init(CONFIRM_REG); + } // Try to manually determine the timezone and adjust the dst if the server date/time complies with the default setting +/- 1 $timezone = date('Z') / 3600; @@ -168,7 +190,6 @@ class ucp_register 'password_confirm' => request_var('password_confirm', '', true), 'email' => strtolower(request_var('email', '')), 'email_confirm' => strtolower(request_var('email_confirm', '')), - 'confirm_code' => request_var('confirm_code', ''), 'lang' => basename(request_var('lang', $user->lang_name)), 'tz' => request_var('tz', (float) $timezone), ); @@ -188,17 +209,32 @@ class ucp_register array('string', false, 6, 60), array('email')), 'email_confirm' => array('string', false, 6, 60), - 'confirm_code' => array('string', !$config['enable_confirm'], CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS), 'tz' => array('num', false, -14, 14), 'lang' => array('match', false, '#^[a-z_\-]{2,}$#i'), )); + if (!check_form_key('ucp_register')) { $error[] = $user->lang['FORM_INVALID']; } + // Replace "error" strings with their real, localised form $error = preg_replace('#^([A-Z_]+)$#e', "(!empty(\$user->lang['\\1'])) ? \$user->lang['\\1'] : '\\1'", $error); + if ($config['enable_confirm']) + { + $vc_response = $captcha->validate($data); + if ($vc_response !== false) + { + $error[] = $vc_response; + } + + if ($config['max_reg_attempts'] && $captcha->get_attempt_count() > $config['max_reg_attempts']) + { + $error[] = $user->lang['TOO_MANY_REGISTERS']; + } + } + // DNSBL check if ($config['check_dnsbl']) { @@ -211,50 +247,6 @@ class ucp_register // validate custom profile fields $cp->submit_cp_field('register', $user->get_iso_lang_id(), $cp_data, $error); - // Visual Confirmation handling - $wrong_confirm = false; - if ($config['enable_confirm']) - { - if (!$confirm_id) - { - $error[] = $user->lang['CONFIRM_CODE_WRONG']; - $wrong_confirm = true; - } - else - { - $sql = 'SELECT code - FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_REG; - $result = $db->sql_query($sql); - $row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if ($row) - { - if (strcasecmp($row['code'], $data['confirm_code']) === 0) - { - $sql = 'DELETE FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_REG; - $db->sql_query($sql); - } - else - { - $error[] = $user->lang['CONFIRM_CODE_WRONG']; - $wrong_confirm = true; - } - } - else - { - $error[] = $user->lang['CONFIRM_CODE_WRONG']; - $wrong_confirm = true; - } - } - } - if (!sizeof($error)) { if ($data['new_password'] != $data['password_confirm']) @@ -327,6 +319,11 @@ class ucp_register 'user_inactive_time' => $user_inactive_time, ); + if ($config['new_member_post_limit']) + { + $user_row['user_new'] = 1; + } + // Register user... $user_id = user_add($user_row, $cp_data); @@ -441,85 +438,20 @@ class ucp_register { $s_hidden_fields['coppa'] = $coppa; } - $s_hidden_fields = build_hidden_fields($s_hidden_fields); - - $confirm_image = ''; - - // Visual Confirmation - Show images if ($config['enable_confirm']) { - if ($change_lang || $confirm_refresh) - { - $str = '&change_lang=' . $change_lang; - $sql = 'SELECT code - FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_REG; - $result = $db->sql_query($sql); - if (!$row = $db->sql_fetchrow($result)) - { - $confirm_id = ''; - } - $db->sql_freeresult($result); - } - else - { - $str = ''; - } - if (!$change_lang || !$confirm_id || !$confirm_refresh) - { - $user->confirm_gc(CONFIRM_REG); + $s_hidden_fields = array_merge($s_hidden_fields, $captcha->get_hidden_fields()); + } + $s_hidden_fields = build_hidden_fields($s_hidden_fields); + $confirm_image = ''; - $sql = 'SELECT COUNT(session_id) AS attempts - FROM ' . CONFIRM_TABLE . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_REG; - $result = $db->sql_query($sql); - $attempts = (int) $db->sql_fetchfield('attempts'); - $db->sql_freeresult($result); - - if ($config['max_reg_attempts'] && $attempts > $config['max_reg_attempts']) - { - trigger_error('TOO_MANY_REGISTERS'); - } - - $code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); - $confirm_id = md5(unique_id($user->ip)); - $seed = hexdec(substr(unique_id(), 4, 10)); - - // compute $seed % 0x7fffffff - $seed -= 0x7fffffff * floor($seed / 0x7fffffff); - - $sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'confirm_id' => (string) $confirm_id, - 'session_id' => (string) $user->session_id, - 'confirm_type' => (int) CONFIRM_REG, - 'code' => (string) $code, - 'seed' => (int) $seed) - ); - $db->sql_query($sql); - } - else if ($confirm_refresh) - { - $code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); - $confirm_id = md5(unique_id($user->ip)); - $seed = hexdec(substr(unique_id(), 4, 10)); - // compute $seed % 0x7fffffff - $seed -= 0x7fffffff * floor($seed / 0x7fffffff); - $sql = 'UPDATE ' . CONFIRM_TABLE . ' SET ' . $db->sql_build_array('UPDATE', array( - 'confirm_type' => (int) CONFIRM_REG, - 'code' => (string) $code, - 'seed' => (int) $seed)) . " - WHERE - confirm_id = '" . $db->sql_escape($confirm_id) . "' AND - session_id = '" . $db->sql_escape($session_id) . "' AND - confirm_type = " . (int) CONFIRM_REG; - $db->sql_query($sql); - } - $confirm_image = ''; - $s_hidden_fields .= ''; + // Visual Confirmation - Show images + if ($config['enable_confirm']) + { + $template->assign_vars(array( + 'CAPTCHA_TEMPLATE' => $captcha->get_template(), + )); } // @@ -542,22 +474,19 @@ class ucp_register 'PASSWORD_CONFIRM' => $data['password_confirm'], 'EMAIL' => $data['email'], 'EMAIL_CONFIRM' => $data['email_confirm'], - 'CONFIRM_IMG' => $confirm_image, - 'L_CONFIRM_EXPLAIN' => sprintf($user->lang['CONFIRM_EXPLAIN'], '', ''), 'L_REG_COND' => $l_reg_cond, 'L_USERNAME_EXPLAIN' => sprintf($user->lang[$config['allow_name_chars'] . '_EXPLAIN'], $config['min_name_chars'], $config['max_name_chars']), 'L_PASSWORD_EXPLAIN' => sprintf($user->lang[$config['pass_complex'] . '_EXPLAIN'], $config['min_pass_chars'], $config['max_pass_chars']), 'S_LANG_OPTIONS' => language_select($data['lang']), 'S_TZ_OPTIONS' => tz_select($data['tz']), - 'S_CONFIRM_CODE' => ($config['enable_confirm']) ? true : false, 'S_CONFIRM_REFRESH' => ($config['enable_confirm'] && $config['confirm_refresh']) ? true : false, + 'S_REGISTRATION' => true, 'S_COPPA' => $coppa, 'S_HIDDEN_FIELDS' => $s_hidden_fields, 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'), - ) - ); + )); // $user->profile_fields = array(); diff --git a/phpBB/includes/ucp/ucp_remind.php b/phpBB/includes/ucp/ucp_remind.php index 6325bf89b6..df6733d038 100644 --- a/phpBB/includes/ucp/ucp_remind.php +++ b/phpBB/includes/ucp/ucp_remind.php @@ -38,7 +38,7 @@ class ucp_remind { $sql = 'SELECT user_id, username, user_permissions, user_email, user_jabber, user_notify_type, user_type, user_lang, user_inactive_reason FROM ' . USERS_TABLE . " - WHERE user_email = '" . $db->sql_escape($email) . "' + WHERE user_email_hash = '" . $db->sql_escape(phpbb_email_hash($email)) . "' AND username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; $result = $db->sql_query($sql); $user_row = $db->sql_fetchrow($result); diff --git a/phpBB/includes/ucp/ucp_resend.php b/phpBB/includes/ucp/ucp_resend.php index cad494541b..39e9be24a1 100644 --- a/phpBB/includes/ucp/ucp_resend.php +++ b/phpBB/includes/ucp/ucp_resend.php @@ -45,7 +45,7 @@ class ucp_resend $sql = 'SELECT user_id, group_id, username, user_email, user_type, user_lang, user_actkey, user_inactive_reason FROM ' . USERS_TABLE . " - WHERE user_email = '" . $db->sql_escape($email) . "' + WHERE user_email_hash = '" . $db->sql_escape(phpbb_email_hash($email)) . "' AND username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; $result = $db->sql_query($sql); $user_row = $db->sql_fetchrow($result); diff --git a/phpBB/includes/ucp/ucp_zebra.php b/phpBB/includes/ucp/ucp_zebra.php index fb5df9394b..5ed4db7520 100644 --- a/phpBB/includes/ucp/ucp_zebra.php +++ b/phpBB/includes/ucp/ucp_zebra.php @@ -52,6 +52,18 @@ class ucp_zebra { if (confirm_box(true)) { + // Remove users + if (!empty($data['usernames'])) + { + $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' + WHERE user_id = ' . $user->data['user_id'] . ' + AND ' . $db->sql_in_set('zebra_id', $data['usernames']); + $db->sql_query($sql); + + $updated = true; + } + + // Add users if ($data['add']) { $data['add'] = array_map('trim', array_map('utf8_clean_string', explode("\n", $data['add']))); @@ -124,6 +136,10 @@ class ucp_zebra { $user_id_ary[] = $row['user_id']; } + else if ($row['user_id'] != ANONYMOUS) + { + $error[] = $user->lang['NOT_ADDED_' . $l_mode . '_BOTS']; + } else { $error[] = $user->lang['NOT_ADDED_' . $l_mode . '_ANONYMOUS']; @@ -183,18 +199,6 @@ class ucp_zebra } } } - else if (sizeof($data['usernames'])) - { - // Force integer values - $data['usernames'] = array_map('intval', $data['usernames']); - - $sql = 'DELETE FROM ' . ZEBRA_TABLE . ' - WHERE user_id = ' . $user->data['user_id'] . ' - AND ' . $db->sql_in_set('zebra_id', $data['usernames']); - $db->sql_query($sql); - - $updated = true; - } if ($updated) { diff --git a/phpBB/includes/utf/utf_tools.php b/phpBB/includes/utf/utf_tools.php index 8098176837..6f3ac93305 100644 --- a/phpBB/includes/utf/utf_tools.php +++ b/phpBB/includes/utf/utf_tools.php @@ -70,7 +70,7 @@ if (!extension_loaded('xml')) $pos = 0; $len = strlen($str); $ret = ''; - + while ($pos < $len) { $ord = ord($str[$pos]) & 0xF0; @@ -252,7 +252,7 @@ else if (is_null($offset)) { $ar = explode($needle, $str); - + if (sizeof($ar) > 1) { // Pop off the end of the string where the last match was made @@ -527,7 +527,7 @@ else $op = '^(?:' . $op . '.{' . $oy . '})'; } else - { + { // offset == 0; just anchor the pattern $op = '^'; } @@ -560,7 +560,7 @@ else $lx = (int) ($length / 65535); $ly = $length % 65535; - + // negative length requires a captured group // of length characters if ($lx) @@ -632,7 +632,7 @@ function utf8_str_split($str, $split_len = 1) { return array($str); } - + preg_match_all('/.{' . $split_len . '}|[^\x00]{1,' . $split_len . '}$/us', $str, $ar); return $ar[0]; } @@ -1917,4 +1917,79 @@ function utf8_wordwrap($string, $width = 75, $break = "\n", $cut = false) return implode($break, $new_lines); } +/** +* UTF8-safe basename() function +* +* basename() has some limitations and is dependent on the locale setting +* according to the PHP manual. Therefore we provide our own locale independant +* basename function. +* +* @param string $filename The filename basename() should be applied to +* @return string The basenamed filename +*/ +function utf8_basename($filename) +{ + // We always check for forward slash AND backward slash + // because they could be mixed or "sneaked" in. ;) + // You know, never trust user input... + if (strpos($filename, '/') !== false) + { + $filename = utf8_substr($filename, utf8_strrpos($filename, '/') + 1); + } + + if (strpos($filename, '\\') !== false) + { + $filename = utf8_substr($filename, utf8_strrpos($filename, '\\') + 1); + } + + return $filename; +} + +/** +* UTF8-safe str_replace() function +* +* @param string $search The value to search for +* @param string $replace The replacement string +* @param string $subject The target string +* @return string The resultant string +*/ +function utf8_str_replace($search, $replace, $subject) +{ + if (!is_array($search)) + { + $search = array($search); + if (is_array($replace)) + { + $replace = (string) $replace; + trigger_error('Array to string conversion', E_USER_NOTICE); + } + } + + $length = sizeof($search); + + if (!is_array($replace)) + { + $replace = array_fill(0, $length, $replace); + } + else + { + $replace = array_pad($replace, $length, ''); + } + + for ($i = 0; $i < $length; $i++) + { + $search_length = utf8_strlen($search[$i]); + $replace_length = utf8_strlen($replace[$i]); + + $offset = 0; + while (($start = utf8_strpos($subject, $search[$i], $offset)) !== false) + { + $subject = utf8_substr($subject, 0, $start) . $replace[$i] . utf8_substr($subject, $start + $search_length); + $offset = $start + $replace_length; + } + } + + return $subject; +} + ?> \ No newline at end of file diff --git a/phpBB/index.php b/phpBB/index.php index 2d1329c511..c3dbbd346e 100644 --- a/phpBB/index.php +++ b/phpBB/index.php @@ -84,10 +84,13 @@ $birthday_list = ''; if ($config['load_birthdays'] && $config['allow_birthdays']) { $now = getdate(time() + $user->timezone + $user->dst - date('Z')); - $sql = 'SELECT user_id, username, user_colour, user_birthday - FROM ' . USERS_TABLE . " - WHERE user_birthday LIKE '" . $db->sql_escape(sprintf('%2d-%2d-', $now['mday'], $now['mon'])) . "%' - AND user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')'; + $sql = 'SELECT u.user_id, u.username, u.user_colour, u.user_birthday + FROM ' . USERS_TABLE . ' u + LEFT JOIN ' . BANLIST_TABLE . " b ON (u.user_id = b.ban_userid) + WHERE (b.ban_id IS NULL + OR b.ban_exclude = 1) + AND u.user_birthday LIKE '" . $db->sql_escape(sprintf('%2d-%2d-', $now['mday'], $now['mon'])) . "%' + AND u.user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')'; $result = $db->sql_query($sql); while ($row = $db->sql_fetchrow($result)) diff --git a/phpBB/install/convertors/convert_phpbb20.php b/phpBB/install/convertors/convert_phpbb20.php index 805c67b92d..f4fc466ac7 100644 --- a/phpBB/install/convertors/convert_phpbb20.php +++ b/phpBB/install/convertors/convert_phpbb20.php @@ -611,6 +611,7 @@ if (!$get_info) 'query_first' => array('target', $convert->truncate_statement . POSTS_TABLE), 'execute_first' => ' $config["max_post_chars"] = 0; + $config["min_post_chars"] = 0; $config["max_quote_depth"] = 0; ', @@ -660,6 +661,7 @@ if (!$get_info) 'execute_first' => ' $config["max_post_chars"] = 0; + $config["min_post_chars"] = 0; $config["max_quote_depth"] = 0; ', diff --git a/phpBB/install/convertors/functions_phpbb20.php b/phpBB/install/convertors/functions_phpbb20.php index 124bbe83ce..b80c7673e3 100644 --- a/phpBB/install/convertors/functions_phpbb20.php +++ b/phpBB/install/convertors/functions_phpbb20.php @@ -71,8 +71,8 @@ function phpbb_insert_forums() $result = $src_db->sql_query($sql); $prune_enabled = (int) $src_db->sql_fetchfield('config_value'); $src_db->sql_freeresult($result); - - + + // Insert categories $sql = 'SELECT cat_id, cat_title FROM ' . $convert->src_table_prefix . 'categories @@ -227,6 +227,7 @@ function phpbb_insert_forums() 'prune_freq' => (int) null_to_zero($row['prune_freq']), 'forum_flags' => phpbb_forum_flags(), + 'forum_options' => 0, // Default values 'forum_desc_bitfield' => '', @@ -972,12 +973,12 @@ function phpbb_convert_authentication($mode) { // And now the moderators // We make sure that they have at least standard access to the forums they moderate in addition to the moderating permissions - + $mod_post_map = array( 'auth_announce' => 'f_announce', 'auth_sticky' => 'f_sticky' ); - + foreach ($user_access as $forum_id => $access_map) { $forum_id = (int) $forum_id; @@ -1229,7 +1230,7 @@ function phpbb_prepare_message($message) { $message = preg_replace('/\[quote="(.*?)"\]/s', '[quote="\1"]', $message); $message = preg_replace('/\[quote=\\\"(.*?)\\\"\]/s', '[quote="\1"]', $message); - + // let's hope that this solves more problems than it causes. Deal with escaped quotes. $message = str_replace('\"', '"', $message); $message = str_replace('\"', '"', $message); @@ -1258,7 +1259,7 @@ function phpbb_prepare_message($message) // parse($allow_bbcode, $allow_magic_url, $allow_smilies, $allow_img_bbcode = true, $allow_flash_bbcode = true, $allow_quote_bbcode = true, $allow_url_bbcode = true, $update_this_message = true, $mode = 'post') $message_parser->parse($enable_bbcode, $enable_magic_url, $enable_smilies); - + if (sizeof($message_parser->warn_msg)) { $msg_id = isset($convert->row['post_id']) ? $convert->row['post_id'] : $convert->row['privmsgs_id']; @@ -1352,7 +1353,7 @@ function phpbb_copy_thumbnails() global $db, $convert, $user, $config, $cache, $phpbb_root_path; $src_path = $convert->options['forum_path'] . '/' . phpbb_get_files_dir() . '/thumbs/'; - + if ($handle = @opendir($src_path)) { while ($entry = readdir($handle)) @@ -1431,13 +1432,13 @@ function phpbb_attachment_forum_perms($forum_permissions) $pos--; continue; } - + $forum_auth = substr($forum_permissions, $pos, $auth_len); $forum_id = base64_unpack($forum_auth); $forum_ids[] = (int) $forum_id; } - + if (sizeof($forum_ids)) { return attachment_forum_perms($forum_ids); @@ -1516,7 +1517,7 @@ function phpbb_import_avatar($user_avatar) function phpbb_get_avatar_height($user_avatar) { global $convert_row; - + if (empty($convert_row['user_avatar_type'])) { return 0; @@ -1536,7 +1537,7 @@ function phpbb_get_avatar_width($user_avatar) { return 0; } - + return get_avatar_width($user_avatar, 'phpbb_avatar_type', $convert_row['user_avatar_type']); } @@ -1708,7 +1709,7 @@ function phpbb_create_userconv_table() case 'mysql': $map_dbms = 'mysql_40'; break; - + case 'mysql4': if (version_compare($db->sql_server_info(true), '4.1.3', '>=')) { @@ -1719,16 +1720,16 @@ function phpbb_create_userconv_table() $map_dbms = 'mysql_40'; } break; - + case 'mysqli': $map_dbms = 'mysql_41'; break; - + case 'mssql': case 'mssql_odbc': $map_dbms = 'mssql'; break; - + default: $map_dbms = $db->sql_layer; break; diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index c66ac859cf..41983400fc 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -8,11 +8,14 @@ * */ -$updates_to_version = '3.0.5'; +$updates_to_version = '3.0.6-RC1'; // Enter any version to update from to test updates. The version within the db will not be updated. $debug_from_version = false; +// Which oldest version does this updater support? +$oldest_from_version = '3.0.0'; + // Return if we "just include it" to find out for which version the database update is responsible for if (defined('IN_PHPBB') && defined('IN_INSTALL')) { @@ -219,6 +222,33 @@ if (empty($config['dbms_version'])) set_config('dbms_version', $db->sql_server_info(true)); } +// Firebird update from Firebord 2.0 to 2.1+ required? +if ($db->sql_layer == 'firebird') +{ + // We do not trust any PHP5 function enabled, we will simply test for a function new in 2.1 + $db->sql_return_on_error(true); + + $sql = 'SELECT 1 FROM RDB$DATABASE + WHERE BIN_AND(10, 1) = 0'; + $result = $db->sql_query($sql); + + if (!$result || $db->sql_error_triggered) + { + echo '

    '; + echo '

    ' . $lang['ERROR'] . '


    '; + + echo '

    ' . $lang['FIREBIRD_DBMS_UPDATE_REQUIRED'] . '

    '; + + _print_footer(); + + exit_handler(); + exit; + } + + $db->sql_freeresult($result); + $db->sql_return_on_error(false); +} + // MySQL update from MySQL 3.x/4.x to > 4.1.x required? if ($db->sql_layer == 'mysql' || $db->sql_layer == 'mysql4' || $db->sql_layer == 'mysqli') { @@ -246,28 +276,25 @@ if ($db->sql_layer == 'mysql' || $db->sql_layer == 'mysql4' || $db->sql_layer == echo '

    ' . $lang['ERROR'] . '


    '; echo '

    ' . sprintf($lang['MYSQL_SCHEMA_UPDATE_REQUIRED'], $config['dbms_version'], $db->sql_server_info(true)) . '

    '; -?> -
    - - - - - - - - - - -

    ' . $lang['ERROR'] . '


    '; + echo '

    ' . sprintf($lang['DB_UPDATE_NOT_SUPPORTED'], $oldest_from_version, $current_version) . '

    '; + + _print_footer(); + exit_handler(); + exit; +} + // If the latest version and the current version are 'unequal', we will update the version_update_from, else we do not update anything. if ($inline_update) { @@ -452,8 +479,21 @@ add_log('admin', 'LOG_UPDATE_DATABASE', $orig_version, $updates_to_version); // Now we purge the session table as well as all cache files $cache->purge(); -?> +_print_footer(); +garbage_collection(); + +if (function_exists('exit_handler')) +{ + exit_handler(); +} + +/** +* Print out footer +*/ +function _print_footer() +{ + echo << @@ -468,14 +508,7 @@ $cache->purge(); - -sql_error_sql; - $error_ary['error_code'][] = $db->_sql_error(); + $error_ary['error_code'][] = $db->sql_error_returned; } $db->sql_return_on_error(false); @@ -542,6 +575,130 @@ function _write_result($no_updates, $errored, $error_ary) } } +function _add_modules($modules_to_install) +{ + global $phpbb_root_path, $phpEx, $db; + + include_once($phpbb_root_path . 'includes/acp/acp_modules.' . $phpEx); + + $_module = new acp_modules(); + + foreach ($modules_to_install as $module_mode => $module_data) + { + $_module->module_class = $module_data['class']; + + // Determine parent id first + $sql = 'SELECT module_id + FROM ' . MODULES_TABLE . " + WHERE module_class = '" . $db->sql_escape($module_data['class']) . "' + AND module_langname = '" . $db->sql_escape($module_data['cat']) . "' + AND module_mode = '' + AND module_basename = ''"; + $result = $db->sql_query($sql); + + // There may be more than one categories with the same name + $categories = array(); + while ($row = $db->sql_fetchrow($result)) + { + $categories[] = (int) $row['module_id']; + } + $db->sql_freeresult($result); + + if (!sizeof($categories)) + { + continue; + } + + // Add the module to all categories found + foreach ($categories as $parent_id) + { + // Check if the module already exists + $sql = 'SELECT * + FROM ' . MODULES_TABLE . " + WHERE module_basename = '" . $db->sql_escape($module_data['base']) . "' + AND module_class = '" . $db->sql_escape($module_data['class']) . "' + AND module_langname = '" . $db->sql_escape($module_data['title']) . "' + AND module_mode = '" . $db->sql_escape($module_mode) . "' + AND module_auth = '" . $db->sql_escape($module_data['auth']) . "' + AND parent_id = {$parent_id}"; + $result = $db->sql_query($sql); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + // If it exists, we simply continue with the next category + if ($row) + { + continue; + } + + // Build the module sql row + $module_row = array( + 'module_basename' => $module_data['base'], + 'module_enabled' => (isset($module_data['enabled'])) ? (int) $module_data['enabled'] : 1, + 'module_display' => (isset($module_data['display'])) ? (int) $module_data['display'] : 1, + 'parent_id' => $parent_id, + 'module_class' => $module_data['class'], + 'module_langname' => $module_data['title'], + 'module_mode' => $module_mode, + 'module_auth' => $module_data['auth'], + ); + + $_module->update_module_data($module_row, true); + + // Ok, do we need to re-order the module, move it up or down? + if (!isset($module_data['after'])) + { + continue; + } + + $after_mode = $module_data['after'][0]; + $after_langname = $module_data['after'][1]; + + // First of all, get the module id for the module this one has to be placed after + $sql = 'SELECT left_id + FROM ' . MODULES_TABLE . " + WHERE module_class = '" . $db->sql_escape($module_data['class']) . "' + AND module_basename = '" . $db->sql_escape($module_data['base']) . "' + AND module_langname = '" . $db->sql_escape($after_langname) . "' + AND module_mode = '" . $db->sql_escape($after_mode) . "' + AND parent_id = '{$parent_id}'"; + $result = $db->sql_query($sql); + $first_left_id = (int) $db->sql_fetchfield('left_id'); + $db->sql_freeresult($result); + + if (!$first_left_id) + { + continue; + } + + // Ok, count the number of modules between $after_mode and the added module + $sql = 'SELECT COUNT(module_id) as num_modules + FROM ' . MODULES_TABLE . " + WHERE module_class = '" . $db->sql_escape($module_data['class']) . "' + AND parent_id = {$parent_id} + AND left_id BETWEEN {$first_left_id} AND {$module_row['left_id']} + GROUP BY left_id + ORDER BY left_id"; + $result = $db->sql_query($sql); + $steps = (int) $db->sql_fetchfield('num_modules'); + $db->sql_freeresult($result); + + // We need to substract 2 + $steps -= 2; + + if ($steps <= 0) + { + continue; + } + + // Ok, move module up $num_modules times. ;) + $_module->move_module_by($module_row, 'move_up', $steps); + } + } + + $_module->remove_cache_file(); +} + /**************************************************************************** * ADD YOUR DATABASE SCHEMA CHANGES HERE * *****************************************************************************/ @@ -677,6 +834,52 @@ function database_update_info() // No changes from 3.0.5-RC1 to 3.0.5 '3.0.5-RC1' => array(), + + // Changes from 3.0.5 to 3.0.6-RC1 + '3.0.5' => array( + 'add_columns' => array( + CONFIRM_TABLE => array( + 'attempts' => array('UINT', 0), + ), + USERS_TABLE => array( + 'user_new' => array('BOOL', 1), + 'user_reminded' => array('TINT:4', 0), + 'user_reminded_time'=> array('TIMESTAMP', 0), + ), + GROUPS_TABLE => array( + 'group_skip_auth' => array('BOOL', 0, 'after' => 'group_founder_manage'), + ), + PRIVMSGS_TABLE => array( + 'message_reported' => array('BOOL', 0), + ), + REPORTS_TABLE => array( + 'pm_id' => array('UINT', 0), + ), + PROFILE_FIELDS_TABLE => array( + 'field_show_on_vt' => array('BOOL', 0), + ), + FORUMS_TABLE => array( + 'forum_options' => array('UINT:20', 0), + ), + ), + 'change_columns' => array( + USERS_TABLE => array( + 'user_options' => array('UINT:11', 230271), + ), + ), + 'add_index' => array( + LOG_TABLE => array( + 'log_time' => array('log_time'), + ), + REPORTS_TABLE => array( + 'post_id' => array('post_id'), + 'pm_id' => array('pm_id'), + ), + POSTS_TABLE => array( + 'post_username' => array('post_username'), + ), + ), + ), ); } @@ -903,7 +1106,6 @@ function change_database_data(&$no_updates, $version) set_config('captcha_gd_wave', 0); set_config('captcha_gd_3d_noise', 1); set_config('captcha_gd_fonts', 1); - set_config('confirm_refresh', 1); // Maximum number of keywords @@ -940,6 +1142,7 @@ function change_database_data(&$no_updates, $version) WHERE bot_agent = 'ichiro/2'"; _sql($sql, $errored, $error_ary); + // Before we are able to add a unique key to auth_option, we need to remove duplicate entries // We get duplicate entries first @@ -1012,6 +1215,297 @@ function change_database_data(&$no_updates, $version) // No changes from 3.0.5-RC1 to 3.0.5 case '3.0.5-RC1': break; + + // Changes from 3.0.5 to 3.0.6-RC1 + case '3.0.5': + // Let's see if the GD Captcha can be enabled... we simply look for what *is* enabled... + if (!empty($config['captcha_gd']) && !isset($config['captcha_plugin'])) + { + set_config('captcha_plugin', 'phpbb_captcha_gd'); + } + else if (!isset($config['captcha_plugin'])) + { + set_config('captcha_plugin', 'phpbb_captcha_nogd'); + } + + // Entries for the Feed Feature + set_config('feed_enable', '0'); + set_config('feed_limit', '10'); + + set_config('feed_overall_forums', '1'); + set_config('feed_overall_forums_limit', '15'); + + set_config('feed_overall_topics', '0'); + set_config('feed_overall_topics_limit', '15'); + + set_config('feed_forum', '1'); + set_config('feed_topic', '1'); + set_config('feed_item_statistics', '1'); + + // Entries for smiley pagination + set_config('smilies_per_page', '50'); + + // Entry for reporting PMs + set_config('allow_pm_report', '1'); + + // Install modules + $modules_to_install = array( + 'feed' => array( + 'base' => 'board', + 'class' => 'acp', + 'title' => 'ACP_FEED_SETTINGS', + 'auth' => 'acl_a_board', + 'cat' => 'ACP_BOARD_CONFIGURATION', + 'after' => array('signature', 'ACP_SIGNATURE_SETTINGS') + ), + 'warnings' => array( + 'base' => 'users', + 'class' => 'acp', + 'title' => 'ACP_USER_WARNINGS', + 'auth' => 'acl_a_user', + 'display' => 0, + 'cat' => 'ACP_CAT_USERS', + 'after' => array('feedback', 'ACP_USER_FEEDBACK') + ), + 'send_statistics' => array( + 'base' => 'send_statistics', + 'class' => 'acp', + 'title' => 'ACP_SEND_STATISTICS', + 'auth' => 'acl_a_server', + 'cat' => 'ACP_SERVER_CONFIGURATION' + ), + 'setting_forum_copy' => array( + 'base' => 'permissions', + 'class' => 'acp', + 'title' => 'ACP_FORUM_PERMISSIONS_COPY', + 'auth' => 'acl_a_fauth && acl_a_authusers && acl_a_authgroups && acl_a_mauth', + 'cat' => 'ACP_FORUM_BASED_PERMISSIONS', + 'after' => array('setting_forum_local', 'ACP_FORUM_PERMISSIONS') + ), + 'pm_reports' => array( + 'base' => 'pm_reports', + 'class' => 'mcp', + 'title' => 'MCP_PM_REPORTS_OPEN', + 'auth' => 'aclf_m_report', + 'cat' => 'MCP_REPORTS' + ), + 'pm_reports_closed' => array( + 'base' => 'pm_reports', + 'class' => 'mcp', + 'title' => 'MCP_PM_REPORTS_CLOSED', + 'auth' => 'aclf_m_report', + 'cat' => 'MCP_REPORTS' + ), + 'pm_report_details' => array( + 'base' => 'pm_reports', + 'class' => 'mcp', + 'title' => 'MCP_PM_REPORT_DETAILS', + 'auth' => 'aclf_m_report', + 'cat' => 'MCP_REPORTS' + ), + ); + + _add_modules($modules_to_install); + + // Add newly_registered group... but check if it already exists (we always supported running the updater on any schema) + $sql = 'SELECT group_id + FROM ' . GROUPS_TABLE . " + WHERE group_name = 'NEWLY_REGISTERED'"; + $result = $db->sql_query($sql); + $group_id = (int) $db->sql_fetchfield('group_id'); + $db->sql_freeresult($result); + + if (!$group_id) + { + $sql = 'INSERT INTO ' . GROUPS_TABLE . " (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('NEWLY_REGISTERED', 3, 0, '', 0, '', '', '', 5)"; + _sql($sql, $errored, $error_ary); + + $group_id = $db->sql_nextid(); + } + + // Insert new user role... at the end of the chain + $sql = 'SELECT role_id + FROM ' . ACL_ROLES_TABLE . " + WHERE role_name = 'ROLE_USER_NEW_MEMBER' + AND role_type = 'u_'"; + $result = $db->sql_query($sql); + $u_role = (int) $db->sql_fetchfield('role_id'); + $db->sql_freeresult($result); + + if (!$u_role) + { + $sql = 'SELECT MAX(role_order) as max_order_id + FROM ' . ACL_ROLES_TABLE . " + WHERE role_type = 'u_'"; + $result = $db->sql_query($sql); + $next_order_id = (int) $db->sql_fetchfield('max_order_id'); + $db->sql_freeresult($result); + + $next_order_id++; + + $sql = 'INSERT INTO ' . ACL_ROLES_TABLE . " (role_name, role_description, role_type, role_order) VALUES ('ROLE_USER_NEW_MEMBER', 'ROLE_DESCRIPTION_USER_NEW_MEMBER', 'u_', $next_order_id)"; + _sql($sql, $errored, $error_ary); + $u_role = $db->sql_nextid(); + + if (!$errored) + { + // Now add the correct data to the roles... + // The standard role says that new users are not able to send a PM, Mass PM, are not able to PM groups + $sql = 'INSERT INTO ' . ACL_ROLES_DATA_TABLE . " (role_id, auth_option_id, auth_setting) SELECT $u_role, auth_option_id, 0 FROM " . ACL_OPTIONS_TABLE . " WHERE auth_option LIKE 'u_%' AND auth_option IN ('u_sendpm', 'u_masspm', 'u_masspm_group')"; + _sql($sql, $errored, $error_ary); + + // Add user role to group + $sql = 'INSERT INTO ' . ACL_GROUPS_TABLE . " (group_id, forum_id, auth_option_id, auth_role_id, auth_setting) VALUES ($group_id, 0, 0, $u_role, 0)"; + _sql($sql, $errored, $error_ary); + } + } + + // Insert new forum role + $sql = 'SELECT role_id + FROM ' . ACL_ROLES_TABLE . " + WHERE role_name = 'ROLE_FORUM_NEW_MEMBER' + AND role_type = 'f_'"; + $result = $db->sql_query($sql); + $f_role = (int) $db->sql_fetchfield('role_id'); + $db->sql_freeresult($result); + + if (!$f_role) + { + $sql = 'SELECT MAX(role_order) as max_order_id + FROM ' . ACL_ROLES_TABLE . " + WHERE role_type = 'f_'"; + $result = $db->sql_query($sql); + $next_order_id = (int) $db->sql_fetchfield('max_order_id'); + $db->sql_freeresult($result); + + $next_order_id++; + + $sql = 'INSERT INTO ' . ACL_ROLES_TABLE . " (role_name, role_description, role_type, role_order) VALUES ('ROLE_FORUM_NEW_MEMBER', 'ROLE_DESCRIPTION_FORUM_NEW_MEMBER', 'f_', $next_order_id)"; + _sql($sql, $errored, $error_ary); + $f_role = $db->sql_nextid(); + + if (!$errored) + { + $sql = 'INSERT INTO ' . ACL_ROLES_DATA_TABLE . " (role_id, auth_option_id, auth_setting) SELECT $f_role, auth_option_id, 0 FROM " . ACL_OPTIONS_TABLE . " WHERE auth_option LIKE 'f_%' AND auth_option IN ('f_noapprove')"; + _sql($sql, $errored, $error_ary); + } + } + + // Set every members user_new column to 0 (old users) only if there is no one yet (this makes sure we do not execute this more than once) + $sql = 'SELECT 1 + FROM ' . USERS_TABLE . ' + WHERE user_new = 0'; + $result = $db->sql_query_limit($sql, 1); + $row = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if (!$row) + { + $sql = 'UPDATE ' . USERS_TABLE . ' SET user_new = 0'; + _sql($sql, $errored, $error_ary); + } + + // Newly registered users limit + if (!isset($config['new_member_post_limit'])) + { + set_config('new_member_post_limit', (!empty($config['enable_queue_trigger'])) ? $config['queue_trigger_posts'] : 0); + } + + if (!isset($config['new_member_group_default'])) + { + set_config('new_member_group_default', 0); + } + + // To mimick the old "feature" we will assign the forum role to every forum, regardless of the setting (this makes sure there are no "this does not work!!!! YUO!!!" posts... + // Check if the role is already assigned... + $sql = 'SELECT forum_id + FROM ' . ACL_GROUPS_TABLE . ' + WHERE group_id = ' . $group_id . ' + AND auth_role_id = ' . $f_role; + $result = $db->sql_query($sql); + $is_options = (int) $db->sql_fetchfield('forum_id'); + $db->sql_freeresult($result); + + // Not assigned at all... :/ + if (!$is_options) + { + // Get postable forums + $sql = 'SELECT forum_id + FROM ' . FORUMS_TABLE . ' + WHERE forum_type != ' . FORUM_LINK; + $result = $db->sql_query($sql); + + while ($row = $db->sql_fetchrow($result)) + { + _sql('INSERT INTO ' . ACL_GROUPS_TABLE . ' (group_id, forum_id, auth_option_id, auth_role_id, auth_setting) VALUES (' . $group_id . ', ' . (int) $row['forum_id'] . ', 0, ' . $f_role . ', 0)', $errored, $error_ary); + } + $db->sql_freeresult($result); + } + + // Clear permissions... + include_once($phpbb_root_path . 'includes/acp/auth.' . $phpEx); + $auth_admin = new auth_admin(); + $auth_admin->acl_clear_prefetch(); + + if (!isset($config['allow_avatar'])) + { + if ($config['allow_avatar_upload'] || $config['allow_avatar_local'] || $config['allow_avatar_remote']) + { + set_config('allow_avatar', '1'); + } + else + { + set_config('allow_avatar', '0'); + } + } + + if (!isset($config['allow_avatar_remote_upload'])) + { + if ($config['allow_avatar_remote'] && $config['allow_avatar_upload']) + { + set_config('allow_avatar_remote_upload', '1'); + } + else + { + set_config('allow_avatar_remote_upload', '0'); + } + } + + // Minimum number of characters + if (!isset($config['min_post_chars'])) + { + set_config('min_post_chars', '1'); + } + + if (!isset($config['allow_quick_reply'])) + { + set_config('allow_quick_reply', '1'); + } + + // Set every members user_options column to enable + // bbcode, smilies and URLs for signatures by default + $sql = 'SELECT user_options + FROM ' . USERS_TABLE . ' + WHERE user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')'; + $result = $db->sql_query_limit($sql, 1); + $user_option = (int) $db->sql_fetchfield('user_options'); + $db->sql_freeresult($result); + + // Check if we already updated the database by checking bit 15 which we used to store the sig_bbcode option + if (!($user_option & 1 << 15)) + { + // 229376 is the added value to enable all three signature options + $sql = 'UPDATE ' . USERS_TABLE . ' SET user_options = user_options + 229376'; + _sql($sql, $errored, $error_ary); + } + + if (!isset($config['delete_time'])) + { + set_config('delete_time', $config['edit_time']); + } + + $no_updates = false; + break; } } @@ -1340,6 +1834,14 @@ class updater_db_tools } $statements = array(); + $sqlite = false; + + // For SQLite we need to perform the schema changes in a much more different way + if ($this->db->sql_layer == 'sqlite' && $this->return_statements) + { + $sqlite_data = array(); + $sqlite = true; + } // Change columns? if (!empty($schema_changes['change_columns'])) @@ -1349,16 +1851,27 @@ class updater_db_tools foreach ($columns as $column_name => $column_data) { // If the column exists we change it, else we add it ;) - if ($this->sql_column_exists($table, $column_name)) + if ($column_exists = $this->sql_column_exists($table, $column_name)) { - $result = $this->sql_column_change($table, $column_name, $column_data); + $result = $this->sql_column_change($table, $column_name, $column_data, true); } else { - $result = $this->sql_column_add($table, $column_name, $column_data); + $result = $this->sql_column_add($table, $column_name, $column_data, true); } - if ($this->return_statements) + if ($sqlite) + { + if ($column_exists) + { + $sqlite_data[$table]['change_columns'][] = $result; + } + else + { + $sqlite_data[$table]['add_columns'][] = $result; + } + } + else if ($this->return_statements) { $statements = array_merge($statements, $result); } @@ -1373,17 +1886,30 @@ class updater_db_tools { foreach ($columns as $column_name => $column_data) { - // Only add the column if it does not exist yet, else change it (to be consistent) - if ($this->sql_column_exists($table, $column_name)) + // Only add the column if it does not exist yet + if ($column_exists = $this->sql_column_exists($table, $column_name)) { - $result = $this->sql_column_change($table, $column_name, $column_data); + continue; + // This is commented out here because it can take tremendous time on updates +// $result = $this->sql_column_change($table, $column_name, $column_data, true); } else { - $result = $this->sql_column_add($table, $column_name, $column_data); + $result = $this->sql_column_add($table, $column_name, $column_data, true); } - if ($this->return_statements) + if ($sqlite) + { + if ($column_exists) + { + $sqlite_data[$table]['change_columns'][] = $result; + } + else + { + $sqlite_data[$table]['add_columns'][] = $result; + } + } + else if ($this->return_statements) { $statements = array_merge($statements, $result); } @@ -1418,9 +1944,13 @@ class updater_db_tools // Only remove the column if it exists... if ($this->sql_column_exists($table, $column)) { - $result = $this->sql_column_remove($table, $column); + $result = $this->sql_column_remove($table, $column, true); - if ($this->return_statements) + if ($sqlite) + { + $sqlite_data[$table]['drop_columns'][] = $result; + } + else if ($this->return_statements) { $statements = array_merge($statements, $result); } @@ -1434,9 +1964,13 @@ class updater_db_tools { foreach ($schema_changes['add_primary_keys'] as $table => $columns) { - $result = $this->sql_create_primary_key($table, $columns); + $result = $this->sql_create_primary_key($table, $columns, true); - if ($this->return_statements) + if ($sqlite) + { + $sqlite_data[$table]['primary_key'] = $result; + } + else if ($this->return_statements) { $statements = array_merge($statements, $result); } @@ -1477,6 +2011,147 @@ class updater_db_tools } } + if ($sqlite) + { + foreach ($sqlite_data as $table_name => $sql_schema_changes) + { + // Create temporary table with original data + $statements[] = 'begin'; + + $sql = "SELECT sql + FROM sqlite_master + WHERE type = 'table' + AND name = '{$table_name}' + ORDER BY type DESC, name;"; + $result = $this->db->sql_query($sql); + + if (!$result) + { + continue; + } + + $row = $this->db->sql_fetchrow($result); + $this->db->sql_freeresult($result); + + // Create a backup table and populate it, destroy the existing one + $statements[] = preg_replace('#CREATE\s+TABLE\s+"?' . $table_name . '"?#i', 'CREATE TEMPORARY TABLE ' . $table_name . '_temp', $row['sql']); + $statements[] = 'INSERT INTO ' . $table_name . '_temp SELECT * FROM ' . $table_name; + $statements[] = 'DROP TABLE ' . $table_name; + + // Get the columns... + preg_match('#\((.*)\)#s', $row['sql'], $matches); + + $plain_table_cols = trim($matches[1]); + $new_table_cols = preg_split('/,(?![\s\w]+\))/m', $plain_table_cols); + $column_list = array(); + + foreach ($new_table_cols as $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + if ($entities[0] == 'PRIMARY') + { + continue; + } + $column_list[] = $entities[0]; + } + + // note down the primary key notation because sqlite only supports adding it to the end for the new table + $primary_key = false; + $_new_cols = array(); + + foreach ($new_table_cols as $key => $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + if ($entities[0] == 'PRIMARY') + { + $primary_key = $declaration; + continue; + } + $_new_cols[] = $declaration; + } + + $new_table_cols = $_new_cols; + + // First of all... change columns + if (!empty($sql_schema_changes['change_columns'])) + { + foreach ($sql_schema_changes['change_columns'] as $column_sql) + { + foreach ($new_table_cols as $key => $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + if (strpos($column_sql, $entities[0] . ' ') === 0) + { + $new_table_cols[$key] = $column_sql; + } + } + } + } + + if (!empty($sql_schema_changes['add_columns'])) + { + foreach ($sql_schema_changes['add_columns'] as $column_sql) + { + $new_table_cols[] = $column_sql; + } + } + + // Now drop them... + if (!empty($sql_schema_changes['drop_columns'])) + { + foreach ($sql_schema_changes['drop_columns'] as $column_name) + { + // Remove from column list... + $new_column_list = array(); + foreach ($column_list as $key => $value) + { + if ($value === $column_name) + { + continue; + } + + $new_column_list[] = $value; + } + + $column_list = $new_column_list; + + // Remove from table... + $_new_cols = array(); + foreach ($new_table_cols as $key => $declaration) + { + $entities = preg_split('#\s+#', trim($declaration)); + if (strpos($column_name . ' ', $entities[0] . ' ') === 0) + { + continue; + } + $_new_cols[] = $declaration; + } + $new_table_cols = $_new_cols; + } + } + + // Primary key... + if (!empty($sql_schema_changes['primary_key'])) + { + $new_table_cols[] = 'PRIMARY KEY (' . implode(', ', $sql_schema_changes['primary_key']) . ')'; + } + // Add a new one or the old primary key + else if ($primary_key !== false) + { + $new_table_cols[] = $primary_key; + } + + $columns = implode(',', $column_list); + + // create a new table and fill it up. destroy the temp one + $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $new_table_cols) . ');'; + $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;'; + $statements[] = 'DROP TABLE ' . $table_name . '_temp'; + + $statements[] = 'commit'; + } + } + if ($this->return_statements) { return $statements; @@ -1561,7 +2236,7 @@ class updater_db_tools case 'oracle': $sql = "SELECT column_name FROM user_tab_columns - WHERE table_name = '{$table}'"; + WHERE LOWER(table_name) = '" . strtolower($table) . "'"; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { @@ -1579,7 +2254,7 @@ class updater_db_tools case 'firebird': $sql = "SELECT RDB\$FIELD_NAME as FNAME FROM RDB\$RELATION_FIELDS - WHERE RDB\$RELATION_NAME = '{$table}'"; + WHERE RDB\$RELATION_NAME = '" . strtoupper($table) . "'"; $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { @@ -1732,10 +2407,12 @@ class updater_db_tools { case 'firebird': $sql .= " {$column_type} "; + $return_array['column_type_sql_type'] = " {$column_type} "; if (!is_null($column_data[1])) { $sql .= 'DEFAULT ' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ' '; + $return_array['column_type_sql_default'] = ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ' '; } $sql .= 'NOT NULL'; @@ -1889,7 +2566,7 @@ class updater_db_tools /** * Add new column */ - function sql_column_add($table_name, $column_name, $column_data) + function sql_column_add($table_name, $column_name, $column_data, $inline = false) { $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); $statements = array(); @@ -1897,27 +2574,38 @@ class updater_db_tools switch ($this->sql_layer) { case 'firebird': + // Does not support AFTER statement, only POSITION (and there you need the column position) $statements[] = 'ALTER TABLE ' . $table_name . ' ADD "' . strtoupper($column_name) . '" ' . $column_data['column_type_sql']; break; case 'mssql': + // Does not support AFTER, only through temporary table $statements[] = 'ALTER TABLE [' . $table_name . '] ADD [' . $column_name . '] ' . $column_data['column_type_sql_default']; break; case 'mysql_40': case 'mysql_41': - $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql']; + $after = (!empty($column_data['after'])) ? ' AFTER ' . $column_data['after'] : ''; + $statements[] = 'ALTER TABLE `' . $table_name . '` ADD COLUMN `' . $column_name . '` ' . $column_data['column_type_sql'] . $after; break; case 'oracle': + // Does not support AFTER, only through temporary table $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' ' . $column_data['column_type_sql']; break; case 'postgres': + // Does not support AFTER, only through temporary table $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql']; break; case 'sqlite': + + if ($inline && $this->return_statements) + { + return $column_name . ' ' . $column_data['column_type_sql']; + } + if (version_compare(sqlite_libversion(), '3.0') == -1) { $sql = "SELECT sql @@ -1982,7 +2670,7 @@ class updater_db_tools /** * Drop column */ - function sql_column_remove($table_name, $column_name) + function sql_column_remove($table_name, $column_name, $inline = false) { $statements = array(); @@ -2010,6 +2698,12 @@ class updater_db_tools break; case 'sqlite': + + if ($inline && $this->return_statements) + { + return $column_name; + } + if (version_compare(sqlite_libversion(), '3.0') == -1) { $sql = "SELECT sql @@ -2103,7 +2797,7 @@ class updater_db_tools /** * Add primary key */ - function sql_create_primary_key($table_name, $column) + function sql_create_primary_key($table_name, $column, $inline = false) { $statements = array(); @@ -2130,6 +2824,12 @@ class updater_db_tools break; case 'sqlite': + + if ($inline && $this->return_statements) + { + return $column; + } + $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' @@ -2243,7 +2943,7 @@ class updater_db_tools /** * Change column type (not name!) */ - function sql_column_change($table_name, $column_name, $column_data) + function sql_column_change($table_name, $column_name, $column_data, $inline = false) { $column_data = $this->sql_prepare_column_data($table_name, $column_name, $column_data); $statements = array(); @@ -2252,7 +2952,15 @@ class updater_db_tools { case 'firebird': // Change type... - $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql']; + if (!empty($column_data['column_type_sql_default'])) + { + $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql_type']; + $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" SET DEFAULT ' . ' ' . $column_data['column_type_sql_default']; + } + else + { + $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql']; + } break; case 'mssql': @@ -2333,6 +3041,11 @@ class updater_db_tools case 'sqlite': + if ($inline && $this->return_statements) + { + return $column_name . ' ' . $column_data['column_type_sql']; + } + $sql = "SELECT sql FROM sqlite_master WHERE type = 'table' diff --git a/phpBB/install/index.php b/phpBB/install/index.php index b1eba60af5..47f1787030 100644 --- a/phpBB/install/index.php +++ b/phpBB/install/index.php @@ -175,7 +175,7 @@ if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) && !$language) // Set correct format ... guess full xx_yy form $accept_lang = substr($accept_lang, 0, 2) . '_' . substr($accept_lang, 3, 2); - if (file_exists($phpbb_root_path . 'language/' . $accept_lang)) + if (file_exists($phpbb_root_path . 'language/' . $accept_lang) && is_dir($phpbb_root_path . 'language/' . $accept_lang)) { $language = $accept_lang; break; @@ -184,7 +184,7 @@ if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) && !$language) { // No match on xx_yy so try xx $accept_lang = substr($accept_lang, 0, 2); - if (file_exists($phpbb_root_path . 'language/' . $accept_lang)) + if (file_exists($phpbb_root_path . 'language/' . $accept_lang) && is_dir($phpbb_root_path . 'language/' . $accept_lang)) { $language = $accept_lang; break; @@ -218,7 +218,7 @@ if (!$language) closedir($dir); } -if (!file_exists($phpbb_root_path . 'language/' . $language)) +if (!file_exists($phpbb_root_path . 'language/' . $language) || !is_dir($phpbb_root_path . 'language/' . $language)) { die('No language found!'); } diff --git a/phpBB/install/install_convert.php b/phpBB/install/install_convert.php index 7a4155e09d..7f1b9de5b6 100644 --- a/phpBB/install/install_convert.php +++ b/phpBB/install/install_convert.php @@ -611,7 +611,7 @@ class install_convert extends module $config['max_quote_depth'] = 0; // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues - $config['max_post_chars'] = 0; + $config['max_post_chars'] = $config['min_post_chars'] = 0; // Set up a user as well. We _should_ have enough of a database here at this point to do this // and it helps for any core code we call @@ -989,7 +989,7 @@ class install_convert extends module $config['max_quote_depth'] = 0; // @todo Need to confirm that max post length in source is <= max post length in destination or there may be interesting formatting issues - $config['max_post_chars'] = 0; + $config['max_post_chars'] = $config['min_post_chars'] = 0; } $template->assign_block_vars('checks', array( @@ -1558,7 +1558,7 @@ class install_convert extends module */ function finish_conversion() { - global $db, $phpbb_root_path, $convert, $config, $language, $user, $template; + global $db, $phpbb_root_path, $phpEx, $convert, $config, $language, $user, $template; $db->sql_query('DELETE FROM ' . CONFIG_TABLE . " WHERE config_name = 'convert_progress' @@ -1567,7 +1567,7 @@ class install_convert extends module OR config_name = 'convert_db_user'"); $db->sql_query('DELETE FROM ' . SESSIONS_TABLE); - @unlink($phpbb_root_path . 'cache/data_global.php'); + @unlink($phpbb_root_path . 'cache/data_global.' . $phpEx); cache_moderators(); // And finally, add a note to the log diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php index adb0fb9623..1b8553fb7a 100644 --- a/phpBB/install/install_install.php +++ b/phpBB/install/install_install.php @@ -1337,7 +1337,7 @@ class install_install extends module WHERE config_name = 'avatar_salt'", 'UPDATE ' . $data['table_prefix'] . "users - SET username = '" . $db->sql_escape($data['admin_name']) . "', user_password='" . $db->sql_escape(md5($data['admin_pass1'])) . "', user_ip = '" . $db->sql_escape($user_ip) . "', user_lang = '" . $db->sql_escape($data['default_lang']) . "', user_email='" . $db->sql_escape($data['board_email1']) . "', user_dateformat='" . $db->sql_escape($lang['default_dateformat']) . "', user_email_hash = " . (crc32($data['board_email1']) . strlen($data['board_email1'])) . ", username_clean = '" . $db->sql_escape(utf8_clean_string($data['admin_name'])) . "' + SET username = '" . $db->sql_escape($data['admin_name']) . "', user_password='" . $db->sql_escape(md5($data['admin_pass1'])) . "', user_ip = '" . $db->sql_escape($user_ip) . "', user_lang = '" . $db->sql_escape($data['default_lang']) . "', user_email='" . $db->sql_escape($data['board_email1']) . "', user_dateformat='" . $db->sql_escape($lang['default_dateformat']) . "', user_email_hash = " . $db->sql_escape(phpbb_email_hash($data['board_email1'])) . ", username_clean = '" . $db->sql_escape(utf8_clean_string($data['admin_name'])) . "' WHERE username = 'Admin'", 'UPDATE ' . $data['table_prefix'] . "moderator_cache @@ -1372,6 +1372,10 @@ class install_install extends module if (@extension_loaded('gd') || can_load_dll('gd')) { + $sql_ary[] = 'UPDATE ' . $data['table_prefix'] . "config + SET config_value = 'phpbb_captcha_gd' + WHERE config_name = 'captcha_plugin'"; + $sql_ary[] = 'UPDATE ' . $data['table_prefix'] . "config SET config_value = '1' WHERE config_name = 'captcha_gd'"; @@ -1954,7 +1958,7 @@ class install_install extends module 'TITLE' => $lang['INSTALL_CONGRATS'], 'BODY' => sprintf($lang['INSTALL_CONGRATS_EXPLAIN'], $config['version'], append_sid($phpbb_root_path . 'install/index.' . $phpEx, 'mode=convert&language=' . $data['language']), '../docs/README.html'), 'L_SUBMIT' => $lang['INSTALL_LOGIN'], - 'U_ACTION' => append_sid($phpbb_root_path . 'adm/index.' . $phpEx), + 'U_ACTION' => append_sid($phpbb_root_path . 'adm/index.' . $phpEx, 'i=send_statistics&mode=send_statistics'), )); } @@ -2227,6 +2231,7 @@ class install_install extends module ), 'ACP_FORUM_BASED_PERMISSIONS' => array( 'ACP_FORUM_PERMISSIONS', + 'ACP_FORUM_PERMISSIONS_COPY', 'ACP_FORUM_MODERATORS', 'ACP_USERS_FORUM_PERMISSIONS', 'ACP_GROUPS_FORUM_PERMISSIONS', diff --git a/phpBB/install/install_update.php b/phpBB/install/install_update.php index 388e217133..ad72652e97 100644 --- a/phpBB/install/install_update.php +++ b/phpBB/install/install_update.php @@ -203,10 +203,10 @@ class install_update extends module } // What about the language file? Got it updated? - if (in_array('language/en/install.php', $this->update_info['files'])) + if (in_array('language/en/install.' . $phpEx, $this->update_info['files'])) { $lang = array(); - include($this->new_location . 'language/en/install.php'); + include($this->new_location . 'language/en/install.' . $phpEx); // only add new keys to user's language in english $new_keys = array_diff(array_keys($lang), array_keys($user->lang)); foreach ($new_keys as $i => $new_key) @@ -915,6 +915,11 @@ class install_update extends module // Now init the connection if ($update_mode == 'download') { + if (function_exists('phpbb_is_writable') && !phpbb_is_writable($phpbb_root_path . 'store/')) + { + trigger_error(sprintf($user->lang['DIRECTORY_NOT_WRITABLE'], $phpbb_root_path . 'store/'), E_USER_ERROR); + } + if ($use_method == '.zip') { $compress = new compress_zip('w', $phpbb_root_path . 'store/' . $archive_filename . $use_method); @@ -1551,7 +1556,7 @@ class install_update extends module if ($info === false) { $update_info = array(); - include($phpbb_root_path . 'install/update/index.php'); + include($phpbb_root_path . 'install/update/index.' . $phpEx); $info = (empty($update_info) || !is_array($update_info)) ? false : $update_info; if ($info !== false) @@ -1565,13 +1570,19 @@ class install_update extends module global $phpbb_root_path, $phpEx; $update_info = array(); - include($phpbb_root_path . 'install/update/index.php'); + include($phpbb_root_path . 'install/update/index.' . $phpEx); $info = (empty($update_info) || !is_array($update_info)) ? false : $update_info; $errstr = ($info === false) ? $user->lang['WRONG_INFO_FILE_FORMAT'] : ''; if ($info !== false) { + // We assume that all file extensions have been renamed to .$phpEx, + // if someone is using a non .php file extension for php files. + // However, in $update_info['files'] we use hardcoded .php. + // We therefore replace .php with .$phpEx. + $info['files'] = preg_replace('/\.php$/i', ".$phpEx", $info['files']); + // Adjust the update info file to hold some specific style-related information $info['custom'] = array(); /* diff --git a/phpBB/install/schemas/firebird_schema.sql b/phpBB/install/schemas/firebird_schema.sql index fecbc61dc1..f3defe9a54 100644 --- a/phpBB/install/schemas/firebird_schema.sql +++ b/phpBB/install/schemas/firebird_schema.sql @@ -227,7 +227,8 @@ CREATE TABLE phpbb_confirm ( session_id CHAR(32) CHARACTER SET NONE DEFAULT '' NOT NULL, confirm_type INTEGER DEFAULT 0 NOT NULL, code VARCHAR(8) CHARACTER SET NONE DEFAULT '' NOT NULL, - seed INTEGER DEFAULT 0 NOT NULL + seed INTEGER DEFAULT 0 NOT NULL, + attempts INTEGER DEFAULT 0 NOT NULL );; ALTER TABLE phpbb_confirm ADD PRIMARY KEY (session_id, confirm_id);; @@ -362,6 +363,7 @@ CREATE TABLE phpbb_forums ( forum_last_poster_name VARCHAR(255) CHARACTER SET UTF8 DEFAULT '' NOT NULL COLLATE UNICODE, forum_last_poster_colour VARCHAR(6) CHARACTER SET NONE DEFAULT '' NOT NULL, forum_flags INTEGER DEFAULT 32 NOT NULL, + forum_options INTEGER DEFAULT 0 NOT NULL, display_subforum_list INTEGER DEFAULT 1 NOT NULL, display_on_index INTEGER DEFAULT 1 NOT NULL, enable_indexing INTEGER DEFAULT 1 NOT NULL, @@ -425,6 +427,7 @@ CREATE TABLE phpbb_groups ( group_id INTEGER NOT NULL, group_type INTEGER DEFAULT 1 NOT NULL, group_founder_manage INTEGER DEFAULT 0 NOT NULL, + group_skip_auth INTEGER DEFAULT 0 NOT NULL, group_name VARCHAR(255) CHARACTER SET UTF8 DEFAULT '' NOT NULL COLLATE UNICODE, group_desc BLOB SUB_TYPE TEXT CHARACTER SET UTF8 DEFAULT '' NOT NULL, group_desc_bitfield VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL, @@ -526,6 +529,7 @@ CREATE TABLE phpbb_log ( ALTER TABLE phpbb_log ADD PRIMARY KEY (log_id);; CREATE INDEX phpbb_log_log_type ON phpbb_log(log_type);; +CREATE INDEX phpbb_log_log_time ON phpbb_log(log_time);; CREATE INDEX phpbb_log_forum_id ON phpbb_log(forum_id);; CREATE INDEX phpbb_log_topic_id ON phpbb_log(topic_id);; CREATE INDEX phpbb_log_reportee_id ON phpbb_log(reportee_id);; @@ -647,6 +651,7 @@ CREATE INDEX phpbb_posts_topic_id ON phpbb_posts(topic_id);; CREATE INDEX phpbb_posts_poster_ip ON phpbb_posts(poster_ip);; CREATE INDEX phpbb_posts_poster_id ON phpbb_posts(poster_id);; CREATE INDEX phpbb_posts_post_approved ON phpbb_posts(post_approved);; +CREATE INDEX phpbb_posts_post_username ON phpbb_posts(post_username);; CREATE INDEX phpbb_posts_tid_post_time ON phpbb_posts(topic_id, post_time);; CREATE GENERATOR phpbb_posts_gen;; @@ -682,7 +687,8 @@ CREATE TABLE phpbb_privmsgs ( message_edit_time INTEGER DEFAULT 0 NOT NULL, message_edit_count INTEGER DEFAULT 0 NOT NULL, to_address BLOB SUB_TYPE TEXT CHARACTER SET UTF8 DEFAULT '' NOT NULL, - bcc_address BLOB SUB_TYPE TEXT CHARACTER SET UTF8 DEFAULT '' NOT NULL + bcc_address BLOB SUB_TYPE TEXT CHARACTER SET UTF8 DEFAULT '' NOT NULL, + message_reported INTEGER DEFAULT 0 NOT NULL );; ALTER TABLE phpbb_privmsgs ADD PRIMARY KEY (msg_id);; @@ -786,6 +792,7 @@ CREATE TABLE phpbb_profile_fields ( field_validation VARCHAR(20) CHARACTER SET UTF8 DEFAULT '' NOT NULL COLLATE UNICODE, field_required INTEGER DEFAULT 0 NOT NULL, field_show_on_reg INTEGER DEFAULT 0 NOT NULL, + field_show_on_vt INTEGER DEFAULT 0 NOT NULL, field_show_profile INTEGER DEFAULT 0 NOT NULL, field_hide INTEGER DEFAULT 0 NOT NULL, field_no_view INTEGER DEFAULT 0 NOT NULL, @@ -869,6 +876,7 @@ CREATE TABLE phpbb_reports ( report_id INTEGER NOT NULL, reason_id INTEGER DEFAULT 0 NOT NULL, post_id INTEGER DEFAULT 0 NOT NULL, + pm_id INTEGER DEFAULT 0 NOT NULL, user_id INTEGER DEFAULT 0 NOT NULL, user_notify INTEGER DEFAULT 0 NOT NULL, report_closed INTEGER DEFAULT 0 NOT NULL, @@ -878,6 +886,8 @@ CREATE TABLE phpbb_reports ( ALTER TABLE phpbb_reports ADD PRIMARY KEY (report_id);; +CREATE INDEX phpbb_reports_post_id ON phpbb_reports(post_id);; +CREATE INDEX phpbb_reports_pm_id ON phpbb_reports(pm_id);; CREATE GENERATOR phpbb_reports_gen;; SET GENERATOR phpbb_reports_gen TO 0;; @@ -1343,7 +1353,7 @@ CREATE TABLE phpbb_users ( user_allow_viewonline INTEGER DEFAULT 1 NOT NULL, user_allow_viewemail INTEGER DEFAULT 1 NOT NULL, user_allow_massemail INTEGER DEFAULT 1 NOT NULL, - user_options INTEGER DEFAULT 895 NOT NULL, + user_options INTEGER DEFAULT 230271 NOT NULL, user_avatar VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL, user_avatar_type INTEGER DEFAULT 0 NOT NULL, user_avatar_width INTEGER DEFAULT 0 NOT NULL, @@ -1362,7 +1372,10 @@ CREATE TABLE phpbb_users ( user_interests BLOB SUB_TYPE TEXT CHARACTER SET UTF8 DEFAULT '' NOT NULL, user_actkey VARCHAR(32) CHARACTER SET NONE DEFAULT '' NOT NULL, user_newpasswd VARCHAR(40) CHARACTER SET UTF8 DEFAULT '' NOT NULL COLLATE UNICODE, - user_form_salt VARCHAR(32) CHARACTER SET UTF8 DEFAULT '' NOT NULL COLLATE UNICODE + user_form_salt VARCHAR(32) CHARACTER SET UTF8 DEFAULT '' NOT NULL COLLATE UNICODE, + user_new INTEGER DEFAULT 1 NOT NULL, + user_reminded INTEGER DEFAULT 0 NOT NULL, + user_reminded_time INTEGER DEFAULT 0 NOT NULL );; ALTER TABLE phpbb_users ADD PRIMARY KEY (user_id);; diff --git a/phpBB/install/schemas/mssql_schema.sql b/phpBB/install/schemas/mssql_schema.sql index 8600fdb1e0..ac7c0928cd 100644 --- a/phpBB/install/schemas/mssql_schema.sql +++ b/phpBB/install/schemas/mssql_schema.sql @@ -25,15 +25,15 @@ CREATE TABLE [phpbb_attachments] ( [mimetype] [varchar] (100) DEFAULT ('') NOT NULL , [filesize] [int] DEFAULT (0) NOT NULL , [filetime] [int] DEFAULT (0) NOT NULL , - [thumbnail] [int] DEFAULT (0) NOT NULL + [thumbnail] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_attachments] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_attachments] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_attachments] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_attachments] PRIMARY KEY CLUSTERED ( [attach_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [filetime] ON [phpbb_attachments]([filetime]) ON [PRIMARY] @@ -60,7 +60,7 @@ CREATE TABLE [phpbb_acl_groups] ( [forum_id] [int] DEFAULT (0) NOT NULL , [auth_option_id] [int] DEFAULT (0) NOT NULL , [auth_role_id] [int] DEFAULT (0) NOT NULL , - [auth_setting] [int] DEFAULT (0) NOT NULL + [auth_setting] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO @@ -82,15 +82,15 @@ CREATE TABLE [phpbb_acl_options] ( [auth_option] [varchar] (50) DEFAULT ('') NOT NULL , [is_global] [int] DEFAULT (0) NOT NULL , [is_local] [int] DEFAULT (0) NOT NULL , - [founder_only] [int] DEFAULT (0) NOT NULL + [founder_only] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_acl_options] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_acl_options] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_acl_options] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_acl_options] PRIMARY KEY CLUSTERED ( [auth_option_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE UNIQUE INDEX [auth_option] ON [phpbb_acl_options]([auth_option]) ON [PRIMARY] @@ -105,15 +105,15 @@ CREATE TABLE [phpbb_acl_roles] ( [role_name] [varchar] (255) DEFAULT ('') NOT NULL , [role_description] [varchar] (4000) DEFAULT ('') NOT NULL , [role_type] [varchar] (10) DEFAULT ('') NOT NULL , - [role_order] [int] DEFAULT (0) NOT NULL + [role_order] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_acl_roles] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_acl_roles] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_acl_roles] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_acl_roles] PRIMARY KEY CLUSTERED ( [role_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [role_type] ON [phpbb_acl_roles]([role_type]) ON [PRIMARY] @@ -129,16 +129,16 @@ GO CREATE TABLE [phpbb_acl_roles_data] ( [role_id] [int] DEFAULT (0) NOT NULL , [auth_option_id] [int] DEFAULT (0) NOT NULL , - [auth_setting] [int] DEFAULT (0) NOT NULL + [auth_setting] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_acl_roles_data] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_acl_roles_data] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_acl_roles_data] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_acl_roles_data] PRIMARY KEY CLUSTERED ( [role_id], [auth_option_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [ath_op_id] ON [phpbb_acl_roles_data]([auth_option_id]) ON [PRIMARY] @@ -153,7 +153,7 @@ CREATE TABLE [phpbb_acl_users] ( [forum_id] [int] DEFAULT (0) NOT NULL , [auth_option_id] [int] DEFAULT (0) NOT NULL , [auth_role_id] [int] DEFAULT (0) NOT NULL , - [auth_setting] [int] DEFAULT (0) NOT NULL + [auth_setting] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO @@ -179,15 +179,15 @@ CREATE TABLE [phpbb_banlist] ( [ban_end] [int] DEFAULT (0) NOT NULL , [ban_exclude] [int] DEFAULT (0) NOT NULL , [ban_reason] [varchar] (255) DEFAULT ('') NOT NULL , - [ban_give_reason] [varchar] (255) DEFAULT ('') NOT NULL + [ban_give_reason] [varchar] (255) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_banlist] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_banlist] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_banlist] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_banlist] PRIMARY KEY CLUSTERED ( [ban_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [ban_end] ON [phpbb_banlist]([ban_end]) ON [PRIMARY] @@ -216,15 +216,15 @@ CREATE TABLE [phpbb_bbcodes] ( [first_pass_match] [text] DEFAULT ('') NOT NULL , [first_pass_replace] [text] DEFAULT ('') NOT NULL , [second_pass_match] [text] DEFAULT ('') NOT NULL , - [second_pass_replace] [text] DEFAULT ('') NOT NULL + [second_pass_replace] [text] DEFAULT ('') NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO -ALTER TABLE [phpbb_bbcodes] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_bbcodes] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_bbcodes] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_bbcodes] PRIMARY KEY CLUSTERED ( [bbcode_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [display_on_post] ON [phpbb_bbcodes]([display_on_posting]) ON [PRIMARY] @@ -236,16 +236,16 @@ GO */ CREATE TABLE [phpbb_bookmarks] ( [topic_id] [int] DEFAULT (0) NOT NULL , - [user_id] [int] DEFAULT (0) NOT NULL + [user_id] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_bookmarks] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_bookmarks] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_bookmarks] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_bookmarks] PRIMARY KEY CLUSTERED ( [topic_id], [user_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -258,15 +258,15 @@ CREATE TABLE [phpbb_bots] ( [bot_name] [varchar] (255) DEFAULT ('') NOT NULL , [user_id] [int] DEFAULT (0) NOT NULL , [bot_agent] [varchar] (255) DEFAULT ('') NOT NULL , - [bot_ip] [varchar] (255) DEFAULT ('') NOT NULL + [bot_ip] [varchar] (255) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_bots] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_bots] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_bots] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_bots] PRIMARY KEY CLUSTERED ( [bot_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [bot_active] ON [phpbb_bots]([bot_active]) ON [PRIMARY] @@ -279,15 +279,15 @@ GO CREATE TABLE [phpbb_config] ( [config_name] [varchar] (255) DEFAULT ('') NOT NULL , [config_value] [varchar] (255) DEFAULT ('') NOT NULL , - [is_dynamic] [int] DEFAULT (0) NOT NULL + [is_dynamic] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_config] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_config] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_config] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_config] PRIMARY KEY CLUSTERED ( [config_name] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [is_dynamic] ON [phpbb_config]([is_dynamic]) ON [PRIMARY] @@ -302,16 +302,17 @@ CREATE TABLE [phpbb_confirm] ( [session_id] [char] (32) DEFAULT ('') NOT NULL , [confirm_type] [int] DEFAULT (0) NOT NULL , [code] [varchar] (8) DEFAULT ('') NOT NULL , - [seed] [int] DEFAULT (0) NOT NULL + [seed] [int] DEFAULT (0) NOT NULL , + [attempts] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_confirm] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_confirm] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_confirm] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_confirm] PRIMARY KEY CLUSTERED ( [session_id], [confirm_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [confirm_type] ON [phpbb_confirm]([confirm_type]) ON [PRIMARY] @@ -323,15 +324,15 @@ GO */ CREATE TABLE [phpbb_disallow] ( [disallow_id] [int] IDENTITY (1, 1) NOT NULL , - [disallow_username] [varchar] (255) DEFAULT ('') NOT NULL + [disallow_username] [varchar] (255) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_disallow] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_disallow] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_disallow] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_disallow] PRIMARY KEY CLUSTERED ( [disallow_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -345,15 +346,15 @@ CREATE TABLE [phpbb_drafts] ( [forum_id] [int] DEFAULT (0) NOT NULL , [save_time] [int] DEFAULT (0) NOT NULL , [draft_subject] [varchar] (255) DEFAULT ('') NOT NULL , - [draft_message] [text] DEFAULT ('') NOT NULL + [draft_message] [text] DEFAULT ('') NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO -ALTER TABLE [phpbb_drafts] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_drafts] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_drafts] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_drafts] PRIMARY KEY CLUSTERED ( [draft_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [save_time] ON [phpbb_drafts]([save_time]) ON [PRIMARY] @@ -366,15 +367,15 @@ GO CREATE TABLE [phpbb_extensions] ( [extension_id] [int] IDENTITY (1, 1) NOT NULL , [group_id] [int] DEFAULT (0) NOT NULL , - [extension] [varchar] (100) DEFAULT ('') NOT NULL + [extension] [varchar] (100) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_extensions] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_extensions] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_extensions] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_extensions] PRIMARY KEY CLUSTERED ( [extension_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -390,15 +391,15 @@ CREATE TABLE [phpbb_extension_groups] ( [upload_icon] [varchar] (255) DEFAULT ('') NOT NULL , [max_filesize] [int] DEFAULT (0) NOT NULL , [allowed_forums] [varchar] (8000) DEFAULT ('') NOT NULL , - [allow_in_pm] [int] DEFAULT (0) NOT NULL + [allow_in_pm] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_extension_groups] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_extension_groups] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_extension_groups] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_extension_groups] PRIMARY KEY CLUSTERED ( [group_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -438,6 +439,7 @@ CREATE TABLE [phpbb_forums] ( [forum_last_poster_name] [varchar] (255) DEFAULT ('') NOT NULL , [forum_last_poster_colour] [varchar] (6) DEFAULT ('') NOT NULL , [forum_flags] [int] DEFAULT (32) NOT NULL , + [forum_options] [int] DEFAULT (0) NOT NULL , [display_subforum_list] [int] DEFAULT (1) NOT NULL , [display_on_index] [int] DEFAULT (1) NOT NULL , [enable_indexing] [int] DEFAULT (1) NOT NULL , @@ -446,15 +448,15 @@ CREATE TABLE [phpbb_forums] ( [prune_next] [int] DEFAULT (0) NOT NULL , [prune_days] [int] DEFAULT (0) NOT NULL , [prune_viewed] [int] DEFAULT (0) NOT NULL , - [prune_freq] [int] DEFAULT (0) NOT NULL + [prune_freq] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO -ALTER TABLE [phpbb_forums] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_forums] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_forums] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_forums] PRIMARY KEY CLUSTERED ( [forum_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [left_right_id] ON [phpbb_forums]([left_id], [right_id]) ON [PRIMARY] @@ -470,17 +472,17 @@ GO CREATE TABLE [phpbb_forums_access] ( [forum_id] [int] DEFAULT (0) NOT NULL , [user_id] [int] DEFAULT (0) NOT NULL , - [session_id] [char] (32) DEFAULT ('') NOT NULL + [session_id] [char] (32) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_forums_access] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_forums_access] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_forums_access] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_forums_access] PRIMARY KEY CLUSTERED ( [forum_id], [user_id], [session_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -490,16 +492,16 @@ GO CREATE TABLE [phpbb_forums_track] ( [user_id] [int] DEFAULT (0) NOT NULL , [forum_id] [int] DEFAULT (0) NOT NULL , - [mark_time] [int] DEFAULT (0) NOT NULL + [mark_time] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_forums_track] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_forums_track] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_forums_track] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_forums_track] PRIMARY KEY CLUSTERED ( [user_id], [forum_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -509,7 +511,7 @@ GO CREATE TABLE [phpbb_forums_watch] ( [forum_id] [int] DEFAULT (0) NOT NULL , [user_id] [int] DEFAULT (0) NOT NULL , - [notify_status] [int] DEFAULT (0) NOT NULL + [notify_status] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO @@ -530,6 +532,7 @@ CREATE TABLE [phpbb_groups] ( [group_id] [int] IDENTITY (1, 1) NOT NULL , [group_type] [int] DEFAULT (1) NOT NULL , [group_founder_manage] [int] DEFAULT (0) NOT NULL , + [group_skip_auth] [int] DEFAULT (0) NOT NULL , [group_name] [varchar] (255) DEFAULT ('') NOT NULL , [group_desc] [varchar] (4000) DEFAULT ('') NOT NULL , [group_desc_bitfield] [varchar] (255) DEFAULT ('') NOT NULL , @@ -546,15 +549,15 @@ CREATE TABLE [phpbb_groups] ( [group_receive_pm] [int] DEFAULT (0) NOT NULL , [group_message_limit] [int] DEFAULT (0) NOT NULL , [group_max_recipients] [int] DEFAULT (0) NOT NULL , - [group_legend] [int] DEFAULT (1) NOT NULL + [group_legend] [int] DEFAULT (1) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_groups] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_groups] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_groups] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_groups] PRIMARY KEY CLUSTERED ( [group_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [group_legend_name] ON [phpbb_groups]([group_legend], [group_name]) ON [PRIMARY] @@ -570,15 +573,15 @@ CREATE TABLE [phpbb_icons] ( [icons_width] [int] DEFAULT (0) NOT NULL , [icons_height] [int] DEFAULT (0) NOT NULL , [icons_order] [int] DEFAULT (0) NOT NULL , - [display_on_posting] [int] DEFAULT (1) NOT NULL + [display_on_posting] [int] DEFAULT (1) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_icons] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_icons] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_icons] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_icons] PRIMARY KEY CLUSTERED ( [icons_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [display_on_posting] ON [phpbb_icons]([display_on_posting]) ON [PRIMARY] @@ -594,15 +597,15 @@ CREATE TABLE [phpbb_lang] ( [lang_dir] [varchar] (30) DEFAULT ('') NOT NULL , [lang_english_name] [varchar] (100) DEFAULT ('') NOT NULL , [lang_local_name] [varchar] (255) DEFAULT ('') NOT NULL , - [lang_author] [varchar] (255) DEFAULT ('') NOT NULL + [lang_author] [varchar] (255) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_lang] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_lang] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_lang] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_lang] PRIMARY KEY CLUSTERED ( [lang_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [lang_iso] ON [phpbb_lang]([lang_iso]) ON [PRIMARY] @@ -622,20 +625,23 @@ CREATE TABLE [phpbb_log] ( [log_ip] [varchar] (40) DEFAULT ('') NOT NULL , [log_time] [int] DEFAULT (0) NOT NULL , [log_operation] [varchar] (4000) DEFAULT ('') NOT NULL , - [log_data] [text] DEFAULT ('') NOT NULL + [log_data] [text] DEFAULT ('') NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO -ALTER TABLE [phpbb_log] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_log] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_log] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_log] PRIMARY KEY CLUSTERED ( [log_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [log_type] ON [phpbb_log]([log_type]) ON [PRIMARY] GO +CREATE INDEX [log_time] ON [phpbb_log]([log_time]) ON [PRIMARY] +GO + CREATE INDEX [forum_id] ON [phpbb_log]([forum_id]) ON [PRIMARY] GO @@ -658,7 +664,7 @@ CREATE TABLE [phpbb_moderator_cache] ( [username] [varchar] (255) DEFAULT ('') NOT NULL , [group_id] [int] DEFAULT (0) NOT NULL , [group_name] [varchar] (255) DEFAULT ('') NOT NULL , - [display_on_index] [int] DEFAULT (1) NOT NULL + [display_on_index] [int] DEFAULT (1) NOT NULL ) ON [PRIMARY] GO @@ -683,15 +689,15 @@ CREATE TABLE [phpbb_modules] ( [right_id] [int] DEFAULT (0) NOT NULL , [module_langname] [varchar] (255) DEFAULT ('') NOT NULL , [module_mode] [varchar] (255) DEFAULT ('') NOT NULL , - [module_auth] [varchar] (255) DEFAULT ('') NOT NULL + [module_auth] [varchar] (255) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_modules] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_modules] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_modules] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_modules] PRIMARY KEY CLUSTERED ( [module_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [left_right_id] ON [phpbb_modules]([left_id], [right_id]) ON [PRIMARY] @@ -711,7 +717,7 @@ CREATE TABLE [phpbb_poll_options] ( [poll_option_id] [int] DEFAULT (0) NOT NULL , [topic_id] [int] DEFAULT (0) NOT NULL , [poll_option_text] [varchar] (4000) DEFAULT ('') NOT NULL , - [poll_option_total] [int] DEFAULT (0) NOT NULL + [poll_option_total] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO @@ -729,7 +735,7 @@ CREATE TABLE [phpbb_poll_votes] ( [topic_id] [int] DEFAULT (0) NOT NULL , [poll_option_id] [int] DEFAULT (0) NOT NULL , [vote_user_id] [int] DEFAULT (0) NOT NULL , - [vote_user_ip] [varchar] (40) DEFAULT ('') NOT NULL + [vote_user_ip] [varchar] (40) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO @@ -772,15 +778,15 @@ CREATE TABLE [phpbb_posts] ( [post_edit_reason] [varchar] (255) DEFAULT ('') NOT NULL , [post_edit_user] [int] DEFAULT (0) NOT NULL , [post_edit_count] [int] DEFAULT (0) NOT NULL , - [post_edit_locked] [int] DEFAULT (0) NOT NULL + [post_edit_locked] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO -ALTER TABLE [phpbb_posts] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_posts] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_posts] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_posts] PRIMARY KEY CLUSTERED ( [post_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [forum_id] ON [phpbb_posts]([forum_id]) ON [PRIMARY] @@ -798,6 +804,9 @@ GO CREATE INDEX [post_approved] ON [phpbb_posts]([post_approved]) ON [PRIMARY] GO +CREATE INDEX [post_username] ON [phpbb_posts]([post_username]) ON [PRIMARY] +GO + CREATE INDEX [tid_post_time] ON [phpbb_posts]([topic_id], [post_time]) ON [PRIMARY] GO @@ -826,15 +835,16 @@ CREATE TABLE [phpbb_privmsgs] ( [message_edit_time] [int] DEFAULT (0) NOT NULL , [message_edit_count] [int] DEFAULT (0) NOT NULL , [to_address] [varchar] (4000) DEFAULT ('') NOT NULL , - [bcc_address] [varchar] (4000) DEFAULT ('') NOT NULL + [bcc_address] [varchar] (4000) DEFAULT ('') NOT NULL , + [message_reported] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO -ALTER TABLE [phpbb_privmsgs] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_privmsgs] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_privmsgs] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_privmsgs] PRIMARY KEY CLUSTERED ( [msg_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [author_ip] ON [phpbb_privmsgs]([author_ip]) ON [PRIMARY] @@ -857,15 +867,15 @@ CREATE TABLE [phpbb_privmsgs_folder] ( [folder_id] [int] IDENTITY (1, 1) NOT NULL , [user_id] [int] DEFAULT (0) NOT NULL , [folder_name] [varchar] (255) DEFAULT ('') NOT NULL , - [pm_count] [int] DEFAULT (0) NOT NULL + [pm_count] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_privmsgs_folder] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_privmsgs_folder] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_privmsgs_folder] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_privmsgs_folder] PRIMARY KEY CLUSTERED ( [folder_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [user_id] ON [phpbb_privmsgs_folder]([user_id]) ON [PRIMARY] @@ -884,15 +894,15 @@ CREATE TABLE [phpbb_privmsgs_rules] ( [rule_user_id] [int] DEFAULT (0) NOT NULL , [rule_group_id] [int] DEFAULT (0) NOT NULL , [rule_action] [int] DEFAULT (0) NOT NULL , - [rule_folder_id] [int] DEFAULT (0) NOT NULL + [rule_folder_id] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_privmsgs_rules] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_privmsgs_rules] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_privmsgs_rules] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_privmsgs_rules] PRIMARY KEY CLUSTERED ( [rule_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [user_id] ON [phpbb_privmsgs_rules]([user_id]) ON [PRIMARY] @@ -912,7 +922,7 @@ CREATE TABLE [phpbb_privmsgs_to] ( [pm_replied] [int] DEFAULT (0) NOT NULL , [pm_marked] [int] DEFAULT (0) NOT NULL , [pm_forwarded] [int] DEFAULT (0) NOT NULL , - [folder_id] [int] DEFAULT (0) NOT NULL + [folder_id] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO @@ -942,19 +952,20 @@ CREATE TABLE [phpbb_profile_fields] ( [field_validation] [varchar] (20) DEFAULT ('') NOT NULL , [field_required] [int] DEFAULT (0) NOT NULL , [field_show_on_reg] [int] DEFAULT (0) NOT NULL , + [field_show_on_vt] [int] DEFAULT (0) NOT NULL , [field_show_profile] [int] DEFAULT (0) NOT NULL , [field_hide] [int] DEFAULT (0) NOT NULL , [field_no_view] [int] DEFAULT (0) NOT NULL , [field_active] [int] DEFAULT (0) NOT NULL , - [field_order] [int] DEFAULT (0) NOT NULL + [field_order] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_profile_fields] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_profile_fields] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_profile_fields] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_profile_fields] PRIMARY KEY CLUSTERED ( [field_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [fld_type] ON [phpbb_profile_fields]([field_type]) ON [PRIMARY] @@ -968,15 +979,15 @@ GO Table: 'phpbb_profile_fields_data' */ CREATE TABLE [phpbb_profile_fields_data] ( - [user_id] [int] DEFAULT (0) NOT NULL + [user_id] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_profile_fields_data] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_profile_fields_data] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_profile_fields_data] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_profile_fields_data] PRIMARY KEY CLUSTERED ( [user_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -988,17 +999,17 @@ CREATE TABLE [phpbb_profile_fields_lang] ( [lang_id] [int] DEFAULT (0) NOT NULL , [option_id] [int] DEFAULT (0) NOT NULL , [field_type] [int] DEFAULT (0) NOT NULL , - [lang_value] [varchar] (255) DEFAULT ('') NOT NULL + [lang_value] [varchar] (255) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_profile_fields_lang] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_profile_fields_lang] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_profile_fields_lang] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_profile_fields_lang] PRIMARY KEY CLUSTERED ( [field_id], [lang_id], [option_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -1010,16 +1021,16 @@ CREATE TABLE [phpbb_profile_lang] ( [lang_id] [int] DEFAULT (0) NOT NULL , [lang_name] [varchar] (255) DEFAULT ('') NOT NULL , [lang_explain] [varchar] (4000) DEFAULT ('') NOT NULL , - [lang_default_value] [varchar] (255) DEFAULT ('') NOT NULL + [lang_default_value] [varchar] (255) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_profile_lang] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_profile_lang] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_profile_lang] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_profile_lang] PRIMARY KEY CLUSTERED ( [field_id], [lang_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -1031,15 +1042,15 @@ CREATE TABLE [phpbb_ranks] ( [rank_title] [varchar] (255) DEFAULT ('') NOT NULL , [rank_min] [int] DEFAULT (0) NOT NULL , [rank_special] [int] DEFAULT (0) NOT NULL , - [rank_image] [varchar] (255) DEFAULT ('') NOT NULL + [rank_image] [varchar] (255) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_ranks] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_ranks] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_ranks] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_ranks] PRIMARY KEY CLUSTERED ( [rank_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -1050,19 +1061,26 @@ CREATE TABLE [phpbb_reports] ( [report_id] [int] IDENTITY (1, 1) NOT NULL , [reason_id] [int] DEFAULT (0) NOT NULL , [post_id] [int] DEFAULT (0) NOT NULL , + [pm_id] [int] DEFAULT (0) NOT NULL , [user_id] [int] DEFAULT (0) NOT NULL , [user_notify] [int] DEFAULT (0) NOT NULL , [report_closed] [int] DEFAULT (0) NOT NULL , [report_time] [int] DEFAULT (0) NOT NULL , - [report_text] [text] DEFAULT ('') NOT NULL + [report_text] [text] DEFAULT ('') NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO -ALTER TABLE [phpbb_reports] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_reports] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_reports] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_reports] PRIMARY KEY CLUSTERED ( [report_id] - ) ON [PRIMARY] + ) ON [PRIMARY] +GO + +CREATE INDEX [post_id] ON [phpbb_reports]([post_id]) ON [PRIMARY] +GO + +CREATE INDEX [pm_id] ON [phpbb_reports]([pm_id]) ON [PRIMARY] GO @@ -1073,15 +1091,15 @@ CREATE TABLE [phpbb_reports_reasons] ( [reason_id] [int] IDENTITY (1, 1) NOT NULL , [reason_title] [varchar] (255) DEFAULT ('') NOT NULL , [reason_description] [text] DEFAULT ('') NOT NULL , - [reason_order] [int] DEFAULT (0) NOT NULL + [reason_order] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO -ALTER TABLE [phpbb_reports_reasons] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_reports_reasons] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_reports_reasons] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_reports_reasons] PRIMARY KEY CLUSTERED ( [reason_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -1092,15 +1110,15 @@ CREATE TABLE [phpbb_search_results] ( [search_key] [varchar] (32) DEFAULT ('') NOT NULL , [search_time] [int] DEFAULT (0) NOT NULL , [search_keywords] [text] DEFAULT ('') NOT NULL , - [search_authors] [text] DEFAULT ('') NOT NULL + [search_authors] [text] DEFAULT ('') NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO -ALTER TABLE [phpbb_search_results] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_search_results] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_search_results] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_search_results] PRIMARY KEY CLUSTERED ( [search_key] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -1111,15 +1129,15 @@ CREATE TABLE [phpbb_search_wordlist] ( [word_id] [int] IDENTITY (1, 1) NOT NULL , [word_text] [varchar] (255) DEFAULT ('') NOT NULL , [word_common] [int] DEFAULT (0) NOT NULL , - [word_count] [int] DEFAULT (0) NOT NULL + [word_count] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_search_wordlist] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_search_wordlist] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_search_wordlist] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_search_wordlist] PRIMARY KEY CLUSTERED ( [word_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE UNIQUE INDEX [wrd_txt] ON [phpbb_search_wordlist]([word_text]) ON [PRIMARY] @@ -1135,7 +1153,7 @@ GO CREATE TABLE [phpbb_search_wordmatch] ( [post_id] [int] DEFAULT (0) NOT NULL , [word_id] [int] DEFAULT (0) NOT NULL , - [title_match] [int] DEFAULT (0) NOT NULL + [title_match] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO @@ -1165,15 +1183,15 @@ CREATE TABLE [phpbb_sessions] ( [session_page] [varchar] (255) DEFAULT ('') NOT NULL , [session_viewonline] [int] DEFAULT (1) NOT NULL , [session_autologin] [int] DEFAULT (0) NOT NULL , - [session_admin] [int] DEFAULT (0) NOT NULL + [session_admin] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_sessions] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_sessions] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_sessions] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_sessions] PRIMARY KEY CLUSTERED ( [session_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [session_time] ON [phpbb_sessions]([session_time]) ON [PRIMARY] @@ -1193,16 +1211,16 @@ CREATE TABLE [phpbb_sessions_keys] ( [key_id] [char] (32) DEFAULT ('') NOT NULL , [user_id] [int] DEFAULT (0) NOT NULL , [last_ip] [varchar] (40) DEFAULT ('') NOT NULL , - [last_login] [int] DEFAULT (0) NOT NULL + [last_login] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_sessions_keys] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_sessions_keys] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_sessions_keys] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_sessions_keys] PRIMARY KEY CLUSTERED ( [key_id], [user_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [last_login] ON [phpbb_sessions_keys]([last_login]) ON [PRIMARY] @@ -1216,15 +1234,15 @@ CREATE TABLE [phpbb_sitelist] ( [site_id] [int] IDENTITY (1, 1) NOT NULL , [site_ip] [varchar] (40) DEFAULT ('') NOT NULL , [site_hostname] [varchar] (255) DEFAULT ('') NOT NULL , - [ip_exclude] [int] DEFAULT (0) NOT NULL + [ip_exclude] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_sitelist] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_sitelist] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_sitelist] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_sitelist] PRIMARY KEY CLUSTERED ( [site_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -1239,15 +1257,15 @@ CREATE TABLE [phpbb_smilies] ( [smiley_width] [int] DEFAULT (0) NOT NULL , [smiley_height] [int] DEFAULT (0) NOT NULL , [smiley_order] [int] DEFAULT (0) NOT NULL , - [display_on_posting] [int] DEFAULT (1) NOT NULL + [display_on_posting] [int] DEFAULT (1) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_smilies] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_smilies] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_smilies] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_smilies] PRIMARY KEY CLUSTERED ( [smiley_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [display_on_post] ON [phpbb_smilies]([display_on_posting]) ON [PRIMARY] @@ -1264,15 +1282,15 @@ CREATE TABLE [phpbb_styles] ( [style_active] [int] DEFAULT (1) NOT NULL , [template_id] [int] DEFAULT (0) NOT NULL , [theme_id] [int] DEFAULT (0) NOT NULL , - [imageset_id] [int] DEFAULT (0) NOT NULL + [imageset_id] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_styles] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_styles] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_styles] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_styles] PRIMARY KEY CLUSTERED ( [style_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE UNIQUE INDEX [style_name] ON [phpbb_styles]([style_name]) ON [PRIMARY] @@ -1299,15 +1317,15 @@ CREATE TABLE [phpbb_styles_template] ( [bbcode_bitfield] [varchar] (255) DEFAULT ('kNg=') NOT NULL , [template_storedb] [int] DEFAULT (0) NOT NULL , [template_inherits_id] [int] DEFAULT (0) NOT NULL , - [template_inherit_path] [varchar] (255) DEFAULT ('') NOT NULL + [template_inherit_path] [varchar] (255) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_styles_template] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_styles_template] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_styles_template] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_styles_template] PRIMARY KEY CLUSTERED ( [template_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE UNIQUE INDEX [tmplte_nm] ON [phpbb_styles_template]([template_name]) ON [PRIMARY] @@ -1322,7 +1340,7 @@ CREATE TABLE [phpbb_styles_template_data] ( [template_filename] [varchar] (100) DEFAULT ('') NOT NULL , [template_included] [varchar] (8000) DEFAULT ('') NOT NULL , [template_mtime] [int] DEFAULT (0) NOT NULL , - [template_data] [text] DEFAULT ('') NOT NULL + [template_data] [text] DEFAULT ('') NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO @@ -1343,15 +1361,15 @@ CREATE TABLE [phpbb_styles_theme] ( [theme_path] [varchar] (100) DEFAULT ('') NOT NULL , [theme_storedb] [int] DEFAULT (0) NOT NULL , [theme_mtime] [int] DEFAULT (0) NOT NULL , - [theme_data] [text] DEFAULT ('') NOT NULL + [theme_data] [text] DEFAULT ('') NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO -ALTER TABLE [phpbb_styles_theme] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_styles_theme] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_styles_theme] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_styles_theme] PRIMARY KEY CLUSTERED ( [theme_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE UNIQUE INDEX [theme_name] ON [phpbb_styles_theme]([theme_name]) ON [PRIMARY] @@ -1365,15 +1383,15 @@ CREATE TABLE [phpbb_styles_imageset] ( [imageset_id] [int] IDENTITY (1, 1) NOT NULL , [imageset_name] [varchar] (255) DEFAULT ('') NOT NULL , [imageset_copyright] [varchar] (255) DEFAULT ('') NOT NULL , - [imageset_path] [varchar] (100) DEFAULT ('') NOT NULL + [imageset_path] [varchar] (100) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_styles_imageset] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_styles_imageset] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_styles_imageset] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_styles_imageset] PRIMARY KEY CLUSTERED ( [imageset_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE UNIQUE INDEX [imgset_nm] ON [phpbb_styles_imageset]([imageset_name]) ON [PRIMARY] @@ -1390,15 +1408,15 @@ CREATE TABLE [phpbb_styles_imageset_data] ( [image_lang] [varchar] (30) DEFAULT ('') NOT NULL , [image_height] [int] DEFAULT (0) NOT NULL , [image_width] [int] DEFAULT (0) NOT NULL , - [imageset_id] [int] DEFAULT (0) NOT NULL + [imageset_id] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_styles_imageset_data] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_styles_imageset_data] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_styles_imageset_data] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_styles_imageset_data] PRIMARY KEY CLUSTERED ( [image_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [i_d] ON [phpbb_styles_imageset_data]([imageset_id]) ON [PRIMARY] @@ -1442,15 +1460,15 @@ CREATE TABLE [phpbb_topics] ( [poll_length] [int] DEFAULT (0) NOT NULL , [poll_max_options] [int] DEFAULT (1) NOT NULL , [poll_last_vote] [int] DEFAULT (0) NOT NULL , - [poll_vote_change] [int] DEFAULT (0) NOT NULL + [poll_vote_change] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_topics] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_topics] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_topics] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_topics] PRIMARY KEY CLUSTERED ( [topic_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [forum_id] ON [phpbb_topics]([forum_id]) ON [PRIMARY] @@ -1479,16 +1497,16 @@ CREATE TABLE [phpbb_topics_track] ( [user_id] [int] DEFAULT (0) NOT NULL , [topic_id] [int] DEFAULT (0) NOT NULL , [forum_id] [int] DEFAULT (0) NOT NULL , - [mark_time] [int] DEFAULT (0) NOT NULL + [mark_time] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_topics_track] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_topics_track] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_topics_track] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_topics_track] PRIMARY KEY CLUSTERED ( [user_id], [topic_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [forum_id] ON [phpbb_topics_track]([forum_id]) ON [PRIMARY] @@ -1501,16 +1519,16 @@ GO CREATE TABLE [phpbb_topics_posted] ( [user_id] [int] DEFAULT (0) NOT NULL , [topic_id] [int] DEFAULT (0) NOT NULL , - [topic_posted] [int] DEFAULT (0) NOT NULL + [topic_posted] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_topics_posted] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_topics_posted] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_topics_posted] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_topics_posted] PRIMARY KEY CLUSTERED ( [user_id], [topic_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -1520,7 +1538,7 @@ GO CREATE TABLE [phpbb_topics_watch] ( [topic_id] [int] DEFAULT (0) NOT NULL , [user_id] [int] DEFAULT (0) NOT NULL , - [notify_status] [int] DEFAULT (0) NOT NULL + [notify_status] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO @@ -1541,7 +1559,7 @@ CREATE TABLE [phpbb_user_group] ( [group_id] [int] DEFAULT (0) NOT NULL , [user_id] [int] DEFAULT (0) NOT NULL , [group_leader] [int] DEFAULT (0) NOT NULL , - [user_pending] [int] DEFAULT (1) NOT NULL + [user_pending] [int] DEFAULT (1) NOT NULL ) ON [PRIMARY] GO @@ -1612,7 +1630,7 @@ CREATE TABLE [phpbb_users] ( [user_allow_viewonline] [int] DEFAULT (1) NOT NULL , [user_allow_viewemail] [int] DEFAULT (1) NOT NULL , [user_allow_massemail] [int] DEFAULT (1) NOT NULL , - [user_options] [int] DEFAULT (895) NOT NULL , + [user_options] [int] DEFAULT (230271) NOT NULL , [user_avatar] [varchar] (255) DEFAULT ('') NOT NULL , [user_avatar_type] [int] DEFAULT (0) NOT NULL , [user_avatar_width] [int] DEFAULT (0) NOT NULL , @@ -1631,15 +1649,18 @@ CREATE TABLE [phpbb_users] ( [user_interests] [varchar] (4000) DEFAULT ('') NOT NULL , [user_actkey] [varchar] (32) DEFAULT ('') NOT NULL , [user_newpasswd] [varchar] (40) DEFAULT ('') NOT NULL , - [user_form_salt] [varchar] (32) DEFAULT ('') NOT NULL + [user_form_salt] [varchar] (32) DEFAULT ('') NOT NULL , + [user_new] [int] DEFAULT (1) NOT NULL , + [user_reminded] [int] DEFAULT (0) NOT NULL , + [user_reminded_time] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO -ALTER TABLE [phpbb_users] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_users] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_users] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_users] PRIMARY KEY CLUSTERED ( [user_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO CREATE INDEX [user_birthday] ON [phpbb_users]([user_birthday]) ON [PRIMARY] @@ -1663,15 +1684,15 @@ CREATE TABLE [phpbb_warnings] ( [user_id] [int] DEFAULT (0) NOT NULL , [post_id] [int] DEFAULT (0) NOT NULL , [log_id] [int] DEFAULT (0) NOT NULL , - [warning_time] [int] DEFAULT (0) NOT NULL + [warning_time] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_warnings] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_warnings] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_warnings] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_warnings] PRIMARY KEY CLUSTERED ( [warning_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -1681,15 +1702,15 @@ GO CREATE TABLE [phpbb_words] ( [word_id] [int] IDENTITY (1, 1) NOT NULL , [word] [varchar] (255) DEFAULT ('') NOT NULL , - [replacement] [varchar] (255) DEFAULT ('') NOT NULL + [replacement] [varchar] (255) DEFAULT ('') NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_words] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_words] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_words] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_words] PRIMARY KEY CLUSTERED ( [word_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO @@ -1700,16 +1721,16 @@ CREATE TABLE [phpbb_zebra] ( [user_id] [int] DEFAULT (0) NOT NULL , [zebra_id] [int] DEFAULT (0) NOT NULL , [friend] [int] DEFAULT (0) NOT NULL , - [foe] [int] DEFAULT (0) NOT NULL + [foe] [int] DEFAULT (0) NOT NULL ) ON [PRIMARY] GO -ALTER TABLE [phpbb_zebra] WITH NOCHECK ADD - CONSTRAINT [PK_phpbb_zebra] PRIMARY KEY CLUSTERED +ALTER TABLE [phpbb_zebra] WITH NOCHECK ADD + CONSTRAINT [PK_phpbb_zebra] PRIMARY KEY CLUSTERED ( [user_id], [zebra_id] - ) ON [PRIMARY] + ) ON [PRIMARY] GO diff --git a/phpBB/install/schemas/mysql_40_schema.sql b/phpBB/install/schemas/mysql_40_schema.sql index 146c58904c..4fcead787b 100644 --- a/phpBB/install/schemas/mysql_40_schema.sql +++ b/phpBB/install/schemas/mysql_40_schema.sql @@ -163,6 +163,7 @@ CREATE TABLE phpbb_confirm ( confirm_type tinyint(3) DEFAULT '0' NOT NULL, code varbinary(8) DEFAULT '' NOT NULL, seed int(10) UNSIGNED DEFAULT '0' NOT NULL, + attempts mediumint(8) UNSIGNED DEFAULT '0' NOT NULL, PRIMARY KEY (session_id, confirm_id), KEY confirm_type (confirm_type) ); @@ -248,6 +249,7 @@ CREATE TABLE phpbb_forums ( forum_last_poster_name blob NOT NULL, forum_last_poster_colour varbinary(6) DEFAULT '' NOT NULL, forum_flags tinyint(4) DEFAULT '32' NOT NULL, + forum_options int(20) UNSIGNED DEFAULT '0' NOT NULL, display_subforum_list tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, display_on_index tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, enable_indexing tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, @@ -297,6 +299,7 @@ CREATE TABLE phpbb_groups ( group_id mediumint(8) UNSIGNED NOT NULL auto_increment, group_type tinyint(4) DEFAULT '1' NOT NULL, group_founder_manage tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, + group_skip_auth tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, group_name blob NOT NULL, group_desc blob NOT NULL, group_desc_bitfield varbinary(255) DEFAULT '' NOT NULL, @@ -359,6 +362,7 @@ CREATE TABLE phpbb_log ( log_data mediumblob NOT NULL, PRIMARY KEY (log_id), KEY log_type (log_type), + KEY log_time (log_time), KEY forum_id (forum_id), KEY topic_id (topic_id), KEY reportee_id (reportee_id), @@ -456,6 +460,7 @@ CREATE TABLE phpbb_posts ( KEY poster_ip (poster_ip), KEY poster_id (poster_id), KEY post_approved (post_approved), + KEY post_username (post_username(255)), KEY tid_post_time (topic_id, post_time) ); @@ -483,6 +488,7 @@ CREATE TABLE phpbb_privmsgs ( message_edit_count smallint(4) UNSIGNED DEFAULT '0' NOT NULL, to_address blob NOT NULL, bcc_address blob NOT NULL, + message_reported tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, PRIMARY KEY (msg_id), KEY author_ip (author_ip), KEY message_time (message_time), @@ -550,6 +556,7 @@ CREATE TABLE phpbb_profile_fields ( field_validation varbinary(60) DEFAULT '' NOT NULL, field_required tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, field_show_on_reg tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, + field_show_on_vt tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, field_show_profile tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, field_hide tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, field_no_view tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, @@ -606,12 +613,15 @@ CREATE TABLE phpbb_reports ( report_id mediumint(8) UNSIGNED NOT NULL auto_increment, reason_id smallint(4) UNSIGNED DEFAULT '0' NOT NULL, post_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL, + pm_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL, user_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL, user_notify tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, report_closed tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, report_time int(11) UNSIGNED DEFAULT '0' NOT NULL, report_text mediumblob NOT NULL, - PRIMARY KEY (report_id) + PRIMARY KEY (report_id), + KEY post_id (post_id), + KEY pm_id (pm_id) ); @@ -943,7 +953,7 @@ CREATE TABLE phpbb_users ( user_allow_viewonline tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, user_allow_viewemail tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, user_allow_massemail tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, - user_options int(11) UNSIGNED DEFAULT '895' NOT NULL, + user_options int(11) UNSIGNED DEFAULT '230271' NOT NULL, user_avatar varbinary(255) DEFAULT '' NOT NULL, user_avatar_type tinyint(2) DEFAULT '0' NOT NULL, user_avatar_width smallint(4) UNSIGNED DEFAULT '0' NOT NULL, @@ -963,6 +973,9 @@ CREATE TABLE phpbb_users ( user_actkey varbinary(32) DEFAULT '' NOT NULL, user_newpasswd varbinary(120) DEFAULT '' NOT NULL, user_form_salt varbinary(96) DEFAULT '' NOT NULL, + user_new tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, + user_reminded tinyint(4) DEFAULT '0' NOT NULL, + user_reminded_time int(11) UNSIGNED DEFAULT '0' NOT NULL, PRIMARY KEY (user_id), KEY user_birthday (user_birthday), KEY user_email_hash (user_email_hash), diff --git a/phpBB/install/schemas/mysql_41_schema.sql b/phpBB/install/schemas/mysql_41_schema.sql index 81f8266f4d..34adf5674e 100644 --- a/phpBB/install/schemas/mysql_41_schema.sql +++ b/phpBB/install/schemas/mysql_41_schema.sql @@ -163,6 +163,7 @@ CREATE TABLE phpbb_confirm ( confirm_type tinyint(3) DEFAULT '0' NOT NULL, code varchar(8) DEFAULT '' NOT NULL, seed int(10) UNSIGNED DEFAULT '0' NOT NULL, + attempts mediumint(8) UNSIGNED DEFAULT '0' NOT NULL, PRIMARY KEY (session_id, confirm_id), KEY confirm_type (confirm_type) ) CHARACTER SET `utf8` COLLATE `utf8_bin`; @@ -248,6 +249,7 @@ CREATE TABLE phpbb_forums ( forum_last_poster_name varchar(255) DEFAULT '' NOT NULL, forum_last_poster_colour varchar(6) DEFAULT '' NOT NULL, forum_flags tinyint(4) DEFAULT '32' NOT NULL, + forum_options int(20) UNSIGNED DEFAULT '0' NOT NULL, display_subforum_list tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, display_on_index tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, enable_indexing tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, @@ -297,6 +299,7 @@ CREATE TABLE phpbb_groups ( group_id mediumint(8) UNSIGNED NOT NULL auto_increment, group_type tinyint(4) DEFAULT '1' NOT NULL, group_founder_manage tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, + group_skip_auth tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, group_name varchar(255) DEFAULT '' NOT NULL, group_desc text NOT NULL, group_desc_bitfield varchar(255) DEFAULT '' NOT NULL, @@ -359,6 +362,7 @@ CREATE TABLE phpbb_log ( log_data mediumtext NOT NULL, PRIMARY KEY (log_id), KEY log_type (log_type), + KEY log_time (log_time), KEY forum_id (forum_id), KEY topic_id (topic_id), KEY reportee_id (reportee_id), @@ -456,6 +460,7 @@ CREATE TABLE phpbb_posts ( KEY poster_ip (poster_ip), KEY poster_id (poster_id), KEY post_approved (post_approved), + KEY post_username (post_username), KEY tid_post_time (topic_id, post_time) ) CHARACTER SET `utf8` COLLATE `utf8_bin`; @@ -483,6 +488,7 @@ CREATE TABLE phpbb_privmsgs ( message_edit_count smallint(4) UNSIGNED DEFAULT '0' NOT NULL, to_address text NOT NULL, bcc_address text NOT NULL, + message_reported tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, PRIMARY KEY (msg_id), KEY author_ip (author_ip), KEY message_time (message_time), @@ -550,6 +556,7 @@ CREATE TABLE phpbb_profile_fields ( field_validation varchar(20) DEFAULT '' NOT NULL, field_required tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, field_show_on_reg tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, + field_show_on_vt tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, field_show_profile tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, field_hide tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, field_no_view tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, @@ -606,12 +613,15 @@ CREATE TABLE phpbb_reports ( report_id mediumint(8) UNSIGNED NOT NULL auto_increment, reason_id smallint(4) UNSIGNED DEFAULT '0' NOT NULL, post_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL, + pm_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL, user_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL, user_notify tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, report_closed tinyint(1) UNSIGNED DEFAULT '0' NOT NULL, report_time int(11) UNSIGNED DEFAULT '0' NOT NULL, report_text mediumtext NOT NULL, - PRIMARY KEY (report_id) + PRIMARY KEY (report_id), + KEY post_id (post_id), + KEY pm_id (pm_id) ) CHARACTER SET `utf8` COLLATE `utf8_bin`; @@ -943,7 +953,7 @@ CREATE TABLE phpbb_users ( user_allow_viewonline tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, user_allow_viewemail tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, user_allow_massemail tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, - user_options int(11) UNSIGNED DEFAULT '895' NOT NULL, + user_options int(11) UNSIGNED DEFAULT '230271' NOT NULL, user_avatar varchar(255) DEFAULT '' NOT NULL, user_avatar_type tinyint(2) DEFAULT '0' NOT NULL, user_avatar_width smallint(4) UNSIGNED DEFAULT '0' NOT NULL, @@ -963,6 +973,9 @@ CREATE TABLE phpbb_users ( user_actkey varchar(32) DEFAULT '' NOT NULL, user_newpasswd varchar(40) DEFAULT '' NOT NULL, user_form_salt varchar(32) DEFAULT '' NOT NULL, + user_new tinyint(1) UNSIGNED DEFAULT '1' NOT NULL, + user_reminded tinyint(4) DEFAULT '0' NOT NULL, + user_reminded_time int(11) UNSIGNED DEFAULT '0' NOT NULL, PRIMARY KEY (user_id), KEY user_birthday (user_birthday), KEY user_email_hash (user_email_hash), diff --git a/phpBB/install/schemas/oracle_schema.sql b/phpBB/install/schemas/oracle_schema.sql index 50f3ee1f80..15692ea984 100644 --- a/phpBB/install/schemas/oracle_schema.sql +++ b/phpBB/install/schemas/oracle_schema.sql @@ -338,6 +338,7 @@ CREATE TABLE phpbb_confirm ( confirm_type number(3) DEFAULT '0' NOT NULL, code varchar2(8) DEFAULT '' , seed number(10) DEFAULT '0' NOT NULL, + attempts number(8) DEFAULT '0' NOT NULL, CONSTRAINT pk_phpbb_confirm PRIMARY KEY (session_id, confirm_id) ) / @@ -504,6 +505,7 @@ CREATE TABLE phpbb_forums ( forum_last_poster_name varchar2(765) DEFAULT '' , forum_last_poster_colour varchar2(6) DEFAULT '' , forum_flags number(4) DEFAULT '32' NOT NULL, + forum_options number(20) DEFAULT '0' NOT NULL, display_subforum_list number(1) DEFAULT '1' NOT NULL, display_on_index number(1) DEFAULT '1' NOT NULL, enable_indexing number(1) DEFAULT '1' NOT NULL, @@ -586,6 +588,7 @@ CREATE TABLE phpbb_groups ( group_id number(8) NOT NULL, group_type number(4) DEFAULT '1' NOT NULL, group_founder_manage number(1) DEFAULT '0' NOT NULL, + group_skip_auth number(1) DEFAULT '0' NOT NULL, group_name varchar2(255) DEFAULT '' , group_desc clob DEFAULT '' , group_desc_bitfield varchar2(255) DEFAULT '' , @@ -712,6 +715,8 @@ CREATE TABLE phpbb_log ( CREATE INDEX phpbb_log_log_type ON phpbb_log (log_type) / +CREATE INDEX phpbb_log_log_time ON phpbb_log (log_time) +/ CREATE INDEX phpbb_log_forum_id ON phpbb_log (forum_id) / CREATE INDEX phpbb_log_topic_id ON phpbb_log (topic_id) @@ -820,7 +825,7 @@ CREATE TABLE phpbb_poll_votes ( topic_id number(8) DEFAULT '0' NOT NULL, poll_option_id number(4) DEFAULT '0' NOT NULL, vote_user_id number(8) DEFAULT '0' NOT NULL, - vote_user_ip varchar2(40) DEFAULT '' + vote_user_ip varchar2(40) DEFAULT '' ) / @@ -875,6 +880,8 @@ CREATE INDEX phpbb_posts_poster_id ON phpbb_posts (poster_id) / CREATE INDEX phpbb_posts_post_approved ON phpbb_posts (post_approved) / +CREATE INDEX phpbb_posts_post_username ON phpbb_posts (post_username) +/ CREATE INDEX phpbb_posts_tid_post_time ON phpbb_posts (topic_id, post_time) / @@ -919,6 +926,7 @@ CREATE TABLE phpbb_privmsgs ( message_edit_count number(4) DEFAULT '0' NOT NULL, to_address clob DEFAULT '' , bcc_address clob DEFAULT '' , + message_reported number(1) DEFAULT '0' NOT NULL, CONSTRAINT pk_phpbb_privmsgs PRIMARY KEY (msg_id) ) / @@ -1055,6 +1063,7 @@ CREATE TABLE phpbb_profile_fields ( field_validation varchar2(60) DEFAULT '' , field_required number(1) DEFAULT '0' NOT NULL, field_show_on_reg number(1) DEFAULT '0' NOT NULL, + field_show_on_vt number(1) DEFAULT '0' NOT NULL, field_show_profile number(1) DEFAULT '0' NOT NULL, field_hide number(1) DEFAULT '0' NOT NULL, field_no_view number(1) DEFAULT '0' NOT NULL, @@ -1160,6 +1169,7 @@ CREATE TABLE phpbb_reports ( report_id number(8) NOT NULL, reason_id number(4) DEFAULT '0' NOT NULL, post_id number(8) DEFAULT '0' NOT NULL, + pm_id number(8) DEFAULT '0' NOT NULL, user_id number(8) DEFAULT '0' NOT NULL, user_notify number(1) DEFAULT '0' NOT NULL, report_closed number(1) DEFAULT '0' NOT NULL, @@ -1169,6 +1179,10 @@ CREATE TABLE phpbb_reports ( ) / +CREATE INDEX phpbb_reports_post_id ON phpbb_reports (post_id) +/ +CREATE INDEX phpbb_reports_pm_id ON phpbb_reports (pm_id) +/ CREATE SEQUENCE phpbb_reports_seq / @@ -1464,7 +1478,7 @@ CREATE TABLE phpbb_styles_template_data ( template_filename varchar2(100) DEFAULT '' , template_included clob DEFAULT '' , template_mtime number(11) DEFAULT '0' NOT NULL, - template_data clob DEFAULT '' + template_data clob DEFAULT '' ) / @@ -1760,7 +1774,7 @@ CREATE TABLE phpbb_users ( user_allow_viewonline number(1) DEFAULT '1' NOT NULL, user_allow_viewemail number(1) DEFAULT '1' NOT NULL, user_allow_massemail number(1) DEFAULT '1' NOT NULL, - user_options number(11) DEFAULT '895' NOT NULL, + user_options number(11) DEFAULT '230271' NOT NULL, user_avatar varchar2(255) DEFAULT '' , user_avatar_type number(2) DEFAULT '0' NOT NULL, user_avatar_width number(4) DEFAULT '0' NOT NULL, @@ -1780,6 +1794,9 @@ CREATE TABLE phpbb_users ( user_actkey varchar2(32) DEFAULT '' , user_newpasswd varchar2(120) DEFAULT '' , user_form_salt varchar2(96) DEFAULT '' , + user_new number(1) DEFAULT '1' NOT NULL, + user_reminded number(4) DEFAULT '0' NOT NULL, + user_reminded_time number(11) DEFAULT '0' NOT NULL, CONSTRAINT pk_phpbb_users PRIMARY KEY (user_id), CONSTRAINT u_phpbb_username_clean UNIQUE (username_clean) ) diff --git a/phpBB/install/schemas/postgres_schema.sql b/phpBB/install/schemas/postgres_schema.sql index 9736363104..46e77e64b4 100644 --- a/phpBB/install/schemas/postgres_schema.sql +++ b/phpBB/install/schemas/postgres_schema.sql @@ -276,6 +276,7 @@ CREATE TABLE phpbb_confirm ( confirm_type INT2 DEFAULT '0' NOT NULL, code varchar(8) DEFAULT '' NOT NULL, seed INT4 DEFAULT '0' NOT NULL CHECK (seed >= 0), + attempts INT4 DEFAULT '0' NOT NULL CHECK (attempts >= 0), PRIMARY KEY (session_id, confirm_id) ); @@ -381,6 +382,7 @@ CREATE TABLE phpbb_forums ( forum_last_poster_name varchar(255) DEFAULT '' NOT NULL, forum_last_poster_colour varchar(6) DEFAULT '' NOT NULL, forum_flags INT2 DEFAULT '32' NOT NULL, + forum_options INT4 DEFAULT '0' NOT NULL CHECK (forum_options >= 0), display_subforum_list INT2 DEFAULT '1' NOT NULL CHECK (display_subforum_list >= 0), display_on_index INT2 DEFAULT '1' NOT NULL CHECK (display_on_index >= 0), enable_indexing INT2 DEFAULT '1' NOT NULL CHECK (enable_indexing >= 0), @@ -440,6 +442,7 @@ CREATE TABLE phpbb_groups ( group_id INT4 DEFAULT nextval('phpbb_groups_seq'), group_type INT2 DEFAULT '1' NOT NULL, group_founder_manage INT2 DEFAULT '0' NOT NULL CHECK (group_founder_manage >= 0), + group_skip_auth INT2 DEFAULT '0' NOT NULL CHECK (group_skip_auth >= 0), group_name varchar_ci DEFAULT '' NOT NULL, group_desc varchar(4000) DEFAULT '' NOT NULL, group_desc_bitfield varchar(255) DEFAULT '' NOT NULL, @@ -516,6 +519,7 @@ CREATE TABLE phpbb_log ( ); CREATE INDEX phpbb_log_log_type ON phpbb_log (log_type); +CREATE INDEX phpbb_log_log_time ON phpbb_log (log_time); CREATE INDEX phpbb_log_forum_id ON phpbb_log (forum_id); CREATE INDEX phpbb_log_topic_id ON phpbb_log (topic_id); CREATE INDEX phpbb_log_reportee_id ON phpbb_log (reportee_id); @@ -627,6 +631,7 @@ CREATE INDEX phpbb_posts_topic_id ON phpbb_posts (topic_id); CREATE INDEX phpbb_posts_poster_ip ON phpbb_posts (poster_ip); CREATE INDEX phpbb_posts_poster_id ON phpbb_posts (poster_id); CREATE INDEX phpbb_posts_post_approved ON phpbb_posts (post_approved); +CREATE INDEX phpbb_posts_post_username ON phpbb_posts (post_username); CREATE INDEX phpbb_posts_tid_post_time ON phpbb_posts (topic_id, post_time); /* @@ -656,6 +661,7 @@ CREATE TABLE phpbb_privmsgs ( message_edit_count INT2 DEFAULT '0' NOT NULL CHECK (message_edit_count >= 0), to_address varchar(4000) DEFAULT '' NOT NULL, bcc_address varchar(4000) DEFAULT '' NOT NULL, + message_reported INT2 DEFAULT '0' NOT NULL CHECK (message_reported >= 0), PRIMARY KEY (msg_id) ); @@ -737,6 +743,7 @@ CREATE TABLE phpbb_profile_fields ( field_validation varchar(20) DEFAULT '' NOT NULL, field_required INT2 DEFAULT '0' NOT NULL CHECK (field_required >= 0), field_show_on_reg INT2 DEFAULT '0' NOT NULL CHECK (field_show_on_reg >= 0), + field_show_on_vt INT2 DEFAULT '0' NOT NULL CHECK (field_show_on_vt >= 0), field_show_profile INT2 DEFAULT '0' NOT NULL CHECK (field_show_profile >= 0), field_hide INT2 DEFAULT '0' NOT NULL CHECK (field_hide >= 0), field_no_view INT2 DEFAULT '0' NOT NULL CHECK (field_no_view >= 0), @@ -807,6 +814,7 @@ CREATE TABLE phpbb_reports ( report_id INT4 DEFAULT nextval('phpbb_reports_seq'), reason_id INT2 DEFAULT '0' NOT NULL CHECK (reason_id >= 0), post_id INT4 DEFAULT '0' NOT NULL CHECK (post_id >= 0), + pm_id INT4 DEFAULT '0' NOT NULL CHECK (pm_id >= 0), user_id INT4 DEFAULT '0' NOT NULL CHECK (user_id >= 0), user_notify INT2 DEFAULT '0' NOT NULL CHECK (user_notify >= 0), report_closed INT2 DEFAULT '0' NOT NULL CHECK (report_closed >= 0), @@ -815,6 +823,8 @@ CREATE TABLE phpbb_reports ( PRIMARY KEY (report_id) ); +CREATE INDEX phpbb_reports_post_id ON phpbb_reports (post_id); +CREATE INDEX phpbb_reports_pm_id ON phpbb_reports (pm_id); /* Table: 'phpbb_reports_reasons' @@ -1206,7 +1216,7 @@ CREATE TABLE phpbb_users ( user_allow_viewonline INT2 DEFAULT '1' NOT NULL CHECK (user_allow_viewonline >= 0), user_allow_viewemail INT2 DEFAULT '1' NOT NULL CHECK (user_allow_viewemail >= 0), user_allow_massemail INT2 DEFAULT '1' NOT NULL CHECK (user_allow_massemail >= 0), - user_options INT4 DEFAULT '895' NOT NULL CHECK (user_options >= 0), + user_options INT4 DEFAULT '230271' NOT NULL CHECK (user_options >= 0), user_avatar varchar(255) DEFAULT '' NOT NULL, user_avatar_type INT2 DEFAULT '0' NOT NULL, user_avatar_width INT2 DEFAULT '0' NOT NULL CHECK (user_avatar_width >= 0), @@ -1226,6 +1236,9 @@ CREATE TABLE phpbb_users ( user_actkey varchar(32) DEFAULT '' NOT NULL, user_newpasswd varchar(40) DEFAULT '' NOT NULL, user_form_salt varchar(32) DEFAULT '' NOT NULL, + user_new INT2 DEFAULT '1' NOT NULL CHECK (user_new >= 0), + user_reminded INT2 DEFAULT '0' NOT NULL, + user_reminded_time INT4 DEFAULT '0' NOT NULL CHECK (user_reminded_time >= 0), PRIMARY KEY (user_id) ); diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql index 8b6c6d7189..5c653afc41 100644 --- a/phpBB/install/schemas/schema_data.sql +++ b/phpBB/install/schemas/schema_data.sql @@ -8,9 +8,11 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('active_sessions', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_attachments', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_autologin', '1'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar_local', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar_remote', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar_upload', '0'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar_remote_upload', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_bbcode', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_birthdays', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_bookmarks', '1'); @@ -21,9 +23,11 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_name_chars', INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_namechange', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_nocensors', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_pm_attach', '0'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_pm_report', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_post_flash', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_post_links', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_privmsg', '1'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_quick_reply', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_sig', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_sig_bbcode', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_sig_flash', '0'); @@ -60,6 +64,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('browser_check', '1 INSERT INTO phpbb_config (config_name, config_value) VALUES ('bump_interval', '10'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('bump_type', 'd'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('cache_gc', '7200'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_plugin', 'phpbb_captcha_nogd'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd_foreground_noise', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('captcha_gd_x_grid', '25'); @@ -85,6 +90,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('default_style', '1 INSERT INTO phpbb_config (config_name, config_value) VALUES ('display_last_edited', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('display_order', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('edit_time', '0'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('delete_time', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('email_check_mx', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('email_enable', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('email_function_name', 'mail'); @@ -92,7 +98,15 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('email_package_size INSERT INTO phpbb_config (config_name, config_value) VALUES ('enable_confirm', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('enable_pm_icons', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('enable_post_confirm', '1'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('enable_queue_trigger', '0'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('feed_enable', '0'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('feed_limit', '10'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('feed_overall_forums', '1'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('feed_overall_forums_limit', '15'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('feed_overall_topics', '0'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('feed_overall_topics_limit', '15'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('feed_forum', '1'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('feed_topic', '1'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('feed_item_statistics', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('flood_interval', '15'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('force_server_vars', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('form_token_lifetime', '7200'); @@ -161,7 +175,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_filesize_pm', INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_login_attempts', '3'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_name_chars', '20'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_num_search_keywords', '10'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_pass_chars', '30'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_pass_chars', '100'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_poll_options', '10'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_post_chars', '60000'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_post_font_size', '200'); @@ -179,8 +193,11 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_sig_smilies', INSERT INTO phpbb_config (config_name, config_value) VALUES ('max_sig_urls', '5'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('min_name_chars', '3'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('min_pass_chars', '6'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('min_post_chars', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('min_search_author_chars', '3'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('mime_triggers', 'body|head|html|img|plaintext|a href|pre|script|table|title'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('new_member_post_limit', '3'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('new_member_group_default', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('override_user_style', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('pass_complex', 'PASS_TYPE_ANY'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('pm_edit_time', '0'); @@ -190,7 +207,6 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('pm_max_recipients' INSERT INTO phpbb_config (config_name, config_value) VALUES ('posts_per_page', '10'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('print_pm', '1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('queue_interval', '600'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('queue_trigger_posts', '3'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('ranks_path', 'images/ranks'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('require_activation', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('referer_validation', '1'); @@ -212,6 +228,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('session_length', ' INSERT INTO phpbb_config (config_name, config_value) VALUES ('site_desc', '{L_CONFIG_SITE_DESC}'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('sitename', '{L_CONFIG_SITENAME}'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('smilies_path', 'images/smilies'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('smilies_per_page', '50'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_auth_method', 'PLAIN'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_delivery', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('smtp_host', ''); @@ -222,7 +239,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('topics_per_page', INSERT INTO phpbb_config (config_name, config_value) VALUES ('tpl_allow_php', '0'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('upload_icons_path', 'images/upload_icons'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('upload_path', 'files'); -INSERT INTO phpbb_config (config_name, config_value) VALUES ('version', '3.0.5'); +INSERT INTO phpbb_config (config_name, config_value) VALUES ('version', '3.0.6-RC1'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('warnings_expire_days', '90'); INSERT INTO phpbb_config (config_name, config_value) VALUES ('warnings_gc', '14400'); @@ -399,6 +416,11 @@ INSERT INTO phpbb_acl_roles (role_name, role_description, role_type, role_order) INSERT INTO phpbb_acl_roles (role_name, role_description, role_type, role_order) VALUES ('ROLE_FORUM_POLLS', 'ROLE_DESCRIPTION_FORUM_POLLS', 'f_', 6); INSERT INTO phpbb_acl_roles (role_name, role_description, role_type, role_order) VALUES ('ROLE_FORUM_LIMITED_POLLS', 'ROLE_DESCRIPTION_FORUM_LIMITED_POLLS', 'f_', 4); +# 23 +INSERT INTO phpbb_acl_roles (role_name, role_description, role_type, role_order) VALUES ('ROLE_USER_NEW_MEMBER', 'ROLE_DESCRIPTION_USER_NEW_MEMBER', 'u_', 6); + +# 24 +INSERT INTO phpbb_acl_roles (role_name, role_description, role_type, role_order) VALUES ('ROLE_FORUM_NEW_MEMBER', 'ROLE_DESCRIPTION_FORUM_NEW_MEMBER', 'f_', 10); # -- phpbb_styles INSERT INTO phpbb_styles (style_name, style_copyright, style_active, template_id, theme_id, imageset_id) VALUES ('prosilver', '© phpBB Group', 1, 1, 1, 1); @@ -500,6 +522,7 @@ INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_co INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('GLOBAL_MODERATORS', 3, 0, '00AA00', 1, '', '', '', 0); INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('ADMINISTRATORS', 3, 1, 'AA0000', 1, '', '', '', 0); INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('BOTS', 3, 0, '9E8DA7', 0, '', '', '', 5); +INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('NEWLY_REGISTERED', 3, 0, '', 0, '', '', '', 5); # -- User -> Group INSERT INTO phpbb_user_group (group_id, user_id, user_pending, group_leader) VALUES (1, 1, 0, 0); @@ -581,6 +604,13 @@ INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT # Limited Access + Polls (f_) INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 22, auth_option_id, 1 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option NOT IN ('f_announce', 'f_attach', 'f_bump', 'f_delete', 'f_flash', 'f_icons', 'f_ignoreflood', 'f_sticky', 'f_user_lock', 'f_votechg'); +# New Member (u_) +INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 23, auth_option_id, 0 FROM phpbb_acl_options WHERE auth_option LIKE 'u_%' AND auth_option IN ('u_sendpm', 'u_masspm', 'u_masspm_group'); + +# New Member (f_) +INSERT INTO phpbb_acl_roles_data (role_id, auth_option_id, auth_setting) SELECT 24, auth_option_id, 0 FROM phpbb_acl_options WHERE auth_option LIKE 'f_%' AND auth_option IN ('f_noapprove'); + + # Permissions # GUESTS - u_download and u_search ability @@ -631,6 +661,12 @@ INSERT INTO phpbb_acl_groups (group_id, forum_id, auth_option_id, auth_role_id, # Bots having bot access INSERT INTO phpbb_acl_groups (group_id, forum_id, auth_option_id, auth_role_id, auth_setting) VALUES (6, 2, 0, 19, 0); +# NEW MEMBERS aren't allowed to PM +INSERT INTO phpbb_acl_groups (group_id, forum_id, auth_option_id, auth_role_id, auth_setting) VALUES (7, 0, 0, 23, 0); + +# NEW MEMBERS on the queue +INSERT INTO phpbb_acl_groups (group_id, forum_id, auth_option_id, auth_role_id, auth_setting) VALUES (7, 2, 0, 24, 0); + # -- Demo Topic INSERT INTO phpbb_topics (topic_title, topic_poster, topic_time, topic_views, topic_replies, topic_replies_real, forum_id, topic_status, topic_type, topic_first_post_id, topic_first_poster_name, topic_first_poster_colour, topic_last_post_id, topic_last_poster_id, topic_last_poster_name, topic_last_poster_colour, topic_last_post_subject, topic_last_post_time, topic_last_view_time, poll_title) VALUES ('{L_TOPICS_TOPIC_TITLE}', 2, 972086460, 0, 0, 0, 2, 0, 0, 1, 'Admin', 'AA0000', 1, 2, 'Admin', 'AA0000', '{L_TOPICS_TOPIC_TITLE}', 972086460, 972086460, ''); diff --git a/phpBB/install/schemas/sqlite_schema.sql b/phpBB/install/schemas/sqlite_schema.sql index 36686955a9..d754219cdf 100644 --- a/phpBB/install/schemas/sqlite_schema.sql +++ b/phpBB/install/schemas/sqlite_schema.sql @@ -160,6 +160,7 @@ CREATE TABLE phpbb_confirm ( confirm_type tinyint(3) NOT NULL DEFAULT '0', code varchar(8) NOT NULL DEFAULT '', seed INTEGER UNSIGNED NOT NULL DEFAULT '0', + attempts INTEGER UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (session_id, confirm_id) ); @@ -241,6 +242,7 @@ CREATE TABLE phpbb_forums ( forum_last_poster_name varchar(255) NOT NULL DEFAULT '', forum_last_poster_colour varchar(6) NOT NULL DEFAULT '', forum_flags tinyint(4) NOT NULL DEFAULT '32', + forum_options INTEGER UNSIGNED NOT NULL DEFAULT '0', display_subforum_list INTEGER UNSIGNED NOT NULL DEFAULT '1', display_on_index INTEGER UNSIGNED NOT NULL DEFAULT '1', enable_indexing INTEGER UNSIGNED NOT NULL DEFAULT '1', @@ -289,6 +291,7 @@ CREATE TABLE phpbb_groups ( group_id INTEGER PRIMARY KEY NOT NULL , group_type tinyint(4) NOT NULL DEFAULT '1', group_founder_manage INTEGER UNSIGNED NOT NULL DEFAULT '0', + group_skip_auth INTEGER UNSIGNED NOT NULL DEFAULT '0', group_name varchar(255) NOT NULL DEFAULT '', group_desc text(65535) NOT NULL DEFAULT '', group_desc_bitfield varchar(255) NOT NULL DEFAULT '', @@ -349,6 +352,7 @@ CREATE TABLE phpbb_log ( ); CREATE INDEX phpbb_log_log_type ON phpbb_log (log_type); +CREATE INDEX phpbb_log_log_time ON phpbb_log (log_time); CREATE INDEX phpbb_log_forum_id ON phpbb_log (forum_id); CREATE INDEX phpbb_log_topic_id ON phpbb_log (topic_id); CREATE INDEX phpbb_log_reportee_id ON phpbb_log (reportee_id); @@ -444,6 +448,7 @@ CREATE INDEX phpbb_posts_topic_id ON phpbb_posts (topic_id); CREATE INDEX phpbb_posts_poster_ip ON phpbb_posts (poster_ip); CREATE INDEX phpbb_posts_poster_id ON phpbb_posts (poster_id); CREATE INDEX phpbb_posts_post_approved ON phpbb_posts (post_approved); +CREATE INDEX phpbb_posts_post_username ON phpbb_posts (post_username); CREATE INDEX phpbb_posts_tid_post_time ON phpbb_posts (topic_id, post_time); # Table: 'phpbb_privmsgs' @@ -468,7 +473,8 @@ CREATE TABLE phpbb_privmsgs ( message_edit_time INTEGER UNSIGNED NOT NULL DEFAULT '0', message_edit_count INTEGER UNSIGNED NOT NULL DEFAULT '0', to_address text(65535) NOT NULL DEFAULT '', - bcc_address text(65535) NOT NULL DEFAULT '' + bcc_address text(65535) NOT NULL DEFAULT '', + message_reported INTEGER UNSIGNED NOT NULL DEFAULT '0' ); CREATE INDEX phpbb_privmsgs_author_ip ON phpbb_privmsgs (author_ip); @@ -533,6 +539,7 @@ CREATE TABLE phpbb_profile_fields ( field_validation varchar(20) NOT NULL DEFAULT '', field_required INTEGER UNSIGNED NOT NULL DEFAULT '0', field_show_on_reg INTEGER UNSIGNED NOT NULL DEFAULT '0', + field_show_on_vt INTEGER UNSIGNED NOT NULL DEFAULT '0', field_show_profile INTEGER UNSIGNED NOT NULL DEFAULT '0', field_hide INTEGER UNSIGNED NOT NULL DEFAULT '0', field_no_view INTEGER UNSIGNED NOT NULL DEFAULT '0', @@ -587,6 +594,7 @@ CREATE TABLE phpbb_reports ( report_id INTEGER PRIMARY KEY NOT NULL , reason_id INTEGER UNSIGNED NOT NULL DEFAULT '0', post_id INTEGER UNSIGNED NOT NULL DEFAULT '0', + pm_id INTEGER UNSIGNED NOT NULL DEFAULT '0', user_id INTEGER UNSIGNED NOT NULL DEFAULT '0', user_notify INTEGER UNSIGNED NOT NULL DEFAULT '0', report_closed INTEGER UNSIGNED NOT NULL DEFAULT '0', @@ -594,6 +602,8 @@ CREATE TABLE phpbb_reports ( report_text mediumtext(16777215) NOT NULL DEFAULT '' ); +CREATE INDEX phpbb_reports_post_id ON phpbb_reports (post_id); +CREATE INDEX phpbb_reports_pm_id ON phpbb_reports (pm_id); # Table: 'phpbb_reports_reasons' CREATE TABLE phpbb_reports_reasons ( @@ -913,7 +923,7 @@ CREATE TABLE phpbb_users ( user_allow_viewonline INTEGER UNSIGNED NOT NULL DEFAULT '1', user_allow_viewemail INTEGER UNSIGNED NOT NULL DEFAULT '1', user_allow_massemail INTEGER UNSIGNED NOT NULL DEFAULT '1', - user_options INTEGER UNSIGNED NOT NULL DEFAULT '895', + user_options INTEGER UNSIGNED NOT NULL DEFAULT '230271', user_avatar varchar(255) NOT NULL DEFAULT '', user_avatar_type tinyint(2) NOT NULL DEFAULT '0', user_avatar_width INTEGER UNSIGNED NOT NULL DEFAULT '0', @@ -932,7 +942,10 @@ CREATE TABLE phpbb_users ( user_interests text(65535) NOT NULL DEFAULT '', user_actkey varchar(32) NOT NULL DEFAULT '', user_newpasswd varchar(40) NOT NULL DEFAULT '', - user_form_salt varchar(32) NOT NULL DEFAULT '' + user_form_salt varchar(32) NOT NULL DEFAULT '', + user_new INTEGER UNSIGNED NOT NULL DEFAULT '1', + user_reminded tinyint(4) NOT NULL DEFAULT '0', + user_reminded_time INTEGER UNSIGNED NOT NULL DEFAULT '0' ); CREATE INDEX phpbb_users_user_birthday ON phpbb_users (user_birthday); diff --git a/phpBB/language/en/acp/ban.php b/phpBB/language/en/acp/ban.php index 5fcbb1fa69..099834d1e4 100644 --- a/phpBB/language/en/acp/ban.php +++ b/phpBB/language/en/acp/ban.php @@ -48,6 +48,8 @@ $lang = array_merge($lang, array( 'BAN_REASON' => 'Reason for ban', 'BAN_GIVE_REASON' => 'Reason shown to the banned', 'BAN_UPDATE_SUCCESSFUL' => 'The banlist has been updated successfully.', + 'BANNED_UNTIL_DATE' => 'until %s', // Example: "until Mon 13.Jul.2009, 14:44" + 'BANNED_UNTIL_DURATION' => '%1$s (until %2$s)', // Example: "7 days (until Tue 14.Jul.2009, 14:44)" 'EMAIL_BAN' => 'Ban one or more e-mail addresses', 'EMAIL_BAN_EXCLUDE_EXPLAIN' => 'Enable this to exclude the entered e-mail address from all current bans.', @@ -67,7 +69,7 @@ $lang = array_merge($lang, array( 'LENGTH_BAN_INVALID' => 'The date has to be formatted YYYY-MM-DD.', 'PERMANENT' => 'Permanent', - + 'UNTIL' => 'Until', 'USER_BAN' => 'Ban one or more usernames', 'USER_BAN_EXCLUDE_EXPLAIN' => 'Enable this to exclude the entered users from all current bans.', @@ -75,8 +77,6 @@ $lang = array_merge($lang, array( 'USER_NO_BANNED' => 'No banned usernames', 'USER_UNBAN' => 'Un-ban or un-exclude usernames', 'USER_UNBAN_EXPLAIN' => 'You can unban (or un-exclude) multiple users in one go using the appropriate combination of mouse and keyboard for your computer and browser. Excluded users are emphasised.', - - )); ?> \ No newline at end of file diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php index 7c2f3a24bb..8797a1210a 100644 --- a/phpBB/language/en/acp/board.php +++ b/phpBB/language/en/acp/board.php @@ -70,6 +70,10 @@ $lang = array_merge($lang, array( 'ALLOW_NO_CENSORS' => 'Allow disabling of word censoring', 'ALLOW_NO_CENSORS_EXPLAIN' => 'Users can choose to disable the automatic word censoring of posts and private messages.', 'ALLOW_PM_ATTACHMENTS' => 'Allow attachments in private messages', + 'ALLOW_PM_REPORT' => 'Allow users to report private messages', + 'ALLOW_PM_REPORT_EXPLAIN' => 'If this setting is enabled, users have the option of reporting a private message they have received or sent to the board’s moderators. These private messages will then be visible in the Moderator Control Panel.', + 'ALLOW_QUICK_REPLY' => 'Allow quick reply', + 'ALLOW_QUICK_REPLY_EXPLAIN' => 'This setting defines if quick reply is enabled or not. If this setting is enabled, forums need to have their quick reply option enabled too.', 'ALLOW_SIG' => 'Allow signatures', 'ALLOW_SIG_BBCODE' => 'Allow BBCode in user signatures', 'ALLOW_SIG_FLASH' => 'Allow use of [FLASH] BBCode tag in user signatures', @@ -87,9 +91,13 @@ $lang = array_merge($lang, array( $lang = array_merge($lang, array( 'ACP_AVATAR_SETTINGS_EXPLAIN' => 'Avatars are generally small, unique images a user can associate with themselves. Depending on the style they are usually displayed below the username when viewing topics. Here you can determine how users can define their avatars. Please note that in order to upload avatars you need to have created the directory you name below and ensure it can be written to by the web server. Please also note that file size limits are only imposed on uploaded avatars, they do not apply to remotely linked images.', + 'ALLOW_AVATARS' => 'Enable avatars', + 'ALLOW_AVATARS_EXPLAIN' => 'Allow general usage of avatars;
    If you disable avatars in general or avatars of a certain mode, the disabled avatars will no longer be shown on the board, but users will still be able to download their own avatars in the User Control Panel.', 'ALLOW_LOCAL' => 'Enable gallery avatars', 'ALLOW_REMOTE' => 'Enable remote avatars', 'ALLOW_REMOTE_EXPLAIN' => 'Avatars linked to from another website.', + 'ALLOW_REMOTE_UPLOAD' => 'Enable remote avatar uploading', + 'ALLOW_REMOTE_UPLOAD_EXPLAIN' => 'Allow uploading of avatars from another website.', 'ALLOW_UPLOAD' => 'Enable avatar uploading', 'AVATAR_GALLERY_PATH' => 'Avatar gallery path', 'AVATAR_GALLERY_PATH_EXPLAIN' => 'Path under your phpBB root directory for pre-loaded images, e.g. images/avatars/gallery.', @@ -140,15 +148,12 @@ $lang = array_merge($lang, array( 'ALLOW_POST_FLASH' => 'Allow use of [FLASH] BBCode tag in posts', 'ALLOW_POST_FLASH_EXPLAIN' => 'If disallowed the [FLASH] BBCode tag is disabled in posts. Otherwise the permission system controls which users can use the [FLASH] BBCode tag.', - 'ENABLE_QUEUE_TRIGGER' => 'Enable queued posts', - 'ENABLE_QUEUE_TRIGGER_EXPLAIN' => 'Ability to put registered users posts to post approval if their post count is lower than the specified value below. This setting has no effect on the permission setting for post/topic approval.', - 'QUEUE_TRIGGER_POSTS' => 'Maximum post count for queued posts', - 'QUEUE_TRIGGER_POSTS_EXPLAIN' => 'If queued posts is enabled, this is the post count the user need to reach in order to post without post approval. If the users post count is below this number, the post is stored in the queue automatically.', - 'BUMP_INTERVAL' => 'Bump interval', 'BUMP_INTERVAL_EXPLAIN' => 'Number of minutes, hours or days between the last post to a topic and the ability to bump this topic.', - 'CHAR_LIMIT' => 'Maximum characters per post', - 'CHAR_LIMIT_EXPLAIN' => 'The number of characters allowed within a post. Set to 0 for unlimited characters.', + 'CHAR_LIMIT' => 'Maximum characters per post/message', + 'CHAR_LIMIT_EXPLAIN' => 'The number of characters allowed within a post/private message. Set to 0 for unlimited characters.', + 'DELETE_TIME' => 'Limit deleting time', + 'DELETE_TIME_EXPLAIN' => 'Limits the time available to delete a new post. Setting the value to 0 disables this behaviour.', 'DISPLAY_LAST_EDITED' => 'Display last edited time information', 'DISPLAY_LAST_EDITED_EXPLAIN' => 'Choose if the last edited by information to be displayed on posts.', 'EDIT_TIME' => 'Limit editing time', @@ -166,12 +171,15 @@ $lang = array_merge($lang, array( 'MAX_POST_IMG_WIDTH_EXPLAIN' => 'Maximum width of an image/flash file in postings. Set to 0 for unlimited size.', 'MAX_POST_URLS' => 'Maximum links per post', 'MAX_POST_URLS_EXPLAIN' => 'Maximum number of URLs in a post. Set to 0 for unlimited links.', + 'MIN_CHAR_LIMIT' => 'Minimum characters per post/message', + 'MIN_CHAR_LIMIT_EXPLAIN' => 'The minimum number of characters the user need to enter within a post/private message.', 'POSTING' => 'Posting', 'POSTS_PER_PAGE' => 'Posts per page', 'QUOTE_DEPTH_LIMIT' => 'Maximum nested quotes per post', 'QUOTE_DEPTH_LIMIT_EXPLAIN' => 'Maximum number of nested quotes in a post. Set to 0 for unlimited depth.', 'SMILIES_LIMIT' => 'Maximum smilies per post', 'SMILIES_LIMIT_EXPLAIN' => 'Maximum number of smilies in a post. Set to 0 for unlimited smilies.', + 'SMILIES_PER_PAGE' => 'Smilies per page', 'TOPICS_PER_PAGE' => 'Topics per page', )); @@ -197,8 +205,13 @@ $lang = array_merge($lang, array( $lang = array_merge($lang, array( 'ACP_REGISTER_SETTINGS_EXPLAIN' => 'Here you are able to define registration and profile related settings.', - 'ACC_ACTIVATION' => 'Account activation', - 'ACC_ACTIVATION_EXPLAIN' => 'This determines whether users have immediate access to the board or if confirmation is required. You can also completely disable new registrations.', + 'ACC_ACTIVATION' => 'Account activation', + 'ACC_ACTIVATION_EXPLAIN' => 'This determines whether users have immediate access to the board or if confirmation is required. You can also completely disable new registrations.', + 'NEW_MEMBER_POST_LIMIT' => 'New member post limit', + 'NEW_MEMBER_POST_LIMIT_EXPLAIN' => 'New members are within the Newly Registered Users group until they reach this number of posts. You can use this group to keep them from using the PM system or to review their posts. A value of 0 disables this feature.', + 'NEW_MEMBER_GROUP_DEFAULT' => 'Set Newly Registered Users group to default', + 'NEW_MEMBER_GROUP_DEFAULT_EXPLAIN' => 'If set to yes and a new member post limit is specified newly registered users will be not only put into the Newly Registered Users group, but this group also being their default one. This may come in handy if you want to assign a group default rank and/or avatar the user then inherits.', + 'ACC_ADMIN' => 'By Admin', 'ACC_DISABLE' => 'Disable', 'ACC_NONE' => 'None', @@ -231,11 +244,45 @@ $lang = array_merge($lang, array( 'USERNAME_LENGTH_EXPLAIN' => 'Minimum and maximum number of characters in usernames.', )); +// Feeds +$lang = array_merge($lang, array( + 'ACP_FEED_MANAGEMENT' => 'General Syndication Feeds settings', + 'ACP_FEED_MANAGEMENT_EXPLAIN' => 'This Module makes available various ATOM Feeds, parsing any BBCode in posts to make them readable in external feeds.', + + 'ACP_FEED_ENABLE' => 'Enable Feeds', + 'ACP_FEED_ENABLE_EXPLAIN' => 'Turns on or off ATOM Feeds for the entire board.
    Disabling this switches off all Feeds, no matter how the options below are set.', + 'ACP_FEED_LIMIT' => 'Number of items', + 'ACP_FEED_LIMIT_EXPLAIN' => 'The maximum number of feed items to display.', + + 'ACP_FEED_OVERALL_FORUMS' => 'Enable overall forums feed', + 'ACP_FEED_OVERALL_FORUMS_EXPLAIN' => 'This feed displays the latest posts from all forums topics.', + 'ACP_FEED_OVERALL_FORUMS_LIMIT' => 'Number of items per page to display in the forums feed', + + 'ACP_FEED_OVERALL_TOPIC' => 'Enable overall topics feed', + 'ACP_FEED_OVERALL_TOPIC_EXPLAIN' => 'Enables the “All Topics†feed', + 'ACP_FEED_OVERALL_TOPIC_LIMIT' => 'Number of items per page to display in the topics feed', + 'ACP_FEED_FORUM' => 'Enable Per-Forum Feeds', + 'ACP_FEED_FORUM_EXPLAIN' => 'Single forum new posts.', + 'ACP_FEED_TOPIC' => 'Enable Per-Topic Feeds', + 'ACP_FEED_TOPIC_EXPLAIN' => 'Single topics new posts.', + 'ACP_FEED_NEWS' => 'News Feeds', + 'ACP_FEED_NEWS_EXPLAIN' => 'Pull the first post from these forums. Select no forums to disable news feed.
    Select multiple forums by holding CTRL and clicking.', + + 'ACP_FEED_GENERAL' => 'General Feed Settings', + + 'ACP_FEED_ITEM_STATISTICS' => 'Item statistics', + 'ACP_FEED_ITEM_STATISTICS_EXPLAIN' => 'Display individual statistics underneath feed items
    (Posted by, date and time, Replies, Views)', + 'ACP_FEED_EXCLUDE_ID' => 'Exclude these forums', + 'ACP_FEED_EXCLUDE_ID_EXPLAIN' => 'Content from these will be not included in feeds. Select no forum to pull data from all forums.
    Select/Deselect multiple forums by holding CTRL and clicking.', +)); + // Visual Confirmation Settings $lang = array_merge($lang, array( - 'ACP_VC_SETTINGS_EXPLAIN' => 'Here you are able to define visual confirmation defaults and CAPTCHA settings.', - + 'ACP_VC_SETTINGS_EXPLAIN' => 'Here you can select and configure CAPTCHA plugins, which implement various ways to reject registration attempts from so-called spambots.', + 'AVAILABLE_CAPTCHAS' => 'Available plugins', + 'CAPTCHA_UNAVAILABLE' => 'The CAPTCHA cannot be selected as its requirements are not met.', 'CAPTCHA_GD' => 'GD CAPTCHA', + 'CAPTCHA_GD_3D' => 'GD 3D Captcha', 'CAPTCHA_GD_FOREGROUND_NOISE' => 'GD CAPTCHA foreground noise', 'CAPTCHA_GD_EXPLAIN' => 'Use GD to make a more advanced CAPTCHA.', 'CAPTCHA_GD_FOREGROUND_NOISE_EXPLAIN' => 'Use foreground noise to make the GD based CAPTCHA harder.', @@ -252,16 +299,23 @@ $lang = array_merge($lang, array( 'CAPTCHA_FONT_DEFAULT' => 'Default', 'CAPTCHA_FONT_NEW' => 'New Shapes', 'CAPTCHA_FONT_LOWER' => 'Also use lowercase', - - + 'CAPTCHA_NO_GD' => 'CAPTCHA without GD', 'CAPTCHA_PREVIEW_MSG' => 'Your changes to the visual confirmation setting were not saved. This is just a preview.', - 'CAPTCHA_PREVIEW_EXPLAIN' => 'The CAPTCHA as it will look like using the current settings. Use the preview button to refresh. Note that captchas are randomized and will differ from one view to the next.', + 'CAPTCHA_PREVIEW_EXPLAIN' => 'The CAPTCHA as it would look like using the current selection.', + + 'CAPTCHA_SELECT' => 'Installed CAPTCHA plugins', + 'CAPTCHA_SELECT_EXPLAIN' => 'The dropdown holds the CAPTCHA plugins recognized by the board. Gray entries are not available right now and might need configuration prior to use.', + 'CAPTCHA_CONFIGURE' => 'Configure CAPTCHAs', + 'CAPTCHA_CONFIGURE_EXPLAIN' => 'Change the settings for the selected CAPTCHA.', + 'CONFIGURE' => 'Configure', + 'CAPTCHA_NO_OPTIONS' => 'This CAPTCHA has no configuration options.', + 'VISUAL_CONFIRM_POST' => 'Enable visual confirmation for guest postings', 'VISUAL_CONFIRM_POST_EXPLAIN' => 'Requires anonymous users to enter a random code matching an image to help prevent mass postings.', 'VISUAL_CONFIRM_REG' => 'Enable visual confirmation for registrations', 'VISUAL_CONFIRM_REG_EXPLAIN' => 'Requires new users to enter a random code matching an image to help prevent mass registrations.', 'VISUAL_CONFIRM_REFRESH' => 'Enable users to refresh the confirmation image', - 'VISUAL_CONFIRM_REFRESH_EXPLAIN' => 'Allows users to request new confirmation codes, if they are unable to solve the VC during registration.', + 'VISUAL_CONFIRM_REFRESH_EXPLAIN' => 'Allows users to request new confirmation codes, if they are unable to solve the VC during registration. Some plugins might not support this option.', )); // Cookie Settings @@ -347,7 +401,7 @@ $lang = array_merge($lang, array( 'ACP_SERVER_SETTINGS_EXPLAIN' => 'Here you define server and domain dependant settings. Please ensure the data you enter is accurate, errors will result in e-mails containing incorrect information. When entering the domain name remember it does include http:// or other protocol term. Only alter the port number if you know your server uses a different value, port 80 is correct in most cases.', 'ENABLE_GZIP' => 'Enable GZip compression', - 'ENABLE_GZIP_EXPLAIN' => 'Generated content will be compressed prior to sending it to the user. This can reduce network traffic but will also increase CPU usage on both server and client side.', + 'ENABLE_GZIP_EXPLAIN' => 'Generated content will be compressed prior to sending it to the user. This can reduce network traffic but will also increase CPU usage on both server and client side. Requires zlib PHP extension to be loaded.', 'FORCE_SERVER_VARS' => 'Force server URL settings', 'FORCE_SERVER_VARS_EXPLAIN' => 'If set to yes the server settings defined here will be used in favour of the automatically determined values.', 'ICONS_PATH' => 'Post icons storage path', @@ -434,7 +488,7 @@ $lang = array_merge($lang, array( 'EMAIL_SIG' => 'E-mail signature', 'EMAIL_SIG_EXPLAIN' => 'This text will be attached to all e-mails the board sends.', 'ENABLE_EMAIL' => 'Enable board-wide e-mails', - 'ENABLE_EMAIL_EXPLAIN' => 'If this is set to disabled no e-mails will be sent by the board at all.', + 'ENABLE_EMAIL_EXPLAIN' => 'If this is set to disabled no e-mails will be sent by the board at all. Note the user and admin account activation settings require this setting to be enabled. If currently using “user†or “admin†activation in the activation settings, disabling this setting will require no activation of new accounts.', 'SMTP_AUTH_METHOD' => 'Authentication method for SMTP', 'SMTP_AUTH_METHOD_EXPLAIN' => 'Only used if a username/password is set, ask your provider if you are unsure which method to use.', 'SMTP_CRAM_MD5' => 'CRAM-MD5', diff --git a/phpBB/language/en/acp/common.php b/phpBB/language/en/acp/common.php index 6cfcc44d21..94188f4b1b 100644 --- a/phpBB/language/en/acp/common.php +++ b/phpBB/language/en/acp/common.php @@ -88,6 +88,7 @@ $lang = array_merge($lang, array( 'ACP_FORUM_MANAGEMENT' => 'Forum management', 'ACP_FORUM_MODERATORS' => 'Forum moderators', 'ACP_FORUM_PERMISSIONS' => 'Forum permissions', + 'ACP_FORUM_PERMISSIONS_COPY' => 'Copy forum permissions', 'ACP_FORUM_ROLES' => 'Forum roles', 'ACP_GENERAL_CONFIGURATION' => 'General configuration', @@ -148,11 +149,15 @@ $lang = array_merge($lang, array( 'ACP_RESTORE' => 'Restore', + 'ACP_FEED' => 'Feed management', + 'ACP_FEED_SETTINGS' => 'Feed settings', + 'ACP_SEARCH' => 'Search configuration', 'ACP_SEARCH_INDEX' => 'Search index', 'ACP_SEARCH_SETTINGS' => 'Search settings', 'ACP_SECURITY_SETTINGS' => 'Security settings', + 'ACP_SEND_STATISTICS' => 'Send statistical information', 'ACP_SERVER_CONFIGURATION' => 'Server configuration', 'ACP_SERVER_SETTINGS' => 'Server settings', 'ACP_SIGNATURE_SETTINGS' => 'Signature settings', @@ -161,6 +166,8 @@ $lang = array_merge($lang, array( 'ACP_STYLE_MANAGEMENT' => 'Style management', 'ACP_STYLES' => 'Styles', + 'ACP_SUBMIT_CHANGES' => 'Submit changes', + 'ACP_TEMPLATES' => 'Templates', 'ACP_THEMES' => 'Themes', @@ -181,8 +188,9 @@ $lang = array_merge($lang, array( 'ACP_USER_ROLES' => 'User roles', 'ACP_USER_SECURITY' => 'User security', 'ACP_USER_SIG' => 'Signature', + 'ACP_USER_WARNINGS' => 'Warnings', - 'ACP_VC_SETTINGS' => 'Visual confirmation settings', + 'ACP_VC_SETTINGS' => 'CAPTCHA module settings', 'ACP_VC_CAPTCHA_DISPLAY' => 'CAPTCHA image preview', 'ACP_VERSION_CHECK' => 'Check for updates', 'ACP_VIEW_ADMIN_PERMISSIONS' => 'View administrative permissions', @@ -241,6 +249,8 @@ $lang = array_merge($lang, array( 'MANAGE' => 'Manage', 'MENU_TOGGLE' => 'Hide or display the side menu', + 'MORE' => 'More', // Not used at the moment + 'MORE_INFORMATION' => 'More information »', 'MOVE_DOWN' => 'Move down', 'MOVE_UP' => 'Move up', @@ -267,10 +277,12 @@ $lang = array_merge($lang, array( 'SELECT_ANONYMOUS' => 'Select anonymous user', 'SELECT_OPTION' => 'Select option', - 'SETTING_TOO_LOW' => 'The entered value for the setting “%1$s†is too low. The minimal allowed value is %2$d.', - 'SETTING_TOO_BIG' => 'The entered value for the setting “%1$s†is too big. The maximal allowed value is %2$d.', - 'SETTING_TOO_LONG' => 'The entered value for the setting “%1$s†is too long. The maximal allowed length is %2$d.', - 'SETTING_TOO_SHORT' => 'The entered value for the setting “%1$s†is not long enough. The minimal allowed length is %2$d.', + 'SETTING_TOO_LOW' => 'The provided value for the setting “%1$s†is too low. The minimum acceptable value is %2$d.', + 'SETTING_TOO_BIG' => 'The provided value for the setting “%1$s†is too high. The maximum acceptable value is %2$d.', + 'SETTING_TOO_LONG' => 'The provided value for the setting “%1$s†is too long. The maximum acceptable length is %2$d.', + 'SETTING_TOO_SHORT' => 'The provided value for the setting “%1$s†is too short. The minimum acceptable length is %2$d.', + + 'SHOW_ALL_OPERATIONS' => 'Show all operations', 'UCP' => 'User Control Panel', 'USERNAMES_EXPLAIN' => 'Place each username on a separate line.', @@ -334,6 +346,10 @@ $lang = array_merge($lang, array( 'PURGE_CACHE_CONFIRM' => 'Are you sure you wish to purge the cache?', 'PURGE_CACHE_EXPLAIN' => 'Purge all cache related items, this includes any cached template files or queries.', + 'PURGE_SESSIONS' => 'Purge all sessions', + 'PURGE_SESSIONS_CONFIRM' => 'Are you sure you wish to purge all sessions? This will log out all users.', + 'PURGE_SESSIONS_EXPLAIN' => 'Purge all sessions. This will log out all users by truncating the session table.', + 'RESET_DATE' => 'Reset board’s start date', 'RESET_DATE_CONFIRM' => 'Are you sure you wish to reset the board’s start date?', 'RESET_ONLINE' => 'Reset most users ever online', @@ -357,9 +373,11 @@ $lang = array_merge($lang, array( 'UPLOAD_DIR_SIZE' => 'Size of posted attachments', 'USERS_PER_DAY' => 'Users per day', - 'VALUE' => 'Value', - 'VIEW_ADMIN_LOG' => 'View administrator log', - 'VIEW_INACTIVE_USERS' => 'View inactive users', + 'VALUE' => 'Value', + 'VERSIONCHECK_FAIL' => 'Failed to obtain latest version information.', + 'VERSIONCHECK_FORCE_UPDATE' => 'Re-Check version', + 'VIEW_ADMIN_LOG' => 'View administrator log', + 'VIEW_INACTIVE_USERS' => 'View inactive users', 'WELCOME_PHPBB' => 'Welcome to phpBB', 'WRITABLE_CONFIG' => 'Your config file (config.php) is currently world-writable. We strongly encourage you to change the permissions to 640 or at least to 644 (for example: chmod 640 config.php).', @@ -384,10 +402,24 @@ $lang = array_merge($lang, array( 'SORT_LAST_VISIT' => 'Last visit', 'SORT_REASON' => 'Reason', 'SORT_REG_DATE' => 'Registration date', + 'SORT_LAST_REMINDER'=> 'Last reminded', + 'SORT_REMINDER' => 'Reminder sent', 'USER_IS_INACTIVE' => 'User is inactive', )); +// Send statistics page +$lang = array_merge($lang, array( + 'EXPLAIN_SEND_STATISTICS' => 'Please send information about your server and board configurations to phpBB for statistical analysis. All information that could identify you or your website has been removed - the data is entirely anonymous. We base decisions about future phpBB versions on this information. The statistics are made available publically. We also share this data with the PHP project, the programming language phpBB is made with.', + 'EXPLAIN_SHOW_STATISTICS' => 'Using the button below you can preview all variables that will be transmitted.', + 'DONT_SEND_STATISTICS' => 'Return to the ACP if you do not wish to send statistical information to phpBB.', + 'GO_ACP_MAIN' => 'Go to the ACP start page', + 'HIDE_STATISTICS' => 'Hide details', + 'SEND_STATISTICS' => 'Send statistical information', + 'SHOW_STATISTICS' => 'Show details', + 'THANKS_SEND_STATISTICS' => 'Thank you for submitting your information.', +)); + // Log Entries $lang = array_merge($lang, array( 'LOG_ACL_ADD_USER_GLOBAL_U_' => 'Added or edited users’ user permissions
    » %s', @@ -464,23 +496,26 @@ $lang = array_merge($lang, array( 'LOG_CONFIG_MESSAGE' => 'Altered private message settings', 'LOG_CONFIG_POST' => 'Altered post settings', 'LOG_CONFIG_REGISTRATION' => 'Altered user registration settings', + 'LOG_CONFIG_FEED' => 'Altered syndication feeds settings', 'LOG_CONFIG_SEARCH' => 'Altered search settings', 'LOG_CONFIG_SECURITY' => 'Altered security settings', 'LOG_CONFIG_SERVER' => 'Altered server settings', 'LOG_CONFIG_SETTINGS' => 'Altered board settings', 'LOG_CONFIG_SIGNATURE' => 'Altered signature settings', - 'LOG_CONFIG_VISUAL' => 'Altered visual confirmation settings', + 'LOG_CONFIG_VISUAL' => 'Altered antibot settings', 'LOG_APPROVE_TOPIC' => 'Approved topic
    » %s', 'LOG_BUMP_TOPIC' => 'User bumped topic
    » %s', - 'LOG_DELETE_POST' => 'Deleted post
    » %s', + 'LOG_DELETE_POST' => 'Deleted post “%1$s†written by
    » %2$s', 'LOG_DELETE_SHADOW_TOPIC' => 'Deleted shadow topic
    » %s', - 'LOG_DELETE_TOPIC' => 'Deleted topic
    » %s', + 'LOG_DELETE_TOPIC' => 'Deleted topic “%1$s†written by
    » %2$s', 'LOG_FORK' => 'Copied topic
    » from %s', 'LOG_LOCK' => 'Locked topic
    » %s', 'LOG_LOCK_POST' => 'Locked post
    » %s', 'LOG_MERGE' => 'Merged posts into topic
    » %s', 'LOG_MOVE' => 'Moved topic
    » from %1$s to %2$s', + 'LOG_PM_REPORT_CLOSED' => 'Closed PM report
    » %s', + 'LOG_PM_REPORT_DELETED' => 'Deleted PM report
    » %s', 'LOG_POST_APPROVED' => 'Approved post
    » %s', 'LOG_POST_DISAPPROVED' => 'Disapproved post “%1$s†with the following reason
    » %2$s', 'LOG_POST_EDITED' => 'Edited post “%1$s†written by
    » %2$s', @@ -511,6 +546,7 @@ $lang = array_merge($lang, array( 'LOG_ERROR_EMAIL' => 'E-mail error
    » %s', 'LOG_FORUM_ADD' => 'Created new forum
    » %s', + 'LOG_FORUM_COPIED_PERMISSIONS' => 'Copied forum permissions from %1$s
    » %2$s', 'LOG_FORUM_DEL_FORUM' => 'Deleted forum
    » %s', 'LOG_FORUM_DEL_FORUMS' => 'Deleted forum and its subforums
    » %s', 'LOG_FORUM_DEL_MOVE_FORUMS' => 'Deleted forum and moved subforums to %1$s
    » %2$s', @@ -525,6 +561,8 @@ $lang = array_merge($lang, array( 'LOG_FORUM_MOVE_UP' => 'Moved forum %1$s above %2$s', 'LOG_FORUM_SYNC' => 'Re-synchronised forum
    » %s', + 'LOG_GENERAL_ERROR' => 'A general error occured: %1$s
    » %2$s', + 'LOG_GROUP_CREATED' => 'New usergroup created
    » %s', 'LOG_GROUP_DEFAULTS' => 'Group “%1$s†made default for members
    » %2$s', 'LOG_GROUP_DELETE' => 'Usergroup deleted
    » %s', @@ -533,8 +571,11 @@ $lang = array_merge($lang, array( 'LOG_GROUP_REMOVE' => 'Members removed from usergroup %1$s
    » %2$s', 'LOG_GROUP_UPDATED' => 'Usergroup details updated
    » %s', 'LOG_MODS_ADDED' => 'Added new leaders to usergroup %1$s
    » %2$s', - 'LOG_USERS_APPROVED' => 'Users approved in usergroup %1$s
    » %2$s', 'LOG_USERS_ADDED' => 'Added new members to usergroup %1$s
    » %2$s', + 'LOG_USERS_APPROVED' => 'Users approved in usergroup %1$s
    » %2$s', + 'LOG_USERS_PENDING' => 'Users requested to join group “%1$s†and need to be approved
    » %2$s', + + 'LOG_IMAGE_GENERATION_ERROR' => 'Error while creating image
    » Error in %1$s on line %2$s: %3$s', 'LOG_IMAGESET_ADD_DB' => 'Added new imageset to database
    » %s', 'LOG_IMAGESET_ADD_FS' => 'Add new imageset on filesystem
    » %s', @@ -603,6 +644,8 @@ $lang = array_merge($lang, array( 'LOG_PRUNE_USER_DEL_ANON' => 'Users pruned and posts retained
    » %s', 'LOG_PURGE_CACHE' => 'Purged cache', + 'LOG_PURGE_SESSIONS' => 'Purged sessions', + 'LOG_RANK_ADDED' => 'Added new rank
    » %s', 'LOG_RANK_REMOVED' => 'Removed rank
    » %s', @@ -654,12 +697,15 @@ $lang = array_merge($lang, array( 'LOG_USER_DELETED' => 'Deleted user
    » %s', 'LOG_USER_DEL_ATTACH' => 'Removed all attachments made by the user
    » %s', 'LOG_USER_DEL_AVATAR' => 'Removed user avatar
    » %s', + 'LOG_USER_DEL_OUTBOX' => 'Emptied user outbox
    » %s', 'LOG_USER_DEL_POSTS' => 'Removed all posts made by the user
    » %s', 'LOG_USER_DEL_SIG' => 'Removed user signature
    » %s', 'LOG_USER_INACTIVE' => 'User deactivated
    » %s', 'LOG_USER_MOVE_POSTS' => 'Moved user posts
    » posts by “%1$s†to forum “%2$sâ€', 'LOG_USER_NEW_PASSWORD' => 'Changed user password
    » %s', 'LOG_USER_REACTIVATE' => 'Forced user account reactivation
    » %s', + 'LOG_USER_REMOVED_NR' => 'Removed newly registered flag from user
    » %s', + 'LOG_USER_UPDATE_EMAIL' => 'User “%1$s†changed e-mail
    » from “%2$s†to “%3$sâ€', 'LOG_USER_UPDATE_NAME' => 'Changed username
    » from “%1$s†to “%2$sâ€', 'LOG_USER_USER_UPDATE' => 'Updated user details
    » %s', @@ -683,6 +729,10 @@ $lang = array_merge($lang, array( 'LOG_USER_GROUP_JOIN_PENDING' => 'User joined group and needs to be approved
    » %s', 'LOG_USER_GROUP_RESIGN' => 'User resigned membership from group
    » %s', + 'LOG_WARNING_DELETED' => 'Deleted user warning
    » %s', + 'LOG_WARNINGS_DELETED' => 'Deleted %2$s user warnings
    » %1$s', // Example: 'Deleted 2 user warnings
    » username' + 'LOG_WARNINGS_DELETED_ALL' => 'Deleted all user warnings
    » %s', + 'LOG_WORD_ADD' => 'Added word censor
    » %s', 'LOG_WORD_DELETE' => 'Deleted word censor
    » %s', 'LOG_WORD_EDIT' => 'Edited word censor
    » %s', diff --git a/phpBB/language/en/acp/database.php b/phpBB/language/en/acp/database.php index 7100fcb1e3..ae8f76d6b7 100644 --- a/phpBB/language/en/acp/database.php +++ b/phpBB/language/en/acp/database.php @@ -54,6 +54,7 @@ $lang = array_merge($lang, array( 'DOWNLOAD_BACKUP' => 'Download backup', 'FILE_TYPE' => 'File type', + 'FILE_WRITE_FAIL' => 'Unable to write file to storage folder.', 'FULL_BACKUP' => 'Full', 'RESTORE_FAILURE' => 'The backup file may be corrupt.', diff --git a/phpBB/language/en/acp/forums.php b/phpBB/language/en/acp/forums.php index 52919f4f40..371a184fb7 100644 --- a/phpBB/language/en/acp/forums.php +++ b/phpBB/language/en/acp/forums.php @@ -44,9 +44,12 @@ $lang = array_merge($lang, array( 'AUTO_PRUNE_VIEWED' => 'Auto-prune post viewed age', 'AUTO_PRUNE_VIEWED_EXPLAIN' => 'Number of days since topic was viewed after which topic is removed.', + 'CONTINUE' => 'Continue', 'COPY_PERMISSIONS' => 'Copy permissions from', + 'COPY_PERMISSIONS_EXPLAIN' => 'To ease up the permission setup for your new forum, you can copy the permissions of an existing forum.', 'COPY_PERMISSIONS_ADD_EXPLAIN' => 'Once created, the forum will have the same permissions as the one you select here. If no forum is selected the newly created forum will not be visible until permissions had been set.', 'COPY_PERMISSIONS_EDIT_EXPLAIN' => 'If you select to copy permissions, the forum will have the same permissions as the one you select here. This will overwrite any permissions you have previously set for this forum with the permissions of the forum you select here. If no forum is selected the current permissions will be kept.', + 'COPY_TO_ACL' => 'Alternatively, you are also able to %sset up new permissions%s for this forum.', 'CREATE_FORUM' => 'Create new forum', 'DECIDE_MOVE_DELETE_CONTENT' => 'Delete content or move to forum', @@ -62,6 +65,8 @@ $lang = array_merge($lang, array( 'ENABLE_INDEXING_EXPLAIN' => 'If set to yes posts made to this forum will be indexed for searching.', 'ENABLE_POST_REVIEW' => 'Enable post review', 'ENABLE_POST_REVIEW_EXPLAIN' => 'If set to yes users are able to review their post if new posts were made to the topic while users wrote theirs. This should be disabled for chat forums.', + 'ENABLE_QUICK_REPLY' => 'Enable quick reply', + 'ENABLE_QUICK_REPLY_EXPLAIN' => 'If set to yes users get a quick reply box for this forum. If the global option for quick reply is disabled or the forum not postable to the quick reply box will not be displayed, even if set to yes here.', 'ENABLE_RECENT' => 'Display active topics', 'ENABLE_RECENT_EXPLAIN' => 'If set to yes topics made to this forum will be shown in the active topics list.', 'ENABLE_TOPIC_ICONS' => 'Enable topic icons', diff --git a/phpBB/language/en/acp/groups.php b/phpBB/language/en/acp/groups.php index db6f334540..e8c1a3c494 100644 --- a/phpBB/language/en/acp/groups.php +++ b/phpBB/language/en/acp/groups.php @@ -88,16 +88,19 @@ $lang = array_merge($lang, array( 'GROUP_PENDING' => 'Pending members', 'GROUP_MAX_RECIPIENTS' => 'Maximum number of allowed recipients per private message', 'GROUP_MAX_RECIPIENTS_EXPLAIN' => 'The maximum number of allowed recipients in a private message. If 0 is entered, the board-wide setting is used.', + 'GROUP_OPTIONS_SAVE' => 'Group wide options', 'GROUP_PROMOTE' => 'Promote to group leader', 'GROUP_RANK' => 'Group rank', 'GROUP_RECEIVE_PM' => 'Group able to receive private messages', 'GROUP_RECEIVE_PM_EXPLAIN' => 'Please note that hidden groups are not able to be messaged, regardless of this setting.', 'GROUP_REQUEST' => 'Request', 'GROUP_SETTINGS_SAVE' => 'Group wide settings', + 'GROUP_SKIP_AUTH' => 'Exempt group leader from permissions', + 'GROUP_SKIP_AUTH_EXPLAIN' => 'If enabled group leader no longer inherit permissions from the group.', 'GROUP_TYPE' => 'Group type', 'GROUP_TYPE_EXPLAIN' => 'This determines which users can join or view this group.', 'GROUP_UPDATED' => 'Group preferences updated successfully.', - + 'GROUP_USERS_ADDED' => 'New users added to group successfully.', 'GROUP_USERS_EXIST' => 'The selected users are already members.', 'GROUP_USERS_REMOVE' => 'Users removed from group and new defaults set successfully.', diff --git a/phpBB/language/en/acp/language.php b/phpBB/language/en/acp/language.php index a10148942b..4d11309ebb 100644 --- a/phpBB/language/en/acp/language.php +++ b/phpBB/language/en/acp/language.php @@ -37,7 +37,7 @@ if (empty($lang) || !is_array($lang)) $lang = array_merge($lang, array( 'ACP_FILES' => 'Admin language files', - 'ACP_LANGUAGE_PACKS_EXPLAIN' => 'Here you are able to install/remove language packs.', + 'ACP_LANGUAGE_PACKS_EXPLAIN' => 'Here you are able to install/remove language packs. The default language pack is marked with an asterisk (*).', 'EMAIL_FILES' => 'E-mail templates', diff --git a/phpBB/language/en/acp/permissions.php b/phpBB/language/en/acp/permissions.php index 920643d927..cf248cffdb 100644 --- a/phpBB/language/en/acp/permissions.php +++ b/phpBB/language/en/acp/permissions.php @@ -80,6 +80,7 @@ $lang = array_merge($lang, array( 'ACP_ADMINISTRATORS_EXPLAIN' => 'Here you can assign administrator permissions to users or groups. All users with administrator permissions can view the administration control panel.', 'ACP_FORUM_MODERATORS_EXPLAIN' => 'Here you can assign users and groups as forum moderators. To assign users access to forums, to define global moderative permissions or administrators please use the appropriate page.', 'ACP_FORUM_PERMISSIONS_EXPLAIN' => 'Here you can alter which users and groups can access which forums. To assign moderators or define administrators please use the appropriate page.', + 'ACP_FORUM_PERMISSIONS_COPY_EXPLAIN' => 'Here you can copy forum permissions from one forum to one or more other forums.', 'ACP_GLOBAL_MODERATORS_EXPLAIN' => 'Here you can assign global moderator permissions to users or groups. These moderators are like ordinary moderators except they have access to every forum on your board.', 'ACP_GROUPS_FORUM_PERMISSIONS_EXPLAIN' => 'Here you can assign forum permissions to groups.', 'ACP_GROUPS_PERMISSIONS_EXPLAIN' => 'Here you can assign global permissions to groups - user permissions, global moderator permissions and administrator permissions. User permissions include capabilities such as the use of avatars, sending private messages, et cetera; global moderator permissions such as approving posts, manage topics, manage bans, et cetera and lastly administrator permissions such as altering permissions, define custom BBCodes, manage forums, et cetera. Individual users permissions should only be changed in rare occasions, the preferred method is putting users in groups and assigning the group’s permissions.', @@ -109,6 +110,12 @@ $lang = array_merge($lang, array( 'APPLY_PERMISSIONS_EXPLAIN' => 'The permissions and role defined for this item will only be applied to this item and all checked items.', 'AUTH_UPDATED' => 'Permissions have been updated.', + 'COPY_PERMISSIONS_CONFIRM' => 'Are you sure you wish to carry out this operation? Please be aware that this will overwrite any existing permissions on the selected targets.', + 'COPY_PERMISSIONS_FORUM_FROM_EXPLAIN' => 'The source forum you want to copy permissions from.', + 'COPY_PERMISSIONS_FORUM_TO_EXPLAIN' => 'The destination forums you want the copied permissions applied to.', + 'COPY_PERMISSIONS_FROM' => 'Copy permissions from', + 'COPY_PERMISSIONS_TO' => 'Apply permissions to', + 'CREATE_ROLE' => 'Create role', 'CREATE_ROLE_FROM' => 'Use settings from…', 'CUSTOM' => 'Custom…', @@ -164,6 +171,7 @@ $lang = array_merge($lang, array( 'ROLE_FORUM_POLLS' => 'Standard Access + Polls', 'ROLE_FORUM_READONLY' => 'Read Only Access', 'ROLE_FORUM_STANDARD' => 'Standard Access', + 'ROLE_FORUM_NEW_MEMBER' => 'Newly registered User', 'ROLE_MOD_FULL' => 'Full Moderator', 'ROLE_MOD_QUEUE' => 'Queue Moderator', 'ROLE_MOD_SIMPLE' => 'Simple Moderator', @@ -173,6 +181,8 @@ $lang = array_merge($lang, array( 'ROLE_USER_NOAVATAR' => 'No Avatar', 'ROLE_USER_NOPM' => 'No Private Messages', 'ROLE_USER_STANDARD' => 'Standard Features', + 'ROLE_USER_NEW_MEMBER' => 'Newly registered User', + 'ROLE_DESCRIPTION_ADMIN_FORUM' => 'Can access the forum management and forum permission settings.', 'ROLE_DESCRIPTION_ADMIN_FULL' => 'Has access to all administrative functions of this board.
    Not recommended.', @@ -187,6 +197,7 @@ $lang = array_merge($lang, array( 'ROLE_DESCRIPTION_FORUM_POLLS' => 'Like Standard Access but can also create polls.', 'ROLE_DESCRIPTION_FORUM_READONLY' => 'Can read the forum, but cannot create new topics or reply to posts.', 'ROLE_DESCRIPTION_FORUM_STANDARD' => 'Can use most forum features including attachments and deleting own topics, but cannot lock own topics, and cannot create polls.', + 'ROLE_DESCRIPTION_FORUM_NEW_MEMBER' => 'A role for members of the special newly registered users group; contains NEVER permissions to lock features for new users.', 'ROLE_DESCRIPTION_MOD_FULL' => 'Can use all moderating features, including banning.', 'ROLE_DESCRIPTION_MOD_QUEUE' => 'Can use the Moderation Queue to validate and edit posts, but nothing else.', 'ROLE_DESCRIPTION_MOD_SIMPLE' => 'Can only use basic topic actions. Cannot send warnings or use moderation queue.', @@ -196,6 +207,7 @@ $lang = array_merge($lang, array( 'ROLE_DESCRIPTION_USER_NOAVATAR' => 'Has a limited feature set and is not allowed to use the Avatar feature.', 'ROLE_DESCRIPTION_USER_NOPM' => 'Has a limited feature set, and is not allowed to use Private Messages.', 'ROLE_DESCRIPTION_USER_STANDARD' => 'Can access most but not all user features. Cannot change user name or ignore the flood limit, for instance.', + 'ROLE_DESCRIPTION_USER_NEW_MEMBER' => 'A role for members of the special newly registered users group; contains NEVER permissions to lock features for new users.', 'ROLE_DESCRIPTION_EXPLAIN' => 'You are able to enter a short explanation of what the role is doing or for what it is meant for. The text you enter here will be displayed within the permissions screens too.', 'ROLE_DESCRIPTION_LONG' => 'The role description is too long, please limit it to 4000 characters.', @@ -241,7 +253,7 @@ $lang = array_merge($lang, array( 'TRACE_USER_GLOBAL_YES_TOTAL_NEVER' => 'The forum independent user permission evaluates to YES which overwrites the current local result NEVER. %sTrace global permission%s', 'TRACE_USER_GLOBAL_NEVER_TOTAL_KEPT' => 'The forum independent user permission evaluates to NEVER which doesn’t influence the local permission. %sTrace global permission%s', - 'TRACE_USER_FOUNDER' => 'The user has the founder type set, therefore admin permissions are set to YES by default.', + 'TRACE_USER_FOUNDER' => 'The user is a founder, therefore admin permissions are always set to YES.', 'TRACE_USER_KEPT' => 'The user’s permission is NO so the old total value is kept.', 'TRACE_USER_KEPT_LOCAL' => 'The user’s permission for this forum is NO so the old total value is kept.', 'TRACE_USER_NEVER_TOTAL_NEVER' => 'The user’s permission is set to NEVER and the total value is set to NEVER, so nothing is changed.', diff --git a/phpBB/language/en/acp/permissions_phpbb.php b/phpBB/language/en/acp/permissions_phpbb.php index c8ccc0e56a..945a675861 100644 --- a/phpBB/language/en/acp/permissions_phpbb.php +++ b/phpBB/language/en/acp/permissions_phpbb.php @@ -121,10 +121,10 @@ $lang = array_merge($lang, array( 'acl_u_pm_printpm' => array('lang' => 'Can print private messages', 'cat' => 'pm'), 'acl_u_pm_attach' => array('lang' => 'Can attach files in private messages', 'cat' => 'pm'), 'acl_u_pm_download' => array('lang' => 'Can download files in private messages', 'cat' => 'pm'), - 'acl_u_pm_bbcode' => array('lang' => 'Can post BBCode in private messages', 'cat' => 'pm'), - 'acl_u_pm_smilies' => array('lang' => 'Can post smilies in private messages', 'cat' => 'pm'), - 'acl_u_pm_img' => array('lang' => 'Can post images in private messages', 'cat' => 'pm'), - 'acl_u_pm_flash' => array('lang' => 'Can post Flash in private messages', 'cat' => 'pm'), + 'acl_u_pm_bbcode' => array('lang' => 'Can use BBCode in private messages', 'cat' => 'pm'), + 'acl_u_pm_smilies' => array('lang' => 'Can use smilies in private messages', 'cat' => 'pm'), + 'acl_u_pm_img' => array('lang' => 'Can use [img] BBCode tag in private messages', 'cat' => 'pm'), + 'acl_u_pm_flash' => array('lang' => 'Can use [flash] BBCode tag in private messages', 'cat' => 'pm'), 'acl_u_sendemail' => array('lang' => 'Can send e-mails', 'cat' => 'misc'), 'acl_u_sendim' => array('lang' => 'Can send instant messages', 'cat' => 'misc'), @@ -151,10 +151,10 @@ $lang = array_merge($lang, array( 'acl_f_attach' => array('lang' => 'Can attach files', 'cat' => 'content'), 'acl_f_download' => array('lang' => 'Can download files', 'cat' => 'content'), 'acl_f_sigs' => array('lang' => 'Can use signatures', 'cat' => 'content'), - 'acl_f_bbcode' => array('lang' => 'Can post BBCode', 'cat' => 'content'), - 'acl_f_smilies' => array('lang' => 'Can post smilies', 'cat' => 'content'), - 'acl_f_img' => array('lang' => 'Can post images', 'cat' => 'content'), - 'acl_f_flash' => array('lang' => 'Can post Flash', 'cat' => 'content'), + 'acl_f_bbcode' => array('lang' => 'Can use BBCode', 'cat' => 'content'), + 'acl_f_smilies' => array('lang' => 'Can use smilies', 'cat' => 'content'), + 'acl_f_img' => array('lang' => 'Can use [img] BBCode tag', 'cat' => 'content'), + 'acl_f_flash' => array('lang' => 'Can use [flash] BBCode tag', 'cat' => 'content'), 'acl_f_edit' => array('lang' => 'Can edit own posts', 'cat' => 'actions'), 'acl_f_delete' => array('lang' => 'Can delete own posts', 'cat' => 'actions'), diff --git a/phpBB/language/en/acp/posting.php b/phpBB/language/en/acp/posting.php index 01453b85ef..531e07f7ef 100644 --- a/phpBB/language/en/acp/posting.php +++ b/phpBB/language/en/acp/posting.php @@ -68,7 +68,7 @@ $lang = array_merge($lang, array( 'TOKEN' => 'Token', 'TOKENS' => 'Tokens', - 'TOKENS_EXPLAIN' => 'Tokens are placeholders for user input. The input will be validated only if it matches the corresponding definition. If needed, you can number them by adding a number as the last character between the braces, e.g. {TEXT1}, {TEXT2}.

    Within the HTML replacement you can also use any language string present in your language/ directory like this: {L_<STRINGNAME>} where <STRINGNAME> is the name of the translated string you want to add. For example, {L_WROTE} will be displayed as "wrote" or its translation according to user’s locale.

    Please note that only tokens listed below are able to be used within custom BBCodes.', + 'TOKENS_EXPLAIN' => 'Tokens are placeholders for user input. The input will be validated only if it matches the corresponding definition. If needed, you can number them by adding a number as the last character between the braces, e.g. {TEXT1}, {TEXT2}.

    Within the HTML replacement you can also use any language string present in your language/ directory like this: {L_<STRINGNAME>} where <STRINGNAME> is the name of the translated string you want to add. For example, {L_WROTE} will be displayed as “wrote†or its translation according to user’s locale.

    Please note that only tokens listed below are able to be used within custom BBCodes.', 'TOKEN_DEFINITION' => 'What can it be?', 'TOO_MANY_BBCODES' => 'You cannot create any more BBCodes. Please remove one or more BBCodes then try again.', @@ -78,7 +78,7 @@ $lang = array_merge($lang, array( 'IDENTIFIER' => 'Characters from the latin alphabet (A-Z), numbers, hyphen and underscore', 'NUMBER' => 'Any series of digits', 'EMAIL' => 'A valid e-mail address', - 'URL' => 'A valid URL using any protocol (http, ftp, etc… cannot be used for javascript exploits). If none is given, "http://" is prefixed to the string.', + 'URL' => 'A valid URL using any protocol (http, ftp, etc… cannot be used for javascript exploits). If none is given, “http://†is prefixed to the string.', 'LOCAL_URL' => 'A local URL. The URL must be relative to the topic page and cannot contain a server name or protocol.', 'COLOR' => 'A HTML colour, can be either in the numeric form #FF1234 or a CSS colour keyword such as fuchsia or InactiveBorder' ) @@ -180,6 +180,8 @@ $lang = array_merge($lang, array( 'SMILIES_URL' => 'Smiley image file', 'SMILIES_WIDTH' => 'Smiley width', + 'TOO_MANY_SMILIES' => 'Limit of %d smilies reached.', + 'WRONG_PAK_TYPE' => 'The specified package does not contain the appropriate data.', )); @@ -217,6 +219,7 @@ $lang = array_merge($lang, array( 'RANK_ADDED' => 'The rank was successfully added.', 'RANK_IMAGE' => 'Rank image', 'RANK_IMAGE_EXPLAIN' => 'Use this to define a small image associated with the rank. The path is relative to the root phpBB directory.', + 'RANK_IMAGE_IN_USE' => '(In use)', 'RANK_MINIMUM' => 'Minimum posts', 'RANK_REMOVED' => 'The rank was successfully deleted.', 'RANK_SPECIAL' => 'Set as special rank', diff --git a/phpBB/language/en/acp/profile.php b/phpBB/language/en/acp/profile.php index ef291585bc..a25dcd174b 100644 --- a/phpBB/language/en/acp/profile.php +++ b/phpBB/language/en/acp/profile.php @@ -66,6 +66,8 @@ $lang = array_merge($lang, array( 'DISPLAY_AT_PROFILE_EXPLAIN' => 'The user is able to change this profile field within the user control panel.', 'DISPLAY_AT_REGISTER' => 'Display on registration screen', 'DISPLAY_AT_REGISTER_EXPLAIN' => 'If this option is enabled, the field will be displayed on registration.', + 'DISPLAY_ON_VT' => 'Display on viewtopic screen', + 'DISPLAY_ON_VT_EXPLAIN' => 'If this option is enabled, the field will be displayed in the mini-profile on the topic screen.', 'DISPLAY_PROFILE_FIELD' => 'Publicly display profile field', 'DISPLAY_PROFILE_FIELD_EXPLAIN' => 'The profile field will be shown in all locations allowed within the load settings. Setting this to “no†will hide the field from topic pages, profiles and the memberlist.', 'DROPDOWN_ENTRIES_EXPLAIN' => 'Enter your options now, every option in one line.', diff --git a/phpBB/language/en/acp/prune.php b/phpBB/language/en/acp/prune.php index 31e14d62a1..8a06225102 100644 --- a/phpBB/language/en/acp/prune.php +++ b/phpBB/language/en/acp/prune.php @@ -37,23 +37,23 @@ if (empty($lang) || !is_array($lang)) // User pruning $lang = array_merge($lang, array( - 'ACP_PRUNE_USERS_EXPLAIN' => 'Here you can delete (or deactivate) users from your board. This can be done in a variety of ways; by post count, last activity, etc. Each of these criteria can be combined, i.e. you can prune users last active before 2002-01-01 with fewer than 10 posts. Alternatively you can enter a list of users directly into the text box, any criteria entered will be ignored. Take care with this facility! Once a user is deleted there is no way back.', + 'ACP_PRUNE_USERS_EXPLAIN' => 'This section allows you to delete or deactivate users on your board. Accounts can be filtered in a variety of ways; by post count, most recent activity, etc. Criteria may be combined to narrow down which accounts are affected. For example, you can prune users with fewer than 10 posts, who were also inactive after 2002-01-01. Alternatively, you may skip the criteria selection completely by entering a list of users (each on a separate line) into the text field. Take care with this facility! Once a user is deleted, there is no way to reverse the action.', 'DEACTIVATE_DELETE' => 'Deactivate or delete', - 'DEACTIVATE_DELETE_EXPLAIN' => 'Choose whether to deactivate users or delete them entirely, note there is no undo!', + 'DEACTIVATE_DELETE_EXPLAIN' => 'Choose whether to deactivate users or delete them entirely. Please note that deleted users cannot be restored!', 'DELETE_USERS' => 'Delete', 'DELETE_USER_POSTS' => 'Delete pruned user posts', 'DELETE_USER_POSTS_EXPLAIN' => 'Removes posts made by deleted users, has no effect if users are deactivated.', 'JOINED_EXPLAIN' => 'Enter a date in YYYY-MM-DD format.', - 'LAST_ACTIVE_EXPLAIN' => 'Enter a date in YYYY-MM-DD format.', + 'LAST_ACTIVE_EXPLAIN' => 'Enter a date in YYYY-MM-DD format. Enter 0000-00-00 to prune users who never logged in, Before and After conditions will be ignored.', 'PRUNE_USERS_LIST' => 'Users to be pruned', 'PRUNE_USERS_LIST_DELETE' => 'With the selected critera for pruning users the following accounts will be removed.', 'PRUNE_USERS_LIST_DEACTIVATE' => 'With the selected critera for pruning users the following accounts will be deactivated.', - 'SELECT_USERS_EXPLAIN' => 'Enter specific usernames here, they will be used in preference to the criteria above.', + 'SELECT_USERS_EXPLAIN' => 'Enter specific usernames here, they will be used in preference to the criteria above. Founders cannot be pruned.', 'USER_DEACTIVATE_SUCCESS' => 'The selected users have been deactivated successfully.', 'USER_DELETE_SUCCESS' => 'The selected users have been deleted successfully.', diff --git a/phpBB/language/en/acp/styles.php b/phpBB/language/en/acp/styles.php index eb742fd140..247d8a4140 100644 --- a/phpBB/language/en/acp/styles.php +++ b/phpBB/language/en/acp/styles.php @@ -392,6 +392,7 @@ $lang = array_merge($lang, array( 'TEMPLATE_LOCATION' => 'Store templates in', 'TEMPLATE_LOCATION_EXPLAIN' => 'Images are always stored on the filesystem.', 'TEMPLATE_NAME' => 'Template name', + 'TEMPLATE_FILE_NOT_WRITABLE'=> 'Unable to write to template file %s. Please check the permissions for the directory and the files.', 'TEMPLATE_REFRESHED' => 'Template refreshed successfully.', 'THEME_ADDED' => 'New theme added on filesystem.', diff --git a/phpBB/language/en/acp/users.php b/phpBB/language/en/acp/users.php index dc28032483..8d9bf0d486 100644 --- a/phpBB/language/en/acp/users.php +++ b/phpBB/language/en/acp/users.php @@ -77,6 +77,7 @@ $lang = array_merge($lang, array( 'MOVE_POSTS_EXPLAIN' => 'Please select the forum to which you wish to move all the posts this user has made.', 'NO_SPECIAL_RANK' => 'No special rank assigned', + 'NO_WARNINGS' => 'No warnings.', 'NOT_MANAGE_FOUNDER' => 'You tried to manage a user with founder status. Only founders are allowed to manage other founders.', 'QUICK_TOOLS' => 'Quick tools', @@ -102,21 +103,28 @@ $lang = array_merge($lang, array( 'USER_ADMIN_DEACTIVED' => 'User deactivated successfully.', 'USER_ADMIN_DEL_ATTACH' => 'Delete all attachments', 'USER_ADMIN_DEL_AVATAR' => 'Delete avatar', + 'USER_ADMIN_DEL_OUTBOX' => 'Empty PM outbox', 'USER_ADMIN_DEL_POSTS' => 'Delete all posts', 'USER_ADMIN_DEL_SIG' => 'Delete signature', 'USER_ADMIN_EXPLAIN' => 'Here you can change your users information and certain specific options.', 'USER_ADMIN_FORCE' => 'Force reactivation', + 'USER_ADMIN_LEAVE_NR' => 'Remove from Newly Registered', 'USER_ADMIN_MOVE_POSTS' => 'Move all posts', 'USER_ADMIN_SIG_REMOVED' => 'Successfully removed signature from user account.', 'USER_ATTACHMENTS_REMOVED' => 'Successfully removed all attachments made by this user.', + 'USER_AVATAR_NOT_ALLOWED' => 'The avatar cannot be displayed because avatars have been disallowed.', 'USER_AVATAR_UPDATED' => 'Successfully updated user avatars details.', + 'USER_AVATAR_TYPE_NOT_ALLOWED' => 'The current avatar cannot be displayed because its type has been disallowed.', 'USER_CUSTOM_PROFILE_FIELDS' => 'Custom profile fields', 'USER_DELETED' => 'User deleted successfully.', 'USER_GROUP_ADD' => 'Add user to group', 'USER_GROUP_NORMAL' => 'User defined groups user is a member of', 'USER_GROUP_PENDING' => 'Groups user is in pending mode', 'USER_GROUP_SPECIAL' => 'Pre-defined groups user is a member of', + 'USER_LIFTED_NR' => 'Successfully removed the user’s newly registered status.', 'USER_NO_ATTACHMENTS' => 'There are no attached files to display.', + 'USER_OUTBOX_EMPTIED' => 'Successfully emptied user’s private message outbox.', + 'USER_OUTBOX_EMPTY' => 'The user’s private message outbox was already empty.', 'USER_OVERVIEW_UPDATED' => 'User details updated.', 'USER_POSTS_DELETED' => 'Successfully removed all posts made by this user.', 'USER_POSTS_MOVED' => 'Successfully moved users posts to target forum.', @@ -126,6 +134,7 @@ $lang = array_merge($lang, array( 'USER_RANK' => 'User rank', 'USER_RANK_UPDATED' => 'User rank updated.', 'USER_SIG_UPDATED' => 'User signature successfully updated.', + 'USER_WARNING_LOG_DELETED' => 'No information available. Possibly the log entry has been deleted.', 'USER_TOOLS' => 'Basic tools', )); diff --git a/phpBB/language/en/captcha_qa.php b/phpBB/language/en/captcha_qa.php new file mode 100644 index 0000000000..1d443e995a --- /dev/null +++ b/phpBB/language/en/captcha_qa.php @@ -0,0 +1,63 @@ + 'Q&A CAPTCHA', + 'CONFIRM_QUESTION_EXPLAIN' => 'This question is a means of identifying and preventing automated submissions.', + 'CONFIRM_QUESTION_WRONG' => 'You have provided an invalid answer to the confirmation question.', + + 'QUESTION_ANSWERS' => 'Answers', + 'ANSWERS_EXPLAIN' => 'Please enter valid answers to the question, one per line.', + 'CONFIRM_QUESTION' => 'Question', + + 'ANSWER' => 'Answer', + 'EDIT_QUESTION' => 'Edit Question', + 'QUESTIONS' => 'Questions', + 'QUESTIONS_EXPLAIN' => 'During registration, users will be asked one of the questions specified here. To use this plugin, at least one question must be set in the default language. These questions should be easy for your target audience to answer, but beyond the ability of a bot capable of running a Google™ search. Using a large and regulary changed set of questions will yield the best results. Enable the strict setting if your question relies on punctuation or capitalisation.', + 'QUESTION_DELETED' => 'Question deleted', + 'QUESTION_LANG' => 'Language', + 'QUESTION_LANG_EXPLAIN' => 'The language that this question and its answers are written in.', + 'QUESTION_STRICT' => 'Strict check', + 'QUESTION_STRICT_EXPLAIN' => 'If enabled, capitalisation and whitespace will also be enforced.', + + 'QUESTION_TEXT' => 'Question', + 'QUESTION_TEXT_EXPLAIN' => 'The question that will be asked on registration.', + + 'QA_ERROR_MSG' => 'Please fill in all fields and enter at least one answer.', +)); + +?> \ No newline at end of file diff --git a/phpBB/language/en/captcha_recaptcha.php b/phpBB/language/en/captcha_recaptcha.php new file mode 100644 index 0000000000..897e8a4979 --- /dev/null +++ b/phpBB/language/en/captcha_recaptcha.php @@ -0,0 +1,52 @@ + 'en', + 'RECAPTCHA_NOT_AVAILABLE' => 'In order to use reCaptcha, you must create an account on reCaptcha.net.', + 'CAPTCHA_RECAPTCHA' => 'reCaptcha', + 'RECAPTCHA_INCORRECT' => 'The visual confirmation code you submitted was incorrect', + + 'RECAPTCHA_PUBLIC' => 'Public reCaptcha key', + 'RECAPTCHA_PUBLIC_EXPLAIN' => 'Your public reCaptcha key. Keys can be obtained on reCaptcha.net.', + 'RECAPTCHA_PRIVATE' => 'Private reCaptcha key', + 'RECAPTCHA_PRIVATE_EXPLAIN' => 'Your private reCaptcha key. Keys can be obtained on reCaptcha.net.', + + 'RECAPTCHA_EXPLAIN' => 'In an effort to prevent automatic submissions, we require that you enter both of the words displayed below into the text field underneath.', +)); + +?> \ No newline at end of file diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index 12510d5d5e..b97445f186 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -250,6 +250,7 @@ $lang = array_merge($lang, array( 'G_REGISTERED' => 'Registered users', 'G_REGISTERED_COPPA' => 'Registered COPPA users', 'G_GLOBAL_MODERATORS' => 'Global moderators', + 'G_NEWLY_REGISTERED' => 'Newly registered users', 'HIDDEN_USERS_ONLINE' => '%d hidden users online', 'HIDDEN_USERS_TOTAL' => '%d hidden', @@ -383,6 +384,8 @@ $lang = array_merge($lang, array( 'NO_ONLINE_USERS' => 'No registered users', 'NO_POSTS' => 'No posts', 'NO_POSTS_TIME_FRAME' => 'No posts exist inside this topic for the selected time frame.', + 'NO_FEED_ENABLED' => 'Feeds are not available on this board.', + 'NO_FEED' => 'The requested feed is not available.', 'NO_SUBJECT' => 'No subject specified', // Used for posts having no subject defined but displayed within management pages. 'NO_SUCH_SEARCH_MODULE' => 'The specified search backend doesn’t exist.', 'NO_SUPPORTED_AUTH_METHODS' => 'No supported authentication methods.', @@ -486,6 +489,8 @@ $lang = array_merge($lang, array( 'RETURN_PAGE' => '%sReturn to the previous page%s', 'RETURN_TOPIC' => '%sReturn to the topic last visited%s', 'RETURN_TO' => 'Return to', + 'FEED' => 'Feed', + 'FEED_NEWS' => 'News', 'RULES_ATTACH_CAN' => 'You can post attachments in this forum', 'RULES_ATTACH_CANNOT' => 'You cannot post attachments in this forum', 'RULES_DELETE_CAN' => 'You can delete your posts in this forum', @@ -517,6 +522,7 @@ $lang = array_merge($lang, array( 'SEARCH_SELF' => 'View your posts', 'SEARCH_TOPIC' => 'Search this topic…', 'SEARCH_UNANSWERED' => 'View unanswered posts', + 'SEARCH_UNREAD' => 'View unread posts', 'SECONDS' => 'Seconds', 'SELECT' => 'Select', 'SELECT_ALL_CODE' => 'Select all', @@ -535,6 +541,7 @@ $lang = array_merge($lang, array( 'SORT_JOINED' => 'Joined date', 'SORT_LOCATION' => 'Location', 'SORT_RANK' => 'Rank', + 'SORT_POSTS' => 'Posts', 'SORT_TOPIC_TITLE' => 'Topic title', 'SORT_USERNAME' => 'Username', 'SPLIT_TOPIC' => 'Split topic', @@ -598,6 +605,7 @@ $lang = array_merge($lang, array( 'TOPIC' => 'Topic', 'TOPICS' => 'Topics', + 'TOPICS_UNAPPROVED' => 'At least one topic in this forum has not been approved.', 'TOPIC_ICON' => 'Topic icon', 'TOPIC_LOCKED' => 'This topic is locked, you cannot edit posts or make further replies.', 'TOPIC_LOCKED_SHORT'=> 'Topic locked', @@ -644,6 +652,8 @@ $lang = array_merge($lang, array( 'USERS' => 'Users', 'USE_PERMISSIONS' => 'Test out user’s permissions', + 'USER_NEW_PERMISSION_DISALLOWED' => 'We are sorry, but you are not authorised to use this feature. You may have just registered here and may need to participate more to be able to use this feature.', + 'VARIANT_DATE_SEPARATOR' => ' / ', // Used in date format dropdown, eg: "Today, 13:37 / 01 Jan 2007, 13:37" ... to join a relative date with calendar date 'VIEWED' => 'Viewed', 'VIEWING_FAQ' => 'Viewing FAQ', diff --git a/phpBB/language/en/email/admin_welcome_inactive.txt b/phpBB/language/en/email/admin_welcome_inactive.txt index 746d13da7a..af3ac9ca87 100644 --- a/phpBB/language/en/email/admin_welcome_inactive.txt +++ b/phpBB/language/en/email/admin_welcome_inactive.txt @@ -6,14 +6,13 @@ Please keep this e-mail for your records. Your account information is as follows ---------------------------- Username: {USERNAME} -Password: {PASSWORD} Board URL: {U_BOARD} ---------------------------- -Your account is currently inactive, the administrator of the board will need to activate it before you can log in. You will receive another e-mail when this has occurred. +Your account is currently inactive and will need to be approved by an administrator before you can log in. Another email will be sent when this had occured. -Please do not forget your password as it has been encrypted in our database and we cannot retrieve it for you. However, should you forget your password you can request a new one which will be activated in the same way as this account. +Your password has been securely stored in our database and cannot be retrieved. In the event that it is forgotten, you will be able to reset it using the email address associated with your account. Thank you for registering. diff --git a/phpBB/language/en/email/coppa_resend_inactive.txt b/phpBB/language/en/email/coppa_resend_inactive.txt index 9d43ca4f85..c3e4af576d 100644 --- a/phpBB/language/en/email/coppa_resend_inactive.txt +++ b/phpBB/language/en/email/coppa_resend_inactive.txt @@ -2,9 +2,9 @@ Subject: Welcome to "{SITENAME}" {WELCOME_MSG} -In compliance with the COPPA your account is currently inactive. +In compliance with the COPPA, your account is currently inactive. -Please print this message out and have your parent or guardian sign and date it. Then fax it to: +Please print this message and have your parent or guardian sign and date it. Then fax it to: {FAX_INFO} @@ -33,9 +33,9 @@ Date: _______________ ------------------------------ CUT HERE ------------------------------ -Once the administrator has received the above form via fax or regular mail your account will be activated. +Once the administrator has received the above form via fax or regular mail, your account will be activated. -Please do not forget your password as it has been encrypted in our database and we cannot retrieve it for you. However, should you forget your password you can request a new one which will be activated in the same way as this account. +Your password has been securely stored in our database and cannot be retrieved. In the event that it is forgotten, you will be able to reset it using the email address associated with your account. Thank you for registering. diff --git a/phpBB/language/en/email/coppa_welcome_inactive.txt b/phpBB/language/en/email/coppa_welcome_inactive.txt index f079ddb838..c3e4af576d 100644 --- a/phpBB/language/en/email/coppa_welcome_inactive.txt +++ b/phpBB/language/en/email/coppa_welcome_inactive.txt @@ -2,9 +2,9 @@ Subject: Welcome to "{SITENAME}" {WELCOME_MSG} -In compliance with the COPPA your account is currently inactive. +In compliance with the COPPA, your account is currently inactive. -Please print this message out and have your parent or guardian sign and date it. Then fax it to: +Please print this message and have your parent or guardian sign and date it. Then fax it to: {FAX_INFO} @@ -16,7 +16,6 @@ OR mail it to: Permission to participate at "{SITENAME}" - {U_BOARD} Username: {USERNAME} -Password: {PASSWORD} E-mail: {EMAIL_ADDRESS} I HAVE REVIEWED THE INFORMATION PROVIDED BY MY CHILD AND HEREBY GRANT PERMISSION TO "{SITENAME}" TO STORE THIS INFORMATION. @@ -34,9 +33,9 @@ Date: _______________ ------------------------------ CUT HERE ------------------------------ -Once the administrator has received the above form via fax or regular mail your account will be activated. +Once the administrator has received the above form via fax or regular mail, your account will be activated. -Please do not forget your password as it has been encrypted in our database and we cannot retrieve it for you. However, should you forget your password you can request a new one which will be activated in the same way as this account. +Your password has been securely stored in our database and cannot be retrieved. In the event that it is forgotten, you will be able to reset it using the email address associated with your account. Thank you for registering. diff --git a/phpBB/language/en/email/installed.txt b/phpBB/language/en/email/installed.txt index 4d9286bd65..2aa03a7f33 100644 --- a/phpBB/language/en/email/installed.txt +++ b/phpBB/language/en/email/installed.txt @@ -4,17 +4,16 @@ Congratulations, You have successfully installed phpBB on your server. -This e-mail contains important information on your installation that you should keep safe. The password has been encrypted in the database and cannot be recovered, although you can request a new password should you lose this one. +This e-mail contains important information regarding your installation and should be kept for reference. Your password has been securely stored in our database and cannot be retrieved. In the event that it is forgotten, you will be able to reset it using the email address associated with your account. ---------------------------- Username: {USERNAME} -Password: {PASSWORD} Board URL: {U_BOARD} ---------------------------- -Useful information on your phpBB installation can be found in the docs folder of your installation and on phpBB.com's support page - http://www.phpbb.com/support/ +Useful information regarding the phpBB software can be found in the docs folder of your installation and on phpBB.com's support page - http://www.phpbb.com/support/ -In order to keep the board safe and secure, it is highly recommended that you keep current with software releases which can be easily done by subscribing to phpBB.com's mailing list, located at the above URL. +In order to keep your board safe and secure, we highly recommended keeping current with software releases. For your convenience, a mailing list is available at the page referenced above. {EMAIL_SIG} \ No newline at end of file diff --git a/phpBB/language/en/email/pm_report_closed.txt b/phpBB/language/en/email/pm_report_closed.txt new file mode 100644 index 0000000000..1b9f4a6658 --- /dev/null +++ b/phpBB/language/en/email/pm_report_closed.txt @@ -0,0 +1,8 @@ +Subject: Report closed - "{PM_SUBJECT}" + +Hello {USERNAME}, + +You are receiving this notification because the report you filed regarding the private message "{PM_SUBJECT}" at "{SITENAME}" has been tended to by a moderator or administrator. The report is now closed. If you have further questions, please contact {CLOSER_NAME} by private message. + + +{EMAIL_SIG} \ No newline at end of file diff --git a/phpBB/language/en/email/pm_report_deleted.txt b/phpBB/language/en/email/pm_report_deleted.txt new file mode 100644 index 0000000000..8cb7fdd6fa --- /dev/null +++ b/phpBB/language/en/email/pm_report_deleted.txt @@ -0,0 +1,8 @@ +Subject: Report deleted - "{PM_SUBJECT}" + +Hello {USERNAME}, + +You are receiving this notification because the report you filed regarding the post "{PM_SUBJECT}" at "{SITENAME}" was deleted by a moderator or administrator. + + +{EMAIL_SIG} \ No newline at end of file diff --git a/phpBB/language/en/email/user_reactivate_account.txt b/phpBB/language/en/email/user_reactivate_account.txt index b5639d0b7a..4ef7dd899a 100644 --- a/phpBB/language/en/email/user_reactivate_account.txt +++ b/phpBB/language/en/email/user_reactivate_account.txt @@ -9,7 +9,7 @@ Please keep this e-mail for your records. Your account information is as follows Username: {USERNAME} ---------------------------- -Your password has been encrypted in our database. Should you forget your password you can request a new one which will be activated in the same way as this account. +Your password has been securely stored in our database and cannot be retrieved. In the event that it is forgotten, you will be able to reset it using the email address associated with your account. Please visit the following link to reactivate your account: diff --git a/phpBB/language/en/email/user_remind_inactive.txt b/phpBB/language/en/email/user_remind_inactive.txt index 49dea02044..1ba28329f6 100644 --- a/phpBB/language/en/email/user_remind_inactive.txt +++ b/phpBB/language/en/email/user_remind_inactive.txt @@ -2,7 +2,7 @@ Subject: Inactive account reminder Hello {USERNAME}, -On {REGISTER_DATE} you registered a new account at "{SITENAME}". To date you have not activated this account which is a prerequisite for board login. For your convenience the activation link is repeated below. +This notification is a reminder that your account at "{SITENAME}", created on {REGISTER_DATE}, remains inactive. If you would like to activate this account, please visit the following link: {U_ACTIVATE} diff --git a/phpBB/language/en/email/user_resend_inactive.txt b/phpBB/language/en/email/user_resend_inactive.txt index 5635801b80..4638d6df63 100644 --- a/phpBB/language/en/email/user_resend_inactive.txt +++ b/phpBB/language/en/email/user_resend_inactive.txt @@ -8,9 +8,9 @@ Please keep this e-mail for your records. Your account information is as follows Username: {USERNAME} ---------------------------- -Your password has been encrypted in our database. Should you forget your password you can request a new one which will be activated in the same way as this account. +Your password has been securely stored in our database and cannot be retrieved. In the event that it is forgotten, you will be able to reset it using the email address associated with your account. -Your account is currently inactive. You cannot use it until you visit the following link: +Please visit the following link in order to activate your account: {U_ACTIVATE} diff --git a/phpBB/language/en/email/user_welcome.txt b/phpBB/language/en/email/user_welcome.txt index 6c3cee0b50..2648769dfd 100644 --- a/phpBB/language/en/email/user_welcome.txt +++ b/phpBB/language/en/email/user_welcome.txt @@ -6,12 +6,11 @@ Please keep this e-mail for your records. Your account information is as follows ---------------------------- Username: {USERNAME} -Password: {PASSWORD} Board URL: {U_BOARD} ---------------------------- -Please do not forget your password as it has been encrypted in our database and we cannot retrieve it for you. However, should you forget your password you can request a new one which will be activated in the same way as this account. +Your password has been securely stored in our database and cannot be retrieved. In the event that it is forgotten, you will be able to reset it using the email address associated with your account. Thank you for registering. diff --git a/phpBB/language/en/email/user_welcome_inactive.txt b/phpBB/language/en/email/user_welcome_inactive.txt index 4b6d96ddd8..1b72b1c5a8 100644 --- a/phpBB/language/en/email/user_welcome_inactive.txt +++ b/phpBB/language/en/email/user_welcome_inactive.txt @@ -6,16 +6,15 @@ Please keep this e-mail for your records. Your account information is as follows ---------------------------- Username: {USERNAME} -Password: {PASSWORD} Board URL: {U_BOARD} ---------------------------- -Your account is currently inactive. You cannot use it until you visit the following link: +Please visit the following link in order to activate your account: {U_ACTIVATE} -Please do not forget your password as it has been encrypted in our database and we cannot retrieve it for you. However, should you forget your password you can request a new one which will be activated in the same way as this account. +Your password has been securely stored in our database and cannot be retrieved. In the event that it is forgotten, you will be able to reset it using the email address associated with your account. Thank you for registering. diff --git a/phpBB/language/en/help_bbcode.php b/phpBB/language/en/help_bbcode.php index ed6fea96d3..df5f950e3e 100644 --- a/phpBB/language/en/help_bbcode.php +++ b/phpBB/language/en/help_bbcode.php @@ -78,6 +78,11 @@ $help = array( 0 => 'Creating an Ordered list', 1 => 'The second type of list, an ordered list, gives you control over what is output before each item. To create an ordered list you use [list=1][/list] to create a numbered list or alternatively [list=a][/list] for an alphabetical list. As with the unordered list, items are specified using [*]. For example:

    [list=1]
    [*]Go to the shops
    [*]Buy a new computer
    [*]Swear at computer when it crashes
    [/list]

    will generate the following:
    1. Go to the shops
    2. Buy a new computer
    3. Swear at computer when it crashes
    Whereas for an alphabetical list you would use:

    [list=a]
    [*]The first possible answer
    [*]The second possible answer
    [*]The third possible answer
    [/list]

    giving
    1. The first possible answer
    2. The second possible answer
    3. The third possible answer
    ' ), + // This block will switch the FAQ-Questions to the second template column + array( + 0 => '--', + 1 => '--' + ), array( 0 => '--', 1 => 'Creating Links' diff --git a/phpBB/language/en/help_faq.php b/phpBB/language/en/help_faq.php index 89ac845021..88b2cc273d 100644 --- a/phpBB/language/en/help_faq.php +++ b/phpBB/language/en/help_faq.php @@ -202,6 +202,11 @@ $help = array( 0 => 'What are topic icons?', 1 => 'Topic icons are author chosen images associated with posts to indicate their content. The ability to use topic icons depends on the permissions set by the board administrator.' ), + // This block will switch the FAQ-Questions to the second template column + array( + 0 => '--', + 1 => '--' + ), array( 0 => '--', 1 => 'User Levels and Groups' diff --git a/phpBB/language/en/install.php b/phpBB/language/en/install.php index d3fd8d5e26..b653d54318 100644 --- a/phpBB/language/en/install.php +++ b/phpBB/language/en/install.php @@ -133,6 +133,7 @@ $lang = array_merge($lang, array( 'DB_PASSWORD' => 'Database password', 'DB_PORT' => 'Database server port', 'DB_PORT_EXPLAIN' => 'Leave this blank unless you know the server operates on a non-standard port.', + 'DB_UPDATE_NOT_SUPPORTED' => 'We are sorry, but this script does not support updating from versions of phpBB prior to “%1$sâ€. The version you currently have installed is “%2$sâ€. Please update to a previous version before running this script. Assistance with this is available in the Support Forum on phpBB.com.', 'DB_USERNAME' => 'Database username', 'DB_TEST' => 'Test connection', 'DEFAULT_LANG' => 'Default board language', @@ -166,6 +167,9 @@ $lang = array_merge($lang, array( 'FILES_REQUIRED_EXPLAIN' => 'Required - In order to function correctly phpBB needs to be able to access or write to certain files or directories. If you see “Not Found†you need to create the relevant file or directory. If you see “Unwritable†you need to change the permissions on the file or directory to allow phpBB to write to it.', 'FILLING_TABLE' => 'Filling table %s', 'FILLING_TABLES' => 'Filling tables', + + 'FIREBIRD_DBMS_UPDATE_REQUIRED' => 'phpBB no longer supports Firebird/Interbase prior to Version 2.1. Please update your Firebird installation to at least 2.1.0 before proceeding with the update.', + 'FINAL_STEP' => 'Process final step', 'FORUM_ADDRESS' => 'Board address', 'FORUM_ADDRESS_EXPLAIN' => 'This is the URL of your former board, for example http://www.example.com/phpBB2/. If an address is entered here and not left empty every instance of this address will be replaced by your new board address within messages, private messages and signatures.', @@ -184,11 +188,11 @@ $lang = array_merge($lang, array( 'INITIAL_CONFIG_EXPLAIN' => 'Now that install has determined your server can run phpBB you need to supply some specific information. If you do not know how to connect to your database please contact your hosting provider (in the first instance) or use the phpBB support forums. When entering data please ensure you check it thoroughly before continuing.', 'INSTALL_CONGRATS' => 'Congratulations!', 'INSTALL_CONGRATS_EXPLAIN' => ' -

    You have now successfully installed phpBB %1$s. From here, you have two options as to what to do with your newly installed phpBB3:

    + You have successfully installed phpBB %1$s. Please proceed by choosing one of the following options:

    Convert an existing board to phpBB3

    -

    The phpBB Unified Convertor Framework supports the conversion of phpBB 2.0.x and other board systems to phpBB3. If you have an existing board that you wish to convert, please proceed on to the convertor.

    +

    The phpBB Unified Convertor Framework supports the conversion of phpBB 2.0.x and other board systems to phpBB3. If you have an existing board that you wish to convert, please proceed to the convertor.

    Go live with your phpBB3!

    -

    Clicking the button below will take you to your Administration Control Panel (ACP). Take some time to examine the options available to you. Remember that help is available online via the Documentation and the support forums, see the README for further information.

    Please now delete, move or rename the install directory before you use your board. If this directory is still present, only the Administration Control Panel (ACP) will be accessible.

    ', +

    Clicking the button below will take you to a form for submitting statistical data to phpBB in your Administration Control Panel (ACP). We would appreciate it if you could help us by sending that information. Afterwards you should take some time to examine the options available to you. Remember that help is available online via the Documentation, README and the Support Forums.

    Please delete, move or rename the install directory before using your board. While this directory exists, only the Administration Control Panel (ACP) will be accessible.', 'INSTALL_INTRO' => 'Welcome to Installation', 'INSTALL_INTRO_BODY' => 'With this option, it is possible to install phpBB3 onto your server.

    In order to proceed, you will need your database settings. If you do not know your database settings, please contact your host and ask for them. You will not be able to continue without them. You need:

    @@ -208,7 +212,7 @@ $lang = array_merge($lang, array(
  • MySQL 3.23 or above (MySQLi supported)
  • PostgreSQL 7.3+
  • SQLite 2.8.2+
  • -
  • Firebird 2.0+
  • +
  • Firebird 2.1+
  • MS SQL Server 2000 or above (directly or via ODBC)
  • Oracle
  • @@ -230,7 +234,7 @@ $lang = array_merge($lang, array( 'INST_ERR_DB_NO_MYSQLI' => 'The version of MySQL installed on this machine is incompatible with the “MySQL with MySQLi Extension†option you have selected. Please try the “MySQL†option instead.', 'INST_ERR_DB_NO_SQLITE' => 'The version of the SQLite extension you have installed is too old, it must be upgraded to at least 2.8.2.', 'INST_ERR_DB_NO_ORACLE' => 'The version of Oracle installed on this machine requires you to set the NLS_CHARACTERSET parameter to UTF8. Either upgrade your installation to 9.2+ or change the parameter.', - 'INST_ERR_DB_NO_FIREBIRD' => 'The version of Firebird installed on this machine is older than 2.0, please upgrade to a newer version.', + 'INST_ERR_DB_NO_FIREBIRD' => 'The version of Firebird installed on this machine is older than 2.1, please upgrade to a newer version.', 'INST_ERR_DB_NO_FIREBIRD_PS'=> 'The database you selected for Firebird has a page size less than 8192, it must be at least 8192.', 'INST_ERR_DB_NO_POSTGRES' => 'The database you have selected was not created in UNICODE or UTF8 encoding. Try installing with a database in UNICODE or UTF8 encoding.', 'INST_ERR_DB_NO_NAME' => 'No database name specified.', @@ -364,7 +368,7 @@ $lang = array_merge($lang, array( // Updater $lang = array_merge($lang, array( - 'ALL_FILES_UP_TO_DATE' => 'All files are up to date with the latest phpBB version. You should now login to your board and check if everything is working fine. Do not forget to delete, rename or move your install directory!', + 'ALL_FILES_UP_TO_DATE' => 'All files are up to date with the latest phpBB version. You should now login to your board and check if everything is working fine. Do not forget to delete, rename or move your install directory! Please send us updated information about your server and board configurations from the Send statistics module in your ACP.', 'ARCHIVE_FILE' => 'Source file within archive', 'BACK' => 'Back', @@ -466,7 +470,7 @@ $lang = array_merge($lang, array( 'NO_VISIBLE_CHANGES' => 'No visible changes', 'NOTICE' => 'Notice', 'NUM_CONFLICTS' => 'Number of conflicts', - 'NUMBER_OF_FILES_COLLECTED' => 'Currently differences of %1$d of %2$d files have been checked.
    Please wait until all files are checked.', + 'NUMBER_OF_FILES_COLLECTED' => 'Currently differences from %1$d of %2$d files have been checked.
    Please wait until all files are checked.', 'OLD_UPDATE_FILES' => 'Update files are out of date. The update files found are for updating from phpBB %1$s to phpBB %2$s but the latest version of phpBB is %3$s.', @@ -559,14 +563,15 @@ $lang = array_merge($lang, array( 'USER_ACTIVE' => 'Active user', 'USER_INACTIVE' => 'Inactive user', - 'VERSION_CHECK' => 'Version check', - 'VERSION_CHECK_EXPLAIN' => 'Checks to see if the version of phpBB you are currently running is up to date.', - 'VERSION_NOT_UP_TO_DATE' => 'Your version of phpBB is not up to date. Please continue the update process.', - 'VERSION_NOT_UP_TO_DATE_ACP'=> 'Your version of phpBB is not up to date.
    Below you will find a link to the release announcement for the latest version as well as instructions on how to perform the update.', - 'VERSION_UP_TO_DATE' => 'Your installation is up to date, no updates are available for your version of phpBB. You may want to continue anyway to perform a file validity check.', - 'VERSION_UP_TO_DATE_ACP' => 'Your installation is up to date, no updates are available for your version of phpBB. You do not need to update your installation.', - 'VIEWING_FILE_CONTENTS' => 'Viewing file contents', - 'VIEWING_FILE_DIFF' => 'Viewing file differences', + 'VERSION_CHECK' => 'Version check', + 'VERSION_CHECK_EXPLAIN' => 'Checks to see if your phpBB installation is up to date.', + 'VERSION_NOT_UP_TO_DATE' => 'Your phpBB installation is not up to date. Please continue the update process.', + 'VERSION_NOT_UP_TO_DATE_ACP' => 'Your phpBB installation is not up to date.
    Below is a link to the release announcement, which contains more information as well as instructions on updating.', + 'VERSION_NOT_UP_TO_DATE_TITLE' => 'Your phpBB installation is not up to date.', + 'VERSION_UP_TO_DATE' => 'Your phpBB installation is up to date. Although there are no updates available at this time, you may continue in order to perform a file validity check.', + 'VERSION_UP_TO_DATE_ACP' => 'Your phpBB installation is up to date. There are no updates available at this time.', + 'VIEWING_FILE_CONTENTS' => 'Viewing file contents', + 'VIEWING_FILE_DIFF' => 'Viewing file differences', 'WRONG_INFO_FILE_FORMAT' => 'Wrong info file format', )); diff --git a/phpBB/language/en/mcp.php b/phpBB/language/en/mcp.php index 93b694be77..ab03cdb0be 100644 --- a/phpBB/language/en/mcp.php +++ b/phpBB/language/en/mcp.php @@ -46,6 +46,7 @@ $lang = array_merge($lang, array( 'ALL_NOTES_DELETED' => 'Successfully removed all user notes.', 'ALL_REPORTS' => 'All reports', 'ALREADY_REPORTED' => 'This post has already been reported.', + 'ALREADY_REPORTED_PM' => 'This private message has already been reported.', 'ALREADY_WARNED' => 'A warning has already been issued for this post.', 'APPROVE' => 'Approve', 'APPROVE_POST' => 'Approve post', @@ -58,11 +59,19 @@ $lang = array_merge($lang, array( 'CANNOT_WARN_SELF' => 'You cannot warn yourself.', 'CAN_LEAVE_BLANK' => 'This can be left blank.', 'CHANGE_POSTER' => 'Change poster', + 'CLOSE_PM_REPORT' => 'Close PM report', + 'CLOSE_PM_REPORT_CONFIRM' => 'Are you sure you want to close the selected PM report?', + 'CLOSE_PM_REPORTS' => 'Close PM reports', + 'CLOSE_PM_REPORTS_CONFIRM' => 'Are you sure you want to close the selected PM reports?', 'CLOSE_REPORT' => 'Close report', 'CLOSE_REPORT_CONFIRM' => 'Are you sure you want to close the selected report?', 'CLOSE_REPORTS' => 'Close reports', 'CLOSE_REPORTS_CONFIRM' => 'Are you sure you want to close the selected reports?', + 'DELETE_PM_REPORT' => 'Delete PM report', + 'DELETE_PM_REPORT_CONFIRM' => 'Are you sure you want to delete the selected PM report?', + 'DELETE_PM_REPORTS' => 'Delete PM reports', + 'DELETE_PM_REPORTS_CONFIRM' => 'Are you sure you want to delete the selected PM reports?', 'DELETE_POSTS' => 'Delete posts', 'DELETE_POSTS_CONFIRM' => 'Are you sure you want to delete these posts?', 'DELETE_POST_CONFIRM' => 'Are you sure you want to delete this post?', @@ -106,6 +115,7 @@ $lang = array_merge($lang, array( 'LATEST_LOGS' => 'Latest 5 logged actions', 'LATEST_REPORTED' => 'Latest 5 reports', + 'LATEST_REPORTED_PMS' => 'Latest 5 PM reports', 'LATEST_UNAPPROVED' => 'Latest 5 posts awaiting approval', 'LATEST_WARNING_TIME' => 'Latest warning issued', 'LATEST_WARNINGS' => 'Latest 5 warnings', @@ -170,7 +180,14 @@ $lang = array_merge($lang, array( 'MCP_POST_REPORTS' => 'Reports issued on this post', - 'MCP_REPORTS' => 'Reported posts', + 'MCP_PM_REPORTS' => 'Reported PMs', + 'MCP_PM_REPORT_DETAILS' => 'PM Report details', + 'MCP_PM_REPORTS_CLOSED' => 'Closed PM reports', + 'MCP_PM_REPORTS_CLOSED_EXPLAIN' => 'This is a list of all reports about private messages which have previously been resolved.', + 'MCP_PM_REPORTS_OPEN' => 'Open PM reports', + 'MCP_PM_REPORTS_OPEN_EXPLAIN' => 'This is a list of all reported private messages which are still to be handled.', + + 'MCP_REPORTS' => 'Reported messages', 'MCP_REPORT_DETAILS' => 'Report details', 'MCP_REPORTS_CLOSED' => 'Closed reports', 'MCP_REPORTS_CLOSED_EXPLAIN' => 'This is a list of all reports about posts which have previously been resolved.', @@ -232,6 +249,13 @@ $lang = array_merge($lang, array( 'ONLY_TOPIC' => 'Only topic “%sâ€', 'OTHER_USERS' => 'Other users posting from this IP', + 'PM_REPORT_CLOSED_SUCCESS' => 'The selected PM report has been closed successfully.', + 'PM_REPORT_DELETED_SUCCESS' => 'The selected PM report has been deleted successfully.', + 'PM_REPORTED_SUCCESS' => 'This private message has been successfully reported.', + 'PM_REPORT_TOTAL' => 'In total there is 1 PM report to review.', + 'PM_REPORTS_TOTAL' => 'In total there are %d PM reports to review.', + 'PM_REPORTS_ZERO_TOTAL' => 'There are no PM reports to review.', + 'PM_REPORT_DETAILS' => 'Private message report details', 'POSTER' => 'Poster', 'POSTS_APPROVED_SUCCESS' => 'The selected posts have been approved.', 'POSTS_DELETED_SUCCESS' => 'The selected posts have been successfully removed from the database.', @@ -264,7 +288,7 @@ $lang = array_merge($lang, array( 'REPORT_DELETED_SUCCESS' => 'The selected report has been deleted successfully.', 'REPORT_DETAILS' => 'Report details', 'REPORT_MESSAGE' => 'Report this message', - 'REPORT_MESSAGE_EXPLAIN' => 'Use this form to report the selected message. Reporting should generally be used only if the message breaks forum rules.', + 'REPORT_MESSAGE_EXPLAIN' => 'Use this form to report the selected private message. Reporting should generally be used only if the message breaks forum rules. Reporting a private message will make its contents visible to all moderators.', 'REPORT_NOTIFY' => 'Notify me', 'REPORT_NOTIFY_EXPLAIN' => 'Informs you when your report is dealt with.', 'REPORT_POST_EXPLAIN' => 'Use this form to report the selected post to the forum moderators and board administrators. Reporting should generally be used only if the post breaks forum rules.', @@ -275,6 +299,7 @@ $lang = array_merge($lang, array( 'RETURN_MESSAGE' => '%sReturn to the message%s', 'RETURN_NEW_FORUM' => '%sGo to the new forum%s', 'RETURN_NEW_TOPIC' => '%sGo to the new topic%s', + 'RETURN_PM' => '%sReturn to the private message%s', 'RETURN_POST' => '%sReturn to the post%s', 'RETURN_QUEUE' => '%sReturn to the queue%s', 'RETURN_REPORTS' => '%sReturn to the reports%s', @@ -346,6 +371,7 @@ $lang = array_merge($lang, array( 'USER_WARNING_ADDED' => 'User warned successfully.', 'VIEW_DETAILS' => 'View details', + 'VIEW_PM' => 'View private message', 'VIEW_POST' => 'View post', 'WARNED_USERS' => 'Warned users', @@ -365,10 +391,10 @@ $lang = array_merge($lang, array( 'OTHER' => 'Other', ), 'DESCRIPTION' => array( - 'WAREZ' => 'The post contains links to illegal or pirated software.', - 'SPAM' => 'The reported post has the only purpose to advertise for a website or another product.', - 'OFF_TOPIC' => 'The reported post is off topic.', - 'OTHER' => 'The reported post does not fit into any other category, please use the further information field.', + 'WAREZ' => 'The message contains links to illegal or pirated software.', + 'SPAM' => 'The reported message has the only purpose to advertise for a website or another product.', + 'OFF_TOPIC' => 'The reported message is off topic.', + 'OTHER' => 'The reported message does not fit into any other category, please use the further information field.', ) ), )); diff --git a/phpBB/language/en/memberlist.php b/phpBB/language/en/memberlist.php index b5b8434776..e7a9c6b88d 100644 --- a/phpBB/language/en/memberlist.php +++ b/phpBB/language/en/memberlist.php @@ -81,7 +81,7 @@ $lang = array_merge($lang, array( 'IM_MESSAGE' => 'Your message', 'IM_MSNM' => 'Please note that you need Windows Messenger installed to use this.', 'IM_MSNM_BROWSER' => 'Your browser does not support this.', - 'IM_MSNM_CONNECT' => 'MSNM is not connected.\nYou have to connect to MSNM to continue.', + 'IM_MSNM_CONNECT' => 'MSNM is not connected.\nYou have to connect to MSNM to continue.', 'IM_NAME' => 'Your Name', 'IM_NO_DATA' => 'There is no suitable contact information for this user.', 'IM_NO_JABBER' => 'Sorry, direct messaging of Jabber users is not supported on this board. You will need a Jabber client installed on your system to contact the recipient above.', @@ -90,7 +90,7 @@ $lang = array_merge($lang, array( 'IM_SEND_MESSAGE' => 'Send message', 'IM_SENT_JABBER' => 'Your message to %1$s has been sent successfully.', 'IM_USER' => 'Send an instant message', - + 'LAST_ACTIVE' => 'Last active', 'LESS_THAN' => 'Less than', 'LIST_USER' => '1 user', @@ -134,6 +134,10 @@ $lang = array_merge($lang, array( 'USER_ADMIN' => 'Administrate user', 'USER_BAN' => 'Banning', 'USER_FORUM' => 'User statistics', + 'USER_LAST_REMINDED' => array( + 0 => 'No reminder sent at this time', + 1 => '%1$d reminder sent
    » %2$s', + ), 'USER_ONLINE' => 'Online', 'USER_PRESENCE' => 'Board presence', diff --git a/phpBB/language/en/posting.php b/phpBB/language/en/posting.php index b3acb7f290..8016a233fd 100644 --- a/phpBB/language/en/posting.php +++ b/phpBB/language/en/posting.php @@ -167,6 +167,8 @@ $lang = array_merge($lang, array( 'POST_ICON' => 'Post icon', 'POST_NORMAL' => 'Normal', 'POST_REVIEW' => 'Post review', + 'POST_REVIEW_EDIT' => 'Post review', + 'POST_REVIEW_EDIT_EXPLAIN' => 'This post has been altered by another user while you were editing it. You may wish to review the current version of this post and adjust your edits.', 'POST_REVIEW_EXPLAIN' => 'At least one new post has been made to this topic. You may wish to review your post in light of this.', 'POST_STORED' => 'This message has been posted successfully.', 'POST_STORED_MOD' => 'This message has been submitted successfully, but it will need to be approved by a moderator before it is publicly viewable.', @@ -184,10 +186,11 @@ $lang = array_merge($lang, array( 'SMILIES_ARE_ON' => 'Smilies are ON', 'STICKY_ANNOUNCE_TIME_LIMIT'=> 'Sticky/Announcement time limit', 'STICK_TOPIC_FOR' => 'Stick topic for', - 'STICK_TOPIC_FOR_EXPLAIN' => 'Enter 0 or leave blank for a never ending Sticky/Announcement.', + 'STICK_TOPIC_FOR_EXPLAIN' => 'Enter 0 or leave blank for a never ending Sticky/Announcement. Please note that this number is relative to the date of the post.', 'STYLES_TIP' => 'Tip: Styles can be applied quickly to selected text.', 'TOO_FEW_CHARS' => 'Your message contains too few characters.', + 'TOO_FEW_CHARS_LIMIT' => 'Your message contains %1$d characters. The minimum number of characters you need to enter is %2$d.', 'TOO_FEW_POLL_OPTIONS' => 'You must enter at least two poll options.', 'TOO_MANY_ATTACHMENTS' => 'Cannot add another attachment, %d is the maximum.', 'TOO_MANY_CHARS' => 'Your message contains too many characters.', diff --git a/phpBB/language/en/search.php b/phpBB/language/en/search.php index 4618a585b3..be92391a4e 100644 --- a/phpBB/language/en/search.php +++ b/phpBB/language/en/search.php @@ -53,6 +53,7 @@ $lang = array_merge($lang, array( 'JUMP_TO_POST' => 'Jump to post', 'LOGIN_EXPLAIN_EGOSEARCH' => 'The board requires you to be registered and logged in to view your own posts.', + 'LOGIN_EXPLAIN_UNREADSEARCH'=> 'The board requires you to be registered and logged in to view your unread posts.', 'MAX_NUM_SEARCH_KEYWORDS_REFINE' => 'You specified too many words to search for. Please do not enter more than %1$d words.', diff --git a/phpBB/language/en/ucp.php b/phpBB/language/en/ucp.php index 594a1dbe4f..4b79a4b6ca 100644 --- a/phpBB/language/en/ucp.php +++ b/phpBB/language/en/ucp.php @@ -79,6 +79,7 @@ $lang = array_merge($lang, array( 'ADD_NEW_RULE' => 'Add new rule', 'ADD_RULE' => 'Add rule', 'ADD_TO' => 'Add [To]', + 'ADD_USERS_UCP_EXPLAIN' => 'Here you can add new users to the group. You may select whether this group becomes the new default for the selected users. Please enter each username on a separate line.', 'ADMIN_EMAIL' => 'Administrators can e-mail me information', 'AGREE' => 'I agree to these terms', 'ALLOW_PM' => 'Allow users to send you private messages', @@ -92,7 +93,9 @@ $lang = array_merge($lang, array( 'AVATAR_FEATURES_DISABLED' => 'The avatar functionality is currently disabled.', 'AVATAR_GALLERY' => 'Local gallery', 'AVATAR_GENERAL_UPLOAD_ERROR' => 'Could not upload avatar to %s.', + 'AVATAR_NOT_ALLOWED' => 'Your avatar cannot be displayed because avatars have been disallowed.', 'AVATAR_PAGE' => 'Page', + 'AVATAR_TYPE_NOT_ALLOWED' => 'Your current avatar cannot be displayed because its type has been disallowed.', 'BACK_TO_DRAFTS' => 'Back to saved drafts', 'BACK_TO_LOGIN' => 'Back to login screen', @@ -197,6 +200,7 @@ $lang = array_merge($lang, array( 'FOES_UPDATED' => 'Your foes list has been updated successfully.', 'FOLDER_ADDED' => 'Folder successfully added.', 'FOLDER_MESSAGE_STATUS' => '%1$d from %2$d messages stored', + 'FOLDER_NAME_EMPTY' => 'You must enter a name for this folder.', 'FOLDER_NAME_EXIST' => 'Folder %s already exists.', 'FOLDER_OPTIONS' => 'Folder options', 'FOLDER_RENAMED' => 'Folder successfully renamed.', @@ -273,10 +277,12 @@ $lang = array_merge($lang, array( 'NOTIFY_METHOD_IM' => 'Jabber only', 'NOTIFY_ON_PM' => 'Notify me on new private messages', 'NOT_ADDED_FRIENDS_ANONYMOUS' => 'You cannot add the anonymous user to your friends list.', + 'NOT_ADDED_FRIENDS_BOTS' => 'You cannot add bots to your friends list.', 'NOT_ADDED_FRIENDS_FOES' => 'You cannot add users to your friends list who are on your foes list.', 'NOT_ADDED_FRIENDS_SELF' => 'You cannot add yourself to the friends list.', 'NOT_ADDED_FOES_MOD_ADMIN' => 'You cannot add administrators and moderators to your foes list.', 'NOT_ADDED_FOES_ANONYMOUS' => 'You cannot add the anonymous user to your foes list.', + 'NOT_ADDED_FOES_BOTS' => 'You cannot add bots to your foes list.', 'NOT_ADDED_FOES_FRIENDS' => 'You cannot add users to your foes list who are on your friends list.', 'NOT_ADDED_FOES_SELF' => 'You cannot add yourself to the foes list.', 'NOT_AGREE' => 'I do not agree to these terms', @@ -346,7 +352,7 @@ $lang = array_merge($lang, array( 'POST_EDIT_PM' => 'Edit message', 'POST_FORWARD_PM' => 'Forward message', 'POST_NEW_PM' => 'Compose message', - 'POST_PM_LOCKED' => 'Private messaging is locked', + 'POST_PM_LOCKED' => 'Private messaging is locked.', 'POST_PM_POST' => 'Quote post', 'POST_QUOTE_PM' => 'Quote message', 'POST_REPLY_PM' => 'Reply to message', @@ -368,6 +374,8 @@ $lang = array_merge($lang, array( 'RENAME' => 'Rename', 'RENAME_FOLDER' => 'Rename folder', 'REPLIED_MESSAGE' => 'Replied to message', + 'REPLY_TO_ALL' => 'Reply to sender and all recipients.', + 'REPORT_PM' => 'Report private message', 'RESIGN_SELECTED' => 'Resign selected', 'RETURN_FOLDER' => '%1$sReturn to previous folder%2$s', 'RETURN_UCP' => '%sReturn to the User Control Panel%s', @@ -417,7 +425,7 @@ $lang = array_merge($lang, array( 'UCP_MAIN_FRONT' => 'Front page', 'UCP_MAIN_SUBSCRIBED' => 'Manage subscriptions', - 'UCP_MSNM' => 'MSN Messenger', + 'UCP_MSNM' => 'WL/MSN Messenger', 'UCP_NO_ATTACHMENTS' => 'You have posted no files.', 'UCP_PREFS' => 'Board preferences', diff --git a/phpBB/language/en/viewtopic.php b/phpBB/language/en/viewtopic.php index 4252fa7542..3e1874f1ab 100644 --- a/phpBB/language/en/viewtopic.php +++ b/phpBB/language/en/viewtopic.php @@ -48,6 +48,7 @@ $lang = array_merge($lang, array( 'BUMP_TOPIC' => 'Bump topic', 'CODE' => 'Code', + 'COLLAPSE_QR' => 'Hide Quick Reply', 'DELETE_TOPIC' => 'Delete topic', 'DOWNLOAD_NOTICE' => 'You do not have the required permissions to view the files attached to this post.', @@ -59,7 +60,8 @@ $lang = array_merge($lang, array( 'FILE_NOT_FOUND_404' => 'The file %s does not exist.', 'FORK_TOPIC' => 'Copy topic', - + 'FULL_EDITOR' => 'Full Editor', + 'LINKAGE_FORBIDDEN' => 'You are not authorised to view, download or link from/to this site.', 'LOGIN_NOTIFY_TOPIC' => 'You have been notified about this topic, please login to view it.', 'LOGIN_VIEWTOPIC' => 'The board requires you to be registered and logged in to view this topic.', @@ -86,11 +88,13 @@ $lang = array_merge($lang, array( 'PRINT_TOPIC' => 'Print view', 'QUICK_MOD' => 'Quick-mod tools', + 'QUICKREPLY' => 'Quick Reply', 'QUOTE' => 'Quote', 'REPLY_TO_TOPIC' => 'Reply to topic', 'RETURN_POST' => '%sReturn to the post%s', + 'SHOW_QR' => 'Quick Reply', 'SUBMIT_VOTE' => 'Submit vote', 'TOTAL_VOTES' => 'Total votes', diff --git a/phpBB/mcp.php b/phpBB/mcp.php index 5f7aa3bd1f..48cd68500f 100644 --- a/phpBB/mcp.php +++ b/phpBB/mcp.php @@ -77,6 +77,7 @@ if ($mode == 'topic_logs') $post_id = request_var('p', 0); $topic_id = request_var('t', 0); $forum_id = request_var('f', 0); +$report_id = request_var('r', 0); $user_id = request_var('u', 0); $username = utf8_normalize_nfc(request_var('username', '', true)); @@ -211,11 +212,16 @@ if ($mode == '' || $mode == 'unapproved_topics' || $mode == 'unapproved_posts') $module->set_display('queue', 'approve_details', false); } -if ($mode == '' || $mode == 'reports' || $mode == 'reports_closed') +if ($mode == '' || $mode == 'reports' || $mode == 'reports_closed' || $mode == 'pm_reports' || $mode == 'pm_reports_closed' || $mode == 'pm_report_details') { $module->set_display('reports', 'report_details', false); } +if ($mode == '' || $mode == 'reports' || $mode == 'reports_closed' || $mode == 'pm_reports' || $mode == 'pm_reports_closed' || $mode == 'report_details') +{ + $module->set_display('pm_reports', 'pm_report_details', false); +} + if (!$topic_id) { $module->set_display('main', 'topic_view', false); @@ -323,13 +329,14 @@ function _module_reports_url($mode, &$module_row) function extra_url() { - global $forum_id, $topic_id, $post_id, $user_id; + global $forum_id, $topic_id, $post_id, $report_id, $user_id; $url_extra = ''; $url_extra .= ($forum_id) ? "&f=$forum_id" : ''; $url_extra .= ($topic_id) ? "&t=$topic_id" : ''; $url_extra .= ($post_id) ? "&p=$post_id" : ''; $url_extra .= ($user_id) ? "&u=$user_id" : ''; + $url_extra .= ($report_id) ? "&r=$report_id" : ''; return $url_extra; } @@ -563,10 +570,52 @@ function get_forum_data($forum_id, $acl_list = 'f_list', $read_tracking = false) return $rowset; } +/** +* Get simple pm data +*/ +function get_pm_data($pm_ids) +{ + global $db, $auth, $config, $user; + + $rowset = array(); + + if (!sizeof($pm_ids)) + { + return array(); + } + + $sql_array = array( + 'SELECT' => 'p.*, u.*', + + 'FROM' => array( + USERS_TABLE => 'u', + PRIVMSGS_TABLE => 'p', + ), + + 'WHERE' => $db->sql_in_set('p.msg_id', $pm_ids) . ' + AND u.user_id = p.author_id', + ); + + $sql = $db->sql_build_query('SELECT', $sql_array); + $result = $db->sql_query($sql); + unset($sql_array); + + while ($row = $db->sql_fetchrow($result)) + { + $rowset[$row['msg_id']] = $row; + } + $db->sql_freeresult($result); + + return $rowset; +} + /** * sorting in mcp * * @param string $where_sql should either be WHERE (default if ommited) or end with AND or OR +* +* $mode reports and reports_closed: the $where parameters uses aliases p for posts table and r for report table +* $mode unapproved_posts: the $where parameters uses aliases p for posts table and t for topic table */ function mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by_sql, &$sort_order_sql, &$total, $forum_id = 0, $topic_id = 0, $where_sql = 'WHERE') { @@ -614,12 +663,14 @@ function mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by_sql, $type = 'posts'; $default_key = 't'; $default_dir = 'd'; - $where_sql .= ($topic_id) ? ' topic_id = ' . $topic_id . ' AND' : ''; + $where_sql .= ($topic_id) ? ' p.topic_id = ' . $topic_id . ' AND' : ''; - $sql = 'SELECT COUNT(post_id) AS total - FROM ' . POSTS_TABLE . " - $where_sql " . $db->sql_in_set('forum_id', ($forum_id) ? array($forum_id) : array_intersect(get_forum_list('f_read'), get_forum_list('m_approve'))) . ' - AND post_approved = 0'; + $sql = 'SELECT COUNT(p.post_id) AS total + FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t + $where_sql " . $db->sql_in_set('p.forum_id', ($forum_id) ? array($forum_id) : array_intersect(get_forum_list('f_read'), get_forum_list('m_approve'))) . ' + AND p.post_approved = 0 + AND t.topic_id = p.topic_id + AND t.topic_first_post_id <> p.post_id'; if ($min_time) { @@ -643,40 +694,55 @@ function mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by_sql, } break; + case 'pm_reports': + case 'pm_reports_closed': case 'reports': case 'reports_closed': - $type = 'reports'; + $pm = (strpos($mode, 'pm_') === 0) ? true : false; + + $type = ($pm) ? 'pm_reports' : 'reports'; $default_key = 't'; $default_dir = 'd'; $limit_time_sql = ($min_time) ? "AND r.report_time >= $min_time" : ''; if ($topic_id) { - $where_sql .= ' p.topic_id = ' . $topic_id; + $where_sql .= ' p.topic_id = ' . $topic_id . ' AND '; } else if ($forum_id) { - $where_sql .= ' p.forum_id = ' . $forum_id; + $where_sql .= ' p.forum_id = ' . $forum_id . ' AND '; + } + else if (!$pm) + { + $where_sql .= ' ' . $db->sql_in_set('p.forum_id', get_forum_list(array('!f_read', '!m_report')), true, true) . ' AND '; + } + + if ($mode == 'reports' || $mode == 'pm_reports') + { + $where_sql .= ' r.report_closed = 0 AND '; } else { - $where_sql .= ' ' . $db->sql_in_set('p.forum_id', get_forum_list(array('!f_read', '!m_report')), true, true); + $where_sql .= ' r.report_closed = 1 AND '; } - if ($mode == 'reports') + if ($pm) { - $where_sql .= ' AND r.report_closed = 0'; + $sql = 'SELECT COUNT(r.report_id) AS total + FROM ' . REPORTS_TABLE . ' r, ' . PRIVMSGS_TABLE . " p + $where_sql r.post_id = 0 + AND p.msg_id = r.pm_id + $limit_time_sql"; } else { - $where_sql .= ' AND r.report_closed = 1'; + $sql = 'SELECT COUNT(r.report_id) AS total + FROM ' . REPORTS_TABLE . ' r, ' . POSTS_TABLE . " p + $where_sql r.pm_id = 0 + AND p.post_id = r.post_id + $limit_time_sql"; } - - $sql = 'SELECT COUNT(r.report_id) AS total - FROM ' . REPORTS_TABLE . ' r, ' . POSTS_TABLE . " p - $where_sql - AND p.post_id = r.post_id - $limit_time_sql"; break; case 'viewlogs': @@ -719,6 +785,12 @@ function mcp_sorting($mode, &$sort_days, &$sort_key, &$sort_dir, &$sort_by_sql, $sort_by_sql = array('a' => 'u.username_clean', 'r' => 'ru.username', 'p' => 'p.post_time', 't' => 'r.report_time', 's' => 'p.post_subject'); break; + case 'pm_reports': + $limit_days = array(0 => $user->lang['ALL_REPORTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); + $sort_by_text = array('a' => $user->lang['AUTHOR'], 'r' => $user->lang['REPORTER'], 'p' => $user->lang['POST_TIME'], 't' => $user->lang['REPORT_TIME'], 's' => $user->lang['SUBJECT']); + $sort_by_sql = array('a' => 'u.username_clean', 'r' => 'ru.username', 'p' => 'p.message_time', 't' => 'r.report_time', 's' => 'p.message_subject'); + break; + case 'logs': $limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); $sort_by_text = array('u' => $user->lang['SORT_USERNAME'], 't' => $user->lang['SORT_DATE'], 'i' => $user->lang['SORT_IP'], 'o' => $user->lang['SORT_ACTION']); diff --git a/phpBB/memberlist.php b/phpBB/memberlist.php index 298164be9e..11ff9e7685 100644 --- a/phpBB/memberlist.php +++ b/phpBB/memberlist.php @@ -500,7 +500,31 @@ switch ($mode) $poster_avatar = get_user_avatar($member['user_avatar'], $member['user_avatar_type'], $member['user_avatar_width'], $member['user_avatar_height']); - $template->assign_vars(show_profile($member)); + // We need to check if the modules 'zebra' ('friends' & 'foes' mode), 'notes' ('user_notes' mode) and 'warn' ('warn_user' mode) are accessible to decide if we can display appropriate links + $zebra_enabled = $friends_enabled = $foes_enabled = $user_notes_enabled = $warn_user_enabled = false; + + // Only check if the user is logged in + if ($user->data['is_registered']) + { + if (!class_exists('p_master')) + { + include($phpbb_root_path . 'includes/functions_module.' . $phpEx); + } + $module = new p_master(); + + $module->list_modules('ucp'); + $module->list_modules('mcp'); + + $user_notes_enabled = ($module->loaded('notes', 'user_notes')) ? true : false; + $warn_user_enabled = ($module->loaded('warn', 'warn_user')) ? true : false; + $zebra_enabled = ($module->loaded('zebra')) ? true : false; + $friends_enabled = ($module->loaded('zebra', 'friends')) ? true : false; + $foes_enabled = ($module->loaded('zebra', 'foes')) ? true : false; + + unset($module); + } + + $template->assign_vars(show_profile($member, $user_notes_enabled, $warn_user_enabled)); // Custom Profile Fields $profile_fields = array(); @@ -512,21 +536,6 @@ switch ($mode) $profile_fields = (isset($profile_fields[$user_id])) ? $cp->generate_profile_fields_template('show', false, $profile_fields[$user_id]) : array(); } - // We need to check if the module 'zebra' is accessible - $zebra_enabled = false; - - if ($user->data['user_id'] != $user_id && $user->data['is_registered']) - { - include_once($phpbb_root_path . 'includes/functions_module.' . $phpEx); - $module = new p_master(); - $module->list_modules('ucp'); - $module->set_active('zebra'); - - $zebra_enabled = ($module->active_module === false) ? false : true; - - unset($module); - } - // If the user has m_approve permission or a_user permission, then list then display unapproved posts if ($auth->acl_getf_global('m_approve') || $auth->acl_get('a_user')) { @@ -573,13 +582,15 @@ switch ($mode) 'U_USER_BAN' => ($auth->acl_get('m_ban') && $user_id != $user->data['user_id']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=ban&mode=user&u=' . $user_id, true, $user->session_id) : '', 'U_MCP_QUEUE' => ($auth->acl_getf_global('m_approve')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue', true, $user->session_id) : '', - 'U_SWITCH_PERMISSIONS' => ($auth->acl_get('a_switchperm') && $user->data['user_id'] != $user_id) ? append_sid("{$phpbb_root_path}ucp.$phpEx", "mode=switch_perm&u={$user_id}") : '', + 'U_SWITCH_PERMISSIONS' => ($auth->acl_get('a_switchperm') && $user->data['user_id'] != $user_id) ? append_sid("{$phpbb_root_path}ucp.$phpEx", "mode=switch_perm&u={$user_id}&hash=" . generate_link_hash('switchperm')) : '', + 'S_USER_NOTES' => ($user_notes_enabled) ? true : false, + 'S_WARN_USER' => ($warn_user_enabled) ? true : false, 'S_ZEBRA' => ($user->data['user_id'] != $user_id && $user->data['is_registered'] && $zebra_enabled) ? true : false, - 'U_ADD_FRIEND' => (!$friend) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&add=' . urlencode(htmlspecialchars_decode($member['username']))) : '', - 'U_ADD_FOE' => (!$foe) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&mode=foes&add=' . urlencode(htmlspecialchars_decode($member['username']))) : '', - 'U_REMOVE_FRIEND' => ($friend) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&remove=1&usernames[]=' . $user_id) : '', - 'U_REMOVE_FOE' => ($foe) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&remove=1&mode=foes&usernames[]=' . $user_id) : '', + 'U_ADD_FRIEND' => (!$friend && !$foe && $friends_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&add=' . urlencode(htmlspecialchars_decode($member['username']))) : '', + 'U_ADD_FOE' => (!$friend && !$foe && $foes_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&mode=foes&add=' . urlencode(htmlspecialchars_decode($member['username']))) : '', + 'U_REMOVE_FRIEND' => ($friend && $friends_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&remove=1&usernames[]=' . $user_id) : '', + 'U_REMOVE_FOE' => ($foe && $foes_enabled) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=zebra&remove=1&mode=foes&usernames[]=' . $user_id) : '', )); if (!empty($profile_fields['row'])) @@ -1238,7 +1249,7 @@ switch ($mode) 'joined' => array('joined', ''), 'active' => array('active', ''), 'count' => (request_var('count', '') !== '') ? array('count', 0) : array('count', ''), - 'ipdomain' => array('ip', ''), + 'ip' => array('ip', ''), 'first_char' => array('first_char', ''), ); @@ -1522,7 +1533,7 @@ switch ($mode) } // Output the page -page_header($page_title); +page_header($page_title, false); $template->set_filenames(array( 'body' => $template_html) @@ -1534,7 +1545,7 @@ page_footer(); /** * Prepare profile data */ -function show_profile($data) +function show_profile($data, $user_notes_enabled = false, $warn_user_enabled = false) { global $config, $auth, $template, $user, $phpEx, $phpbb_root_path; @@ -1620,9 +1631,11 @@ function show_profile($data) 'ICQ_STATUS_IMG' => (!empty($data['user_icq'])) ? '' : '', 'S_JABBER_ENABLED' => ($config['jab_enable']) ? true : false, + 'S_WARNINGS' => ($auth->acl_getf_global('m_') || $auth->acl_get('m_warn')) ? true : false, + 'U_SEARCH_USER' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$user_id&sr=posts") : '', - 'U_NOTES' => $auth->acl_getf_global('m_') ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $user_id, true, $user->session_id) : '', - 'U_WARN' => $auth->acl_get('m_warn') ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_user&u=' . $user_id, true, $user->session_id) : '', + 'U_NOTES' => ($user_notes_enabled && $auth->acl_getf_global('m_')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=notes&mode=user_notes&u=' . $user_id, true, $user->session_id) : '', + 'U_WARN' => ($warn_user_enabled && $auth->acl_get('m_warn')) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=warn&mode=warn_user&u=' . $user_id, true, $user->session_id) : '', 'U_PM' => ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && ($data['user_allow_pm'] || $auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_'))) ? append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm&mode=compose&u=' . $user_id) : '', 'U_EMAIL' => $email, 'U_WWW' => (!empty($data['user_website'])) ? $data['user_website'] : '', diff --git a/phpBB/posting.php b/phpBB/posting.php index c16c55111a..b241da2eab 100644 --- a/phpBB/posting.php +++ b/phpBB/posting.php @@ -39,12 +39,18 @@ $load = (isset($_POST['load'])) ? true : false; $delete = (isset($_POST['delete'])) ? true : false; $cancel = (isset($_POST['cancel']) && !isset($_POST['save'])) ? true : false; -$refresh = (isset($_POST['add_file']) || isset($_POST['delete_file']) || isset($_POST['cancel_unglobalise']) || $save || $load) ? true : false; +$refresh = (isset($_POST['add_file']) || isset($_POST['delete_file']) || isset($_POST['full_editor']) || isset($_POST['cancel_unglobalise']) || $save || $load) ? true : false; $mode = ($delete && !$preview && !$refresh && $submit) ? 'delete' : request_var('mode', ''); $error = $post_data = array(); $current_time = time(); +if ($config['enable_post_confirm'] && !$user->data['is_registered']) +{ + include($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); + $captcha =& phpbb_captcha_factory::get_instance($config['captcha_plugin']); + $captcha->init(CONFIRM_POST); +} // Was cancel pressed? If so then redirect to the appropriate page if ($cancel || ($current_time - $lastclick < 2 && $submit)) @@ -89,7 +95,8 @@ switch ($mode) FROM ' . TOPICS_TABLE . ' t, ' . FORUMS_TABLE . " f WHERE t.topic_id = $topic_id AND (f.forum_id = t.forum_id - OR f.forum_id = $forum_id)"; + OR f.forum_id = $forum_id) + AND t.topic_approved = 1"; break; case 'quote': @@ -118,7 +125,7 @@ switch ($mode) AND u.user_id = p.poster_id AND (f.forum_id = t.forum_id OR f.forum_id = $forum_id)" . - (($auth->acl_get('m_approve', $forum_id)) ? '' : 'AND p.post_approved = 1'); + (($auth->acl_get('m_approve', $forum_id) && $mode != 'quote') ? '' : 'AND p.post_approved = 1'); break; case 'smilies': @@ -364,6 +371,7 @@ else } $post_data['post_edit_locked'] = (isset($post_data['post_edit_locked'])) ? (int) $post_data['post_edit_locked'] : 0; +$post_data['post_subject_md5'] = (isset($post_data['post_subject']) && $mode == 'edit') ? md5($post_data['post_subject']) : ''; $post_data['post_subject'] = (in_array($mode, array('quote', 'edit'))) ? $post_data['post_subject'] : ((isset($post_data['topic_title'])) ? $post_data['topic_title'] : ''); $post_data['topic_time_limit'] = (isset($post_data['topic_time_limit'])) ? (($post_data['topic_time_limit']) ? (int) $post_data['topic_time_limit'] / 86400 : (int) $post_data['topic_time_limit']) : 0; $post_data['poll_length'] = (!empty($post_data['poll_length'])) ? (int) $post_data['poll_length'] / 86400 : 0; @@ -488,11 +496,11 @@ if ($mode == 'edit' && $post_data['bbcode_uid']) // HTML, BBCode, Smilies, Images and Flash status $bbcode_status = ($config['allow_bbcode'] && $auth->acl_get('f_bbcode', $forum_id)) ? true : false; -$smilies_status = ($bbcode_status && $config['allow_smilies'] && $auth->acl_get('f_smilies', $forum_id)) ? true : false; +$smilies_status = ($config['allow_smilies'] && $auth->acl_get('f_smilies', $forum_id)) ? true : false; $img_status = ($bbcode_status && $auth->acl_get('f_img', $forum_id)) ? true : false; $url_status = ($config['allow_post_links']) ? true : false; $flash_status = ($bbcode_status && $auth->acl_get('f_flash', $forum_id) && $config['allow_post_flash']) ? true : false; -$quote_status = ($auth->acl_get('f_reply', $forum_id)) ? true : false; +$quote_status = true; // Save Draft if ($save && $user->data['is_registered'] && $auth->acl_get('u_savedrafts') && ($mode == 'reply' || $mode == 'post' || $mode == 'quote')) @@ -538,6 +546,47 @@ if ($save && $user->data['is_registered'] && $auth->acl_get('u_savedrafts') && ( ) ); + $hidden_fields = array( + 'icon_id' => 0, + + 'disable_bbcode' => false, + 'disable_smilies' => false, + 'disable_magic_url' => false, + 'attach_sig' => true, + 'lock_topic' => false, + + 'topic_type' => POST_NORMAL, + 'topic_time_limit' => 0, + + 'poll_title' => '', + 'poll_option_text' => '', + 'poll_max_options' => 1, + 'poll_length' => 0, + 'poll_vote_change' => false, + ); + + foreach ($hidden_fields as $name => $default) + { + if (!isset($_POST[$name])) + { + // Don't include it, if its not available + unset($hidden_fields[$name]); + continue; + } + + if (is_bool($default)) + { + // Use the string representation + $hidden_fields[$name] = request_var($name, ''); + } + else + { + $hidden_fields[$name] = request_var($name, $default); + } + } + + $s_hidden_fields .= build_hidden_fields($hidden_fields); + confirm_box(false, 'SAVE_DRAFT', $s_hidden_fields); } } @@ -586,7 +635,6 @@ if ($load && ($mode == 'reply' || $mode == 'quote' || $mode == 'post') && $post_ load_drafts($topic_id, $forum_id); } -$solved_captcha = false; if ($submit || $preview || $refresh) { @@ -600,7 +648,11 @@ if ($submit || $preview || $refresh) $post_data['orig_topic_type'] = $post_data['topic_type']; $post_data['topic_type'] = request_var('topic_type', (($mode != 'post') ? (int) $post_data['topic_type'] : POST_NORMAL)); $post_data['topic_time_limit'] = request_var('topic_time_limit', (($mode != 'post') ? (int) $post_data['topic_time_limit'] : 0)); - $post_data['icon_id'] = request_var('icon', 0); + + if ($post_data['enable_icons'] && $auth->acl_get('f_icons', $forum_id)) + { + $post_data['icon_id'] = request_var('icon', (int) $post_data['icon_id']); + } $post_data['enable_bbcode'] = (!$bbcode_status || isset($_POST['disable_bbcode'])) ? false : true; $post_data['enable_smilies'] = (!$smilies_status || isset($_POST['disable_smilies'])) ? false : true; @@ -690,14 +742,70 @@ if ($submit || $preview || $refresh) } // Parse Attachments - before checksum is calculated - $message_parser->parse_attachments('fileupload', $mode, $forum_id, $submit, $preview, $refresh); + if ($mode == 'edit') + { + $message_parser->parse_attachments('fileupload', $mode, $forum_id, $submit, $preview, $refresh, false, $post_id, $topic_id); + if (sizeof($message_parser->attachment_data)) + { + // Update attachment indicators for post/topic having attachments now, as a precaution if the post does not get stored by submit + $sql = 'UPDATE ' . POSTS_TABLE . ' + SET post_attachment = 1 + WHERE post_id = ' . $post_id; + $db->sql_query($sql); + + $sql = 'UPDATE ' . TOPICS_TABLE . ' + SET topic_attachment = 1 + WHERE topic_id = ' . $topic_id; + $db->sql_query($sql); + } + } + else + { + $message_parser->parse_attachments('fileupload', $mode, $forum_id, $submit, $preview, $refresh); + } + // Grab md5 'checksum' of new message $message_md5 = md5($message_parser->message); + // If editing and checksum has changed we know the post was edited while we're editing + // Notify and show user the changed post + if ($mode == 'edit' && $post_data['forum_flags'] & FORUM_FLAG_POST_REVIEW) + { + $edit_post_message_checksum = request_var('edit_post_message_checksum', ''); + $edit_post_subject_checksum = request_var('edit_post_subject_checksum', ''); + + // $post_data['post_checksum'] is the checksum of the post submitted in the meantime + // $message_md5 is the checksum of the post we're about to submit + // $edit_post_message_checksum is the checksum of the post we're editing + // ... + + // We make sure nobody else made exactly the same change + // we're about to submit by also checking $message_md5 != $post_data['post_checksum'] + if (($edit_post_message_checksum !== '' && $edit_post_message_checksum != $post_data['post_checksum'] && $message_md5 != $post_data['post_checksum']) + || ($edit_post_subject_checksum !== '' && $edit_post_subject_checksum != $post_data['post_subject_md5'] && md5($post_data['post_subject']) != $post_data['post_subject_md5'])) + { + if (topic_review($topic_id, $forum_id, 'post_review_edit', $post_id)) + { + $template->assign_vars(array( + 'S_POST_REVIEW' => true, + + 'L_POST_REVIEW' => $user->lang['POST_REVIEW_EDIT'], + 'L_POST_REVIEW_EXPLAIN' => $user->lang['POST_REVIEW_EDIT_EXPLAIN'], + )); + } + + $submit = false; + $refresh = true; + } + } + // Check checksum ... don't re-parse message if the same $update_message = ($mode != 'edit' || $message_md5 != $post_data['post_checksum'] || $status_switch || strlen($post_data['bbcode_uid']) < BBCODE_UID_LEN) ? true : false; + // Also check if subject got updated... + $update_subject = $mode != 'edit' || ($post_data['post_subject_md5'] && $post_data['post_subject_md5'] != md5($post_data['post_subject'])); + // Parse message if ($update_message) { @@ -763,25 +871,15 @@ if ($submit || $preview || $refresh) if ($config['enable_post_confirm'] && !$user->data['is_registered'] && in_array($mode, array('quote', 'post', 'reply'))) { - $confirm_id = request_var('confirm_id', ''); - $confirm_code = request_var('confirm_code', ''); - - $sql = 'SELECT code - FROM ' . CONFIRM_TABLE . " - WHERE confirm_id = '" . $db->sql_escape($confirm_id) . "' - AND session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_POST; - $result = $db->sql_query($sql); - $confirm_row = $db->sql_fetchrow($result); - $db->sql_freeresult($result); - - if (empty($confirm_row['code']) || strcasecmp($confirm_row['code'], $confirm_code) !== 0) + $captcha_data = array( + 'message' => utf8_normalize_nfc(request_var('message', '', true)), + 'subject' => utf8_normalize_nfc(request_var('subject', '', true)), + 'username' => utf8_normalize_nfc(request_var('username', '', true)), + ); + $vc_response = $captcha->validate($captcha_data); + if ($vc_response) { - $error[] = $user->lang['CONFIRM_CODE_WRONG']; - } - else - { - $solved_captcha = true; + $error[] = $vc_response; } } @@ -1020,10 +1118,16 @@ if ($submit || $preview || $refresh) $data['topic_replies'] = $post_data['topic_replies']; } - $redirect_url = submit_post($mode, $post_data['post_subject'], $post_data['username'], $post_data['topic_type'], $poll, $data, $update_message); + // The last parameter tells submit_post if search indexer has to be run + $redirect_url = submit_post($mode, $post_data['post_subject'], $post_data['username'], $post_data['topic_type'], $poll, $data, $update_message, ($update_message || $update_subject) ? true : false); - // Check the permissions for post approval, as well as the queue trigger where users are put on approval with a post count lower than specified. Moderators are not affected. - if ((($config['enable_queue_trigger'] && $user->data['user_posts'] < $config['queue_trigger_posts']) || !$auth->acl_get('f_noapprove', $data['forum_id'])) && !$auth->acl_get('m_approve', $data['forum_id'])) + + if ($config['enable_post_confirm'] && !$user->data['is_registered'] && (isset($captcha) && $captcha->is_solved() === true) && ($mode == 'post' || $mode == 'reply' || $mode == 'quote')) + { + $captcha->reset(); + } + // Check the permissions for post approval. Moderators are not affected. + if (!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id'])) { meta_refresh(10, $redirect_url); $message = ($mode == 'edit') ? $user->lang['POST_EDITED_MOD'] : $user->lang['POST_STORED_MOD']; @@ -1150,7 +1254,26 @@ $message_parser->decode_message($post_data['bbcode_uid']); if ($mode == 'quote' && !$submit && !$preview && !$refresh) { - $message_parser->message = '[quote="' . $post_data['quote_username'] . '"]' . censor_text(trim($message_parser->message)) . "[/quote]\n"; + if ($config['allow_bbcode']) + { + $message_parser->message = '[quote="' . $post_data['quote_username'] . '"]' . censor_text(trim($message_parser->message)) . "[/quote]\n"; + } + else + { + $offset = 0; + $quote_string = "> "; + $message = censor_text(trim($message_parser->message)); + // see if we are nesting. It's easily tricked but should work for one level of nesting + if (strpos($message, ">") !== false) + { + $offset = 10; + } + $message = utf8_wordwrap($message, 75 + $offset, "\n"); + + $message = $quote_string . $message; + $message = str_replace("\n", "\n" . $quote_string, $message); + $message_parser->message = $post_data['quote_username'] . " " . $user->lang['WROTE'] . " :\n" . $message . "\n"; + } } if (($mode == 'reply' || $mode == 'quote') && !$submit && !$preview && !$refresh) @@ -1179,7 +1302,10 @@ if (sizeof($post_data['poll_options']) && $post_data['poll_title']) // Forum moderators? $moderators = array(); -get_moderators($moderators, $forum_id); +if ($config['load_moderators']) +{ + get_moderators($moderators, $forum_id); +} // Generate smiley listing generate_smilies('inline', $forum_id); @@ -1240,36 +1366,13 @@ generate_forum_nav($post_data); // Build Forum Rules generate_forum_rules($post_data); -if ($config['enable_post_confirm'] && !$user->data['is_registered'] && $solved_captcha === false && ($mode == 'post' || $mode == 'reply' || $mode == 'quote')) +// Posting uses is_solved for legacy reasons. Plugins have to use is_solved to force themselves to be displayed. +if ($config['enable_post_confirm'] && !$user->data['is_registered'] && (isset($captcha) && $captcha->is_solved() === false) && ($mode == 'post' || $mode == 'reply' || $mode == 'quote')) { - // Show confirm image - $sql = 'DELETE FROM ' . CONFIRM_TABLE . " - WHERE session_id = '" . $db->sql_escape($user->session_id) . "' - AND confirm_type = " . CONFIRM_POST; - $db->sql_query($sql); - - // Generate code - $code = gen_rand_string(mt_rand(CAPTCHA_MIN_CHARS, CAPTCHA_MAX_CHARS)); - $confirm_id = md5(unique_id($user->ip)); - $seed = hexdec(substr(unique_id(), 4, 10)); - - // compute $seed % 0x7fffffff - $seed -= 0x7fffffff * floor($seed / 0x7fffffff); - - $sql = 'INSERT INTO ' . CONFIRM_TABLE . ' ' . $db->sql_build_array('INSERT', array( - 'confirm_id' => (string) $confirm_id, - 'session_id' => (string) $user->session_id, - 'confirm_type' => (int) CONFIRM_POST, - 'code' => (string) $code, - 'seed' => (int) $seed) - ); - $db->sql_query($sql); $template->assign_vars(array( 'S_CONFIRM_CODE' => true, - 'CONFIRM_ID' => $confirm_id, - 'CONFIRM_IMAGE' => '', - 'L_POST_CONFIRM_EXPLAIN' => sprintf($user->lang['POST_CONFIRM_EXPLAIN'], '', ''), + 'CAPTCHA_TEMPLATE' => $captcha->get_template(), )); } @@ -1277,13 +1380,18 @@ $s_hidden_fields = ($mode == 'reply' || $mode == 'quote') ? ''; $s_hidden_fields .= ($draft_id || isset($_REQUEST['draft_loaded'])) ? '' : ''; -// Add the confirm id/code pair to the hidden fields, else an error is displayed on next submit/preview -if ($solved_captcha !== false) +if ($mode == 'edit') { $s_hidden_fields .= build_hidden_fields(array( - 'confirm_id' => request_var('confirm_id', ''), - 'confirm_code' => request_var('confirm_code', '')) - ); + 'edit_post_message_checksum' => $post_data['post_checksum'], + 'edit_post_subject_checksum' => $post_data['post_subject_md5'], + )); +} + +// Add the confirm id/code pair to the hidden fields, else an error is displayed on next submit/preview +if (isset($captcha) && $captcha->is_solved() !== false) +{ + $s_hidden_fields .= build_hidden_fields($captcha->get_hidden_fields()); } $form_enctype = (@ini_get('file_uploads') == '0' || strtolower(@ini_get('file_uploads')) == 'off' || !$config['allow_attachments'] || !$auth->acl_get('u_attach') || !$auth->acl_get('f_attach', $forum_id)) ? '' : ' enctype="multipart/form-data"'; @@ -1325,7 +1433,7 @@ $template->assign_vars(array( 'S_EDIT_REASON' => ($mode == 'edit' && $auth->acl_get('m_edit', $forum_id)) ? true : false, 'S_DISPLAY_USERNAME' => (!$user->data['is_registered'] || ($mode == 'edit' && $post_data['poster_id'] == ANONYMOUS)) ? true : false, 'S_SHOW_TOPIC_ICONS' => $s_topic_icons, - 'S_DELETE_ALLOWED' => ($mode == 'edit' && (($post_id == $post_data['topic_last_post_id'] && $post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id) && !$post_data['post_edit_locked'] && ($post_data['post_time'] > time() - ($config['edit_time'] * 60) || !$config['edit_time'])) || $auth->acl_get('m_delete', $forum_id))) ? true : false, + 'S_DELETE_ALLOWED' => ($mode == 'edit' && (($post_id == $post_data['topic_last_post_id'] && $post_data['poster_id'] == $user->data['user_id'] && $auth->acl_get('f_delete', $forum_id) && !$post_data['post_edit_locked'] && ($post_data['post_time'] > time() - ($config['delete_time'] * 60) || !$config['delete_time'])) || $auth->acl_get('m_delete', $forum_id))) ? true : false, 'S_BBCODE_ALLOWED' => $bbcode_status, 'S_BBCODE_CHECKED' => ($bbcode_checked) ? ' checked="checked"' : '', 'S_SMILIES_ALLOWED' => $smilies_status, @@ -1384,7 +1492,7 @@ $allowed = ($auth->acl_get('f_attach', $forum_id) && $auth->acl_get('u_attach') posting_gen_attachment_entry($attachment_data, $filename_data, $allowed); // Output page ... -page_header($page_title); +page_header($page_title, false); $template->set_filenames(array( 'body' => 'posting_body.html') @@ -1412,7 +1520,7 @@ function upload_popup($forum_style = 0) ($forum_style) ? $user->setup('posting', $forum_style) : $user->setup('posting'); - page_header($user->lang['PROGRESS_BAR']); + page_header($user->lang['PROGRESS_BAR'], false); $template->set_filenames(array( 'popup' => 'posting_progress_bar.html') @@ -1437,7 +1545,7 @@ function handle_post_delete($forum_id, $topic_id, $post_id, &$post_data) global $phpbb_root_path, $phpEx; // If moderator removing post or user itself removing post, present a confirmation screen - if ($auth->acl_get('m_delete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get('f_delete', $forum_id) && $post_id == $post_data['topic_last_post_id'] && !$post_data['post_edit_locked'] && ($post_data['post_time'] > time() - ($config['edit_time'] * 60) || !$config['edit_time']))) + if ($auth->acl_get('m_delete', $forum_id) || ($post_data['poster_id'] == $user->data['user_id'] && $user->data['is_registered'] && $auth->acl_get('f_delete', $forum_id) && $post_id == $post_data['topic_last_post_id'] && !$post_data['post_edit_locked'] && ($post_data['post_time'] > time() - ($config['delete_time'] * 60) || !$config['delete_time']))) { $s_hidden_fields = build_hidden_fields(array( 'p' => $post_id, @@ -1464,14 +1572,14 @@ function handle_post_delete($forum_id, $topic_id, $post_id, &$post_data) if ($next_post_id === false) { - add_log('mod', $forum_id, $topic_id, 'LOG_DELETE_TOPIC', $post_data['topic_title']); + add_log('mod', $forum_id, $topic_id, 'LOG_DELETE_TOPIC', $post_data['topic_title'], $post_data['username']); $meta_info = append_sid("{$phpbb_root_path}viewforum.$phpEx", "f=$forum_id"); $message = $user->lang['POST_DELETED']; } else { - add_log('mod', $forum_id, $topic_id, 'LOG_DELETE_POST', $post_data['post_subject']); + add_log('mod', $forum_id, $topic_id, 'LOG_DELETE_POST', $post_data['post_subject'], $post_data['username']); $meta_info = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&p=$next_post_id") . "#p$next_post_id"; $message = $user->lang['POST_DELETED'] . '

    ' . sprintf($user->lang['RETURN_TOPIC'], '', ''); diff --git a/phpBB/report.php b/phpBB/report.php index 03df91135d..db9c957ea8 100644 --- a/phpBB/report.php +++ b/phpBB/report.php @@ -24,18 +24,29 @@ $user->setup('mcp'); $forum_id = request_var('f', 0); $post_id = request_var('p', 0); +$pm_id = request_var('pm', 0); $reason_id = request_var('reason_id', 0); $report_text = utf8_normalize_nfc(request_var('report_text', '', true)); $user_notify = ($user->data['is_registered']) ? request_var('notify', 0) : false; $submit = (isset($_POST['submit'])) ? true : false; -if (!$post_id) +if (!$post_id && (!$pm_id || !$config['allow_pm_report'])) { trigger_error('NO_POST_SELECTED'); } -$redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&p=$post_id") . "#p$post_id"; +if ($post_id) +{ + $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&p=$post_id") . "#p$post_id"; + $pm_id = 0; +} +else +{ + $redirect_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=pm&mode=view&p=$pm_id"); + $post_id = 0; + $forum_id = 0; +} // Has the report been cancelled? if (isset($_POST['cancel'])) @@ -43,52 +54,79 @@ if (isset($_POST['cancel'])) redirect($redirect_url); } -// Grab all relevant data -$sql = 'SELECT t.*, p.* - FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t - WHERE p.post_id = $post_id - AND p.topic_id = t.topic_id"; -$result = $db->sql_query($sql); -$report_data = $db->sql_fetchrow($result); -$db->sql_freeresult($result); - -if (!$report_data) +if ($post_id) { - trigger_error('POST_NOT_EXIST'); -} + // Grab all relevant data + $sql = 'SELECT t.*, p.* + FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . " t + WHERE p.post_id = $post_id + AND p.topic_id = t.topic_id"; + $result = $db->sql_query($sql); + $report_data = $db->sql_fetchrow($result); + $db->sql_freeresult($result); -$forum_id = (int) ($report_data['forum_id']) ? $report_data['forum_id'] : $forum_id; -$topic_id = (int) $report_data['topic_id']; - -$sql = 'SELECT * - FROM ' . FORUMS_TABLE . ' - WHERE forum_id = ' . $forum_id; -$result = $db->sql_query($sql); -$forum_data = $db->sql_fetchrow($result); -$db->sql_freeresult($result); - -if (!$forum_data) -{ - trigger_error('FORUM_NOT_EXIST'); -} - -// Check required permissions -$acl_check_ary = array('f_list' => 'POST_NOT_EXIST', 'f_read' => 'USER_CANNOT_READ', 'f_report' => 'USER_CANNOT_REPORT'); - -foreach ($acl_check_ary as $acl => $error) -{ - if (!$auth->acl_get($acl, $forum_id)) + if (!$report_data) { - trigger_error($error); + trigger_error('POST_NOT_EXIST'); + } + + $forum_id = (int) ($report_data['forum_id']) ? $report_data['forum_id'] : $forum_id; + $topic_id = (int) $report_data['topic_id']; + + $sql = 'SELECT * + FROM ' . FORUMS_TABLE . ' + WHERE forum_id = ' . $forum_id; + $result = $db->sql_query($sql); + $forum_data = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if (!$forum_data) + { + trigger_error('FORUM_NOT_EXIST'); + } + + // Check required permissions + $acl_check_ary = array('f_list' => 'POST_NOT_EXIST', 'f_read' => 'USER_CANNOT_READ', 'f_report' => 'USER_CANNOT_REPORT'); + + foreach ($acl_check_ary as $acl => $error) + { + if (!$auth->acl_get($acl, $forum_id)) + { + trigger_error($error); + } + } + unset($acl_check_ary); + + if ($report_data['post_reported']) + { + $message = $user->lang['ALREADY_REPORTED']; + $message .= '

    ' . sprintf($user->lang['RETURN_TOPIC'], '', ''); + trigger_error($message); } } -unset($acl_check_ary); - -if ($report_data['post_reported']) +else { - $message = $user->lang['ALREADY_REPORTED']; - $message .= '

    ' . sprintf($user->lang['RETURN_TOPIC'], '', ''); - trigger_error($message); + // Grab all relevant data + $sql = 'SELECT p.*, pt.* + FROM ' . PRIVMSGS_TABLE . ' p, ' . PRIVMSGS_TO_TABLE . " pt + WHERE p.msg_id = $pm_id + AND p.msg_id = pt.msg_id + AND (p.author_id = " . $user->data['user_id'] . " OR pt.user_id = " . $user->data['user_id'] . ")"; + $result = $db->sql_query($sql); + $report_data = $db->sql_fetchrow($result); + $db->sql_freeresult($result); + + if (!$report_data) + { + trigger_error('PM_NOT_EXIST'); + } + + if ($report_data['message_reported']) + { + $message = $user->lang['ALREADY_REPORTED_PM']; + $message .= '

    ' . sprintf($user->lang['RETURN_PM'], '', ''); + trigger_error($message); + } } // Submit report? @@ -109,6 +147,7 @@ if ($submit && $reason_id) $sql_ary = array( 'reason_id' => (int) $reason_id, 'post_id' => $post_id, + 'pm_id' => $pm_id, 'user_id' => (int) $user->data['user_id'], 'user_notify' => (int) $user_notify, 'report_closed' => 0, @@ -120,26 +159,55 @@ if ($submit && $reason_id) $db->sql_query($sql); $report_id = $db->sql_nextid(); - if (!$report_data['post_reported']) + if ($post_id) { $sql = 'UPDATE ' . POSTS_TABLE . ' SET post_reported = 1 WHERE post_id = ' . $post_id; $db->sql_query($sql); - } - if (!$report_data['topic_reported']) + if (!$report_data['topic_reported']) + { + $sql = 'UPDATE ' . TOPICS_TABLE . ' + SET topic_reported = 1 + WHERE topic_id = ' . $report_data['topic_id'] . ' + OR topic_moved_id = ' . $report_data['topic_id']; + $db->sql_query($sql); + } + + $lang_return = $user->lang['RETURN_TOPIC']; + $lang_success = $user->lang['POST_REPORTED_SUCCESS']; + } + else { - $sql = 'UPDATE ' . TOPICS_TABLE . ' - SET topic_reported = 1 - WHERE topic_id = ' . $report_data['topic_id'] . ' - OR topic_moved_id = ' . $report_data['topic_id']; + $sql = 'UPDATE ' . PRIVMSGS_TABLE . ' + SET message_reported = 1 + WHERE msg_id = ' . $pm_id; $db->sql_query($sql); + + $sql_ary = array( + 'msg_id' => $pm_id, + 'user_id' => ANONYMOUS, + 'author_id' => (int) $report_data['author_id'], + 'pm_deleted' => 0, + 'pm_new' => 0, + 'pm_unread' => 0, + 'pm_replied' => 0, + 'pm_marked' => 0, + 'pm_forwarded' => 0, + 'folder_id' => PRIVMSGS_INBOX, + ); + + $sql = 'INSERT INTO ' . PRIVMSGS_TO_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary); + $db->sql_query($sql); + + $lang_return = $user->lang['RETURN_PM']; + $lang_success = $user->lang['PM_REPORTED_SUCCESS']; } meta_refresh(3, $redirect_url); - $message = $user->lang['POST_REPORTED_SUCCESS'] . '

    ' . sprintf($user->lang['RETURN_TOPIC'], '', ''); + $message = $lang_success . '

    ' . sprintf($lang_return, '', ''); trigger_error($message); } @@ -147,8 +215,9 @@ if ($submit && $reason_id) display_reasons($reason_id); $template->assign_vars(array( + 'S_REPORT_POST' => ($pm_id) ? false : true, 'REPORT_TEXT' => $report_text, - 'S_REPORT_ACTION' => append_sid("{$phpbb_root_path}report.$phpEx", 'f=' . $forum_id . '&p=' . $post_id), + 'S_REPORT_ACTION' => append_sid("{$phpbb_root_path}report.$phpEx", 'f=' . $forum_id . '&p=' . $post_id . '&pm=' . $pm_id), 'S_NOTIFY' => $user_notify, 'S_CAN_NOTIFY' => ($user->data['is_registered']) ? true : false) diff --git a/phpBB/search.php b/phpBB/search.php index cf2e8615c2..258297d088 100644 --- a/phpBB/search.php +++ b/phpBB/search.php @@ -95,8 +95,16 @@ if ($keywords || $author || $author_id || $search_id || $submit) } } + // search for unread posts needs user to be logged in + // if topics tracking for guests is disabled + if ($search_id == 'unreadposts' && !$config['load_anon_lastread'] && !$user->data['is_registered']) + { + login_box('', $user->lang['LOGIN_EXPLAIN_UNREADSEARCH']); + } + // If we are looking for authors get their ids $author_id_ary = array(); + $sql_author_match = ''; if ($author_id) { $author_id_ary[] = $author_id; @@ -113,7 +121,7 @@ if ($keywords || $author || $author_id || $search_id || $submit) $sql = 'SELECT user_id FROM ' . USERS_TABLE . " WHERE $sql_where - AND user_type IN (" . USER_NORMAL . ', ' . USER_FOUNDER . ')'; + AND user_type <> " . USER_IGNORE; $result = $db->sql_query_limit($sql, 100); while ($row = $db->sql_fetchrow($result)) @@ -122,6 +130,22 @@ if ($keywords || $author || $author_id || $search_id || $submit) } $db->sql_freeresult($result); + $sql_where = (strpos($author, '*') !== false) ? ' post_username ' . $db->sql_like_expression(str_replace('*', $db->any_char, utf8_clean_string($author))) : " post_username = '" . $db->sql_escape(utf8_clean_string($author)) . "'"; + + $sql = 'SELECT 1 as guest_post + FROM ' . POSTS_TABLE . " + WHERE $sql_where + AND poster_id = " . ANONYMOUS; + $result = $db->sql_query_limit($sql, 1); + $found_guest_post = $db->sql_fetchfield('guest_post'); + $db->sql_freeresult($result); + + if ($found_guest_post) + { + $author_id_ary[] = ANONYMOUS; + $sql_author_match = (strpos($author, '*') !== false) ? ' ' . $db->sql_like_expression(str_replace('*', $db->any_char, utf8_clean_string($author))) : " = '" . $db->sql_escape(utf8_clean_string($author)) . "'"; + } + if (!sizeof($author_id_ary)) { trigger_error('NO_SEARCH_RESULTS'); @@ -155,7 +179,7 @@ if ($keywords || $author || $author_id || $search_id || $submit) $not_in_fid = (sizeof($ex_fid_ary)) ? 'WHERE ' . $db->sql_in_set('f.forum_id', $ex_fid_ary, true) . " OR (f.forum_password <> '' AND fa.user_id <> " . (int) $user->data['user_id'] . ')' : ""; - $sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.right_id, f.forum_password, fa.user_id + $sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.right_id, f.forum_password, f.forum_flags, fa.user_id FROM ' . FORUMS_TABLE . ' f LEFT JOIN ' . FORUMS_ACCESS_TABLE . " fa ON (fa.forum_id = f.forum_id AND fa.session_id = '" . $db->sql_escape($user->session_id) . "') @@ -173,6 +197,13 @@ if ($keywords || $author || $author_id || $search_id || $submit) continue; } + // Exclude forums from active topics + if (!($row['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS) && ($search_id == 'active_topics')) + { + $ex_fid_ary[] = (int) $row['forum_id']; + continue; + } + if (sizeof($search_forum)) { if ($search_child) @@ -308,7 +339,6 @@ if ($keywords || $author || $author_id || $search_id || $submit) $last_post_time = ''; } - if ($sort_key == 'a') { $sort_join = USERS_TABLE . ' u, '; @@ -341,6 +371,34 @@ if ($keywords || $author || $author_id || $search_id || $submit) } break; + case 'unreadposts': + $l_search_title = $user->lang['SEARCH_UNREAD']; + // force sorting + $show_results = 'topics'; + $sort_key = 't'; + $sort_by_sql['t'] = 't.topic_last_post_time'; + $sql_sort = 'ORDER BY ' . $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC'); + + $sql_where = 'AND t.topic_moved_id = 0 + ' . str_replace(array('p.', 'post_'), array('t.', 'topic_'), $m_approve_fid_sql) . ' + ' . ((sizeof($ex_fid_ary)) ? 'AND ' . $db->sql_in_set('t.forum_id', $ex_fid_ary, true) : ''); + + gen_sort_selects($limit_days, $sort_by_text, $sort_days, $sort_key, $sort_dir, $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param); + $s_sort_key = $s_sort_dir = $u_sort_param = $s_limit_days = ''; + + $unread_list = array(); + $unread_list = get_unread_topics($user->data['user_id'], $sql_where, $sql_sort); + + if (!empty($unread_list)) + { + $sql = 'SELECT t.topic_id + FROM ' . TOPICS_TABLE . ' t + WHERE ' . $db->sql_in_set('t.topic_id', array_keys($unread_list)) . " + $sql_sort"; + $field = 'topic_id'; + } + break; + case 'newposts': $l_search_title = $user->lang['SEARCH_NEW']; // force sorting @@ -429,12 +487,12 @@ if ($keywords || $author || $author_id || $search_id || $submit) if (!empty($search->search_query)) { - $total_match_count = $search->keyword_search($show_results, $search_fields, $search_terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_id_ary, $id_ary, $start, $per_page); + $total_match_count = $search->keyword_search($show_results, $search_fields, $search_terms, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_id_ary, $sql_author_match, $id_ary, $start, $per_page); } else if (sizeof($author_id_ary)) { $firstpost_only = ($search_fields === 'firstpost' || $search_fields == 'titleonly') ? true : false; - $total_match_count = $search->author_search($show_results, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_id_ary, $id_ary, $start, $per_page); + $total_match_count = $search->author_search($show_results, $firstpost_only, $sort_by_sql, $sort_key, $sort_dir, $sort_days, $ex_fid_ary, $m_approve_fid_ary, $topic_id, $author_id_ary, $sql_author_match, $id_ary, $start, $per_page); } // For some searches we need to print out the "no results" page directly to allow re-sorting/refining the search options. @@ -484,12 +542,12 @@ if ($keywords || $author || $author_id || $search_id || $submit) $hilit = (strspn($hilit, '*') === strlen($hilit)) ? '' : $hilit; $u_hilit = urlencode(htmlspecialchars_decode(str_replace('|', ' ', $hilit))); - $u_show_results = ($show_results != 'posts') ? '&sr=' . $show_results : ''; + $u_show_results = '&sr=' . $show_results; $u_search_forum = implode('&fid%5B%5D=', $search_forum); $u_search = append_sid("{$phpbb_root_path}search.$phpEx", $u_sort_param . $u_show_results); $u_search .= ($search_id) ? '&search_id=' . $search_id : ''; - $u_search .= ($u_hilit) ? '&keywords=' . urlencode(htmlspecialchars_decode($search->search_query)) : ''; + $u_search .= ($u_hilit) ? '&keywords=' . urlencode(htmlspecialchars_decode($keywords)) : ''; $u_search .= ($search_terms != 'all') ? '&terms=' . $search_terms : ''; $u_search .= ($topic_id) ? '&t=' . $topic_id : ''; $u_search .= ($author) ? '&author=' . urlencode(htmlspecialchars_decode($author)) : ''; @@ -945,7 +1003,6 @@ if ($keywords || $author || $author_id || $search_id || $submit) page_footer(); } - // Search forum $s_forums = ''; $sql = 'SELECT f.forum_id, f.forum_name, f.parent_id, f.forum_type, f.left_id, f.right_id, f.forum_password, f.enable_indexing, fa.user_id diff --git a/phpBB/style.php b/phpBB/style.php index 78fd2a91b4..0b4c3d0d41 100644 --- a/phpBB/style.php +++ b/phpBB/style.php @@ -91,8 +91,9 @@ if ($id) $recompile = $config['load_tplcompile']; if (!$user) { - $id = $config['default_style']; - $recompile = false; + $id = ($id) ? $id : $config['default_style']; +// Commented out because calls do not always include the SID anymore +// $recompile = false; $user = array('user_id' => ANONYMOUS); } diff --git a/phpBB/styles/prosilver/imageset/imageset.cfg b/phpBB/styles/prosilver/imageset/imageset.cfg index 64b7f632c9..c838dffd03 100644 --- a/phpBB/styles/prosilver/imageset/imageset.cfg +++ b/phpBB/styles/prosilver/imageset/imageset.cfg @@ -19,7 +19,7 @@ # General Information about this style name = prosilver copyright = © phpBB Group, 2007 -version = 3.0.5 +version = 3.0.6 # Images img_site_logo = site_logo.gif*52*139 diff --git a/phpBB/styles/prosilver/style.cfg b/phpBB/styles/prosilver/style.cfg index 7be43fb4fa..219106e9b6 100644 --- a/phpBB/styles/prosilver/style.cfg +++ b/phpBB/styles/prosilver/style.cfg @@ -19,4 +19,4 @@ # General Information about this style name = prosilver copyright = © phpBB Group, 2007 -version = 3.0.5 \ No newline at end of file +version = 3.0.6 \ No newline at end of file diff --git a/phpBB/styles/prosilver/template/captcha_default.html b/phpBB/styles/prosilver/template/captcha_default.html new file mode 100644 index 0000000000..bccf231251 --- /dev/null +++ b/phpBB/styles/prosilver/template/captcha_default.html @@ -0,0 +1,24 @@ + +
    +
    + +

    {L_CONFIRMATION}

    +

    {L_CONFIRM_EXPLAIN}

    + +
    + + +
    +
    +
    {L_CONFIRM_CODE}
    +
    + +
    +
    {L_CONFIRM_CODE_EXPLAIN}
    +
    + + +
    +
    +
    + diff --git a/phpBB/styles/prosilver/template/captcha_qa.html b/phpBB/styles/prosilver/template/captcha_qa.html new file mode 100644 index 0000000000..0b18ada3bb --- /dev/null +++ b/phpBB/styles/prosilver/template/captcha_qa.html @@ -0,0 +1,21 @@ + +
    +
    + +

    {L_CONFIRMATION}

    +
    + + +
    +

    {L_CONFIRM_QUESTION_EXPLAIN}
    +
    + + +
    +
    + + +
    +
    +
    + diff --git a/phpBB/styles/prosilver/template/captcha_recaptcha.html b/phpBB/styles/prosilver/template/captcha_recaptcha.html new file mode 100644 index 0000000000..5ce19b20ec --- /dev/null +++ b/phpBB/styles/prosilver/template/captcha_recaptcha.html @@ -0,0 +1,43 @@ + +
    +
    + +

    {L_CONFIRMATION}

    +

    {L_CONFIRM_EXPLAIN}

    + +
    + + + +
    +
    :
    {L_RECAPTCHA_EXPLAIN}
    +
    + + + + + +
    +
    + +{L_RECAPTCHA_NOT_AVAILABLE} + + + +
    +
    +
    + diff --git a/phpBB/styles/prosilver/template/drafts.html b/phpBB/styles/prosilver/template/drafts.html index 838569ebf6..dea3bb414e 100644 --- a/phpBB/styles/prosilver/template/drafts.html +++ b/phpBB/styles/prosilver/template/drafts.html @@ -10,7 +10,7 @@ -
    +
      @@ -21,7 +21,7 @@
    -
      +
      • diff --git a/phpBB/styles/prosilver/template/editor.js b/phpBB/styles/prosilver/template/editor.js index 9610cf91d1..1699f783d5 100644 --- a/phpBB/styles/prosilver/template/editor.js +++ b/phpBB/styles/prosilver/template/editor.js @@ -7,6 +7,7 @@ var imageTag = false; var theSelection = false; +var bbcodeEnabled = true; // Check for Browser & Platform for PC & IE specific bits // More details from: http://www.mozilla.org/docs/web-developer/sniffer/browser_type.html var clientPC = navigator.userAgent.toLowerCase(); // Get client info @@ -14,7 +15,6 @@ var clientVer = parseInt(navigator.appVersion); // Get browser version var is_ie = ((clientPC.indexOf('msie') != -1) && (clientPC.indexOf('opera') == -1)); var is_win = ((clientPC.indexOf('win') != -1) || (clientPC.indexOf('16bit') != -1)); - var baseHeight; /** @@ -250,18 +250,65 @@ function addquote(post_id, username) if (theSelection) { - insert_text('[quote="' + username + '"]' + theSelection + '[/quote]'); + if (bbcodeEnabled) + { + insert_text('[quote="' + username + '"]' + theSelection + '[/quote]'); + } + else + { + var lines = split_lines(theSelection); + for (i = 0; i < lines.length; i++) + { + insert_text('> ' + lines[i] + '\n') + } + } } return; } +function split_lines(text) +{ + var lines = text.split('\n'); + var splitLines = new Array(); + var j = 0; + for(i = 0; i < lines.length; i++) + { + if (lines[i].length <= 80) + { + splitLines[j] = lines[i]; + j++; + } + else + { + var line = lines[i]; + do + { + var splitAt = line.indexOf(' ', 80); + + if (splitAt == -1) + { + splitLines[j] = line; + j++ + } + else + { + splitLines[j] = line.substring(0, splitAt); + line = line.substring(splitAt); + j++; + } + } + while(splitAt != -1) + } + } + return splitLines; +} /** * From http://www.massless.org/mozedit/ */ function mozWrap(txtarea, open, close) { - var selLength = txtarea.textLength; + var selLength = (typeof(txtarea.textLength) == 'undefined') ? txtarea.value.length : txtarea.textLength; var selStart = txtarea.selectionStart; var selEnd = txtarea.selectionEnd; var scrollTop = txtarea.scrollTop; diff --git a/phpBB/styles/prosilver/template/faq_body.html b/phpBB/styles/prosilver/template/faq_body.html index 78c2fc11b7..36d677a505 100644 --- a/phpBB/styles/prosilver/template/faq_body.html +++ b/phpBB/styles/prosilver/template/faq_body.html @@ -7,7 +7,7 @@
        - +
        diff --git a/phpBB/styles/prosilver/template/forum_fn.js b/phpBB/styles/prosilver/template/forum_fn.js index c1b86bd064..11e4315e2a 100644 --- a/phpBB/styles/prosilver/template/forum_fn.js +++ b/phpBB/styles/prosilver/template/forum_fn.js @@ -268,3 +268,136 @@ function play_qt_file(obj) obj.SetControllerVisible(true); obj.Play(); } + +/** +* Check if the nodeName of elem is name +* @author jQuery +*/ +function is_node_name(elem, name) +{ + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); +} + +/** +* Check if elem is in array, return position +* @author jQuery +*/ +function is_in_array(elem, array) +{ + for (var i = 0, length = array.length; i < length; i++) + // === is correct (IE) + if (array[i] === elem) + return i; + + return -1; +} + +/** +* Find Element, type and class in tree +* Not used, but may come in handy for those not using JQuery +* @author jQuery.find, Meik Sievertsen +*/ +function find_in_tree(node, tag, type, class_name) +{ + var result, element, i = 0, length = node.childNodes.length; + + for (element = node.childNodes[0]; i < length; element = node.childNodes[++i]) + { + if (!element || element.nodeType != 1) continue; + + if ((!tag || is_node_name(element, tag)) && (!type || element.type == type) && (!class_name || is_in_array(class_name, (element.className || element).toString().split(/\s+/)) > -1)) + { + return element; + } + + if (element.childNodes.length) + result = find_in_tree(element, tag, type, class_name); + + if (result) return result; + } +} + +/** +* Usually used for onkeypress event, to submit a form on enter +*/ +function submit_default_button(event, selector, class_name) +{ + // Add which for key events + if (!event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode)) + event.which = event.charCode || event.keyCode; + + // Keycode is not return, then return. ;) + if (event.which != 13) + return true; + + var current = selector['parentNode']; + + // Search parent form element + while (current && (!current.nodeName || current.nodeType != 1 || !is_node_name(current, 'form')) && current != document) + current = current['parentNode']; + + // Find the input submit button with the class name + //current = find_in_tree(current, 'input', 'submit', class_name); + var input_tags = current.getElementsByTagName('input'); + current = false; + + for (var i = 0, element = input_tags[0]; i < input_tags.length; element = input_tags[++i]) + { + if (element.type == 'submit' && is_in_array(class_name, (element.className || element).toString().split(/\s+/)) > -1) + current = element; + } + + if (!current) + return true; + + // Submit form + current.focus(); + current.click(); + return false; +} + +/** +* Apply onkeypress event for forcing default submit button on ENTER key press +* The jQuery snippet used is based on http://greatwebguy.com/programming/dom/default-html-button-submit-on-enter-with-jquery/ +* The non-jQuery code is a mimick of the jQuery code ;) +*/ +function apply_onkeypress_event() +{ + // jQuery code in case jQuery is used + if (jquery_present) + { + $('form input').live('keypress', function (e) + { + var default_button = $(this).parents('form').find('input[type=submit].default-submit-action'); + + if (!default_button || default_button.length <= 0) + return true; + + if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) + { + default_button.click(); + return false; + } + + return true; + }); + + return; + } + + var input_tags = document.getElementsByTagName('input'); + + for (var i = 0, element = input_tags[0]; i < input_tags.length ; element = input_tags[++i]) + { + if (element.type == 'hidden') + continue; + + // onkeydown is possible too + element.onkeypress = function (evt) { submit_default_button((evt || window.event), this, 'default-submit-action'); }; + } +} + +/** +* Detect JQuery existance. We currently do not deliver it, but some styles do, so why not benefit from it. ;) +*/ +var jquery_present = typeof jQuery == 'function'; diff --git a/phpBB/styles/prosilver/template/forumlist_body.html b/phpBB/styles/prosilver/template/forumlist_body.html index f19f3c3075..9fcafee34a 100644 --- a/phpBB/styles/prosilver/template/forumlist_body.html +++ b/phpBB/styles/prosilver/template/forumlist_body.html @@ -27,6 +27,8 @@
      • + + {forumrow.FORUM_IMAGE} {forumrow.FORUM_NAME}
        {forumrow.FORUM_DESC} @@ -41,6 +43,7 @@
        {forumrow.TOPICS} {L_TOPICS}
        {forumrow.POSTS} {L_POSTS}
        + {UNAPPROVED_IMG} {L_LAST_POST} {L_POST_BY_AUTHOR} {forumrow.LAST_POSTER_FULL} {LAST_POST_IMG}
        {forumrow.LAST_POST_TIME}{L_NO_POSTS}
         
        diff --git a/phpBB/styles/prosilver/template/index_body.html b/phpBB/styles/prosilver/template/index_body.html index 43d8ad0309..3ed8724361 100644 --- a/phpBB/styles/prosilver/template/index_body.html +++ b/phpBB/styles/prosilver/template/index_body.html @@ -6,7 +6,7 @@ @@ -18,7 +18,7 @@

        {L_LOGIN_LOGOUT}  •  {L_REGISTER}

    +
    diff --git a/phpBB/styles/prosilver/template/mcp_forum.html b/phpBB/styles/prosilver/template/mcp_forum.html index 05e4e2c8a2..2c98f7c9fa 100644 --- a/phpBB/styles/prosilver/template/mcp_forum.html +++ b/phpBB/styles/prosilver/template/mcp_forum.html @@ -35,7 +35,7 @@
  • -
    style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"> +
    style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"> [ {L_SELECT_MERGE} ]   {topicrow.TOPIC_TITLE} {topicrow.UNAPPROVED_IMG} diff --git a/phpBB/styles/prosilver/template/mcp_front.html b/phpBB/styles/prosilver/template/mcp_front.html index e0152391b9..0891948fb6 100644 --- a/phpBB/styles/prosilver/template/mcp_front.html +++ b/phpBB/styles/prosilver/template/mcp_front.html @@ -51,6 +51,7 @@
    + {S_HIDDEN_FIELDS}   @@ -100,6 +101,47 @@
  • + +
    +
    + +

    {L_LATEST_REPORTED_PMS}

    +

    {L_PM_REPORTS_TOTAL}

    + + +
      +
    • +
      +
      {L_VIEW_DETAILS}
      +
      {L_REPORTER}
      +
      +
    • +
    +
      + + +
    • +
      +
      + {pm_report.PM_SUBJECT} {pm_report.ATTACH_ICON_IMG}
      + {L_MESSAGE_BY_AUTHOR} {pm_report.PM_AUTHOR_FULL} » {pm_report.PM_TIME}
      + {L_MESSAGE_TO} {pm_report.RECIPIENTS} +
      +
      + {L_REPORTED} {L_POST_BY_AUTHOR} {pm_report.REPORTER_FULL} {L_REPORTED_ON_DATE} {pm_report.REPORT_TIME} +
      +
      +
    • + +
    + +

    {L_PM_REPORTS_ZERO_TOTAL}

    + + +
    +
    + +
    diff --git a/phpBB/styles/prosilver/template/mcp_logs.html b/phpBB/styles/prosilver/template/mcp_logs.html index bf1e867be3..494f63cb1b 100644 --- a/phpBB/styles/prosilver/template/mcp_logs.html +++ b/phpBB/styles/prosilver/template/mcp_logs.html @@ -8,6 +8,9 @@
    - {S_HIDDEN_FIELDS}  + {S_HIDDEN_FIELDS}  {S_FORM_TOKEN}
    -
    +
    -
    +
    @@ -114,7 +117,7 @@
    - +
    diff --git a/phpBB/styles/prosilver/template/mcp_post.html b/phpBB/styles/prosilver/template/mcp_post.html index 0e23148175..8a3c8e7309 100644 --- a/phpBB/styles/prosilver/template/mcp_post.html +++ b/phpBB/styles/prosilver/template/mcp_post.html @@ -1,14 +1,18 @@ + +

    {L_PM_REPORT_DETAILS}

    +

    {L_REPORT_DETAILS}

    +

    {L_REPORT_REASON}: {REPORT_REASON_TITLE}

    -

    {L_REPORTED} {L_POST_BY_AUTHOR} {REPORTER_FULL} {L_REPORTED_ON_DATE} {REPORT_DATE}

    +

    {L_REPORTED} {L_POST_BY_AUTHOR} {REPORTER_FULL} « {REPORT_DATE}

    {L_REPORT_CLOSED}

    @@ -51,7 +55,16 @@

    {POST_SUBJECT}

    + +

    + {L_SENT_AT}: {POST_DATE} +
    {L_PM_FROM}: {POST_AUTHOR_FULL} +
    {L_TO}: {to_recipient.NAME_FULL}{to_recipient.NAME}  +
    {L_BCC}: {bcc_recipient.NAME_FULL}{bcc_recipient.NAME}  +

    +

    {MINI_POST_IMG} {L_POSTED} {L_POST_BY_AUTHOR} {POST_AUTHOR_FULL} » {POST_DATE}

    +
    @@ -152,7 +165,7 @@
    -

    {RETURN_QUEUE} | {RETURN_TOPIC_SIMPLE} | {RETURN_POST}{RETURN_REPORTS} | {L_VIEW_POST} | {L_VIEW_TOPIC} | {L_VIEW_FORUM}{RETURN_TOPIC}

    +

    {RETURN_QUEUE} | {RETURN_TOPIC_SIMPLE} | {RETURN_POST}{RETURN_REPORTS} | {L_VIEW_POST} | {L_VIEW_TOPIC} | {L_VIEW_FORUM}{RETURN_TOPIC}

    @@ -171,7 +184,7 @@

    {L_FEEDBACK}

    - {L_REPORTED_BY}: {usernotes.REPORT_BY} {L_REPORTED_ON_DATE} {usernotes.REPORT_AT} + {L_REPORTED_BY}: {usernotes.REPORT_BY} « {usernotes.REPORT_AT}
    {usernotes.ACTION}
    @@ -211,7 +224,7 @@

    {L_MCP_POST_REPORTS}

    - {L_REPORTED_BY}: {reports.REPORTER}{reports.REPORTER} {L_REPORTED_ON_DATE} {reports.REPORT_TIME} + {L_REPORTED_BY}: {reports.REPORTER}{reports.REPORTER} « {reports.REPORT_TIME}

    {reports.REASON_TITLE}: {reports.REASON_DESC}
    {reports.REPORT_TEXT}

    diff --git a/phpBB/styles/prosilver/template/mcp_reports.html b/phpBB/styles/prosilver/template/mcp_reports.html index 4e9db078c2..649154deb4 100644 --- a/phpBB/styles/prosilver/template/mcp_reports.html +++ b/phpBB/styles/prosilver/template/mcp_reports.html @@ -2,11 +2,13 @@ +
    {S_FORM_TOKEN}
    +

    {L_TITLE}

    @@ -26,7 +28,7 @@
  • {L_VIEW_DETAILS}
    -
    {L_REPORTER} & {L_FORUM}
    +
    {L_REPORTER} & {L_FORUM}
    {L_MARK}
  • @@ -36,14 +38,25 @@
  • + +
    + {postrow.PM_SUBJECT} {postrow.ATTACH_ICON_IMG}
    + {L_MESSAGE_BY_AUTHOR} {postrow.PM_AUTHOR_FULL} » {postrow.PM_TIME}
    + {L_MESSAGE_TO} {postrow.RECIPIENTS} +
    +
    + {postrow.REPORTER_FULL} « {postrow.REPORT_TIME} +
    +
    {postrow.POST_SUBJECT} {postrow.ATTACH_ICON_IMG}
    {L_POSTED} {L_POST_BY_AUTHOR} {postrow.POST_AUTHOR_FULL} » {postrow.POST_TIME}
    - {postrow.REPORTER_FULL} {L_REPORTED_ON_DATE} {postrow.REPORT_TIME}
    + {postrow.REPORTER_FULL} « {postrow.REPORT_TIME}
    {L_FORUM}: {postrow.FORUM_NAME}
    +
  • diff --git a/phpBB/styles/prosilver/template/mcp_topic.html b/phpBB/styles/prosilver/template/mcp_topic.html index 7453c01ec1..db36ebf5ac 100644 --- a/phpBB/styles/prosilver/template/mcp_topic.html +++ b/phpBB/styles/prosilver/template/mcp_topic.html @@ -106,14 +106,14 @@ onload_functions.push('subPanels()');
    -
    {L_POST_DETAILS} | {L_SELECT}: checked="checked" />
    +

    {postrow.POST_SUBJECT}

    {postrow.MINI_POST_IMG} {L_POSTED} {postrow.POST_DATE} {L_POST_BY_AUTHOR} {postrow.POST_AUTHOR_FULL} [ {L_POST_DETAILS} ]

    - {UNAPPROVED_IMG} {L_POST_UNAPPROVED} + {UNAPPROVED_IMG} {L_POST_UNAPPROVED}
    {REPORTED_IMG} {L_POST_REPORTED}

    diff --git a/phpBB/styles/prosilver/template/memberlist_body.html b/phpBB/styles/prosilver/template/memberlist_body.html index ab2be261a8..197cbd4a0c 100644 --- a/phpBB/styles/prosilver/template/memberlist_body.html +++ b/phpBB/styles/prosilver/template/memberlist_body.html @@ -131,7 +131,7 @@ {memberrow.RANK_IMG}{memberrow.RANK_TITLE} {memberrow.USERNAME_FULL}
    {L_SELECT} ] - {memberrow.POSTS}{memberrow.POSTS} + {memberrow.POSTS}{memberrow.POSTS}
    {memberrow.LOCATION}
      {memberrow.JOINED} {memberrow.VISITED}  diff --git a/phpBB/styles/prosilver/template/memberlist_im.html b/phpBB/styles/prosilver/template/memberlist_im.html index 9bb1f90a58..acc7ec359b 100644 --- a/phpBB/styles/prosilver/template/memberlist_im.html +++ b/phpBB/styles/prosilver/template/memberlist_im.html @@ -7,13 +7,13 @@
    - +

    {L_SEND_IM_EXPLAIN}

    -
    {USERNAME} [ {IM_CONTACT} ] {PRESENCE_IMG}
    +
    {USERNAME} [ {IM_CONTACT} ] {PRESENCE_IMG}
    @@ -81,9 +81,10 @@
    -{L_CLOSE_WINDOW} +{L_CLOSE_WINDOW} + +

    {ERROR}

    @@ -88,9 +94,9 @@ -
    +
    -
    +
    @@ -99,13 +105,10 @@
    - -
    -

    {L_CONFIRM_CODE_EXPLAIN}
    -
    {CONFIRM_IMAGE}
    -
    -
    - + + + + @@ -128,8 +131,8 @@ {IMG_STATUS}
    {FLASH_STATUS}
    {URL_STATUS}
    - {SMILIES_STATUS} + {SMILIES_STATUS}
    @@ -139,7 +142,7 @@
    - +
    @@ -184,10 +187,10 @@
    {S_HIDDEN_ADDRESS_FIELD} {S_HIDDEN_FIELDS} -   -   +   +   onclick="document.getElementById('postform').action += '#preview';" />  -   +  
    diff --git a/phpBB/styles/prosilver/template/posting_preview.html b/phpBB/styles/prosilver/template/posting_preview.html index 7ea1fb063d..82227c23b0 100644 --- a/phpBB/styles/prosilver/template/posting_preview.html +++ b/phpBB/styles/prosilver/template/posting_preview.html @@ -1,4 +1,4 @@ -
    +
    @@ -19,16 +19,16 @@
    -
    +

    {L_PREVIEW}: {PREVIEW_SUBJECT}

    - +
    {PREVIEW_MESSAGE}
    - +
    {L_ATTACHMENTS}
    @@ -37,7 +37,7 @@
    - +
    {PREVIEW_SIGNATURE}
    diff --git a/phpBB/styles/prosilver/template/posting_smilies.html b/phpBB/styles/prosilver/template/posting_smilies.html index dd0963baf5..fdd0d7ada1 100644 --- a/phpBB/styles/prosilver/template/posting_smilies.html +++ b/phpBB/styles/prosilver/template/posting_smilies.html @@ -12,11 +12,12 @@
    - {smiley.SMILEY_CODE} + {smiley.SMILEY_CODE}
    +
    {PAGINATION}
    {L_CLOSE_WINDOW} \ No newline at end of file diff --git a/phpBB/styles/prosilver/template/posting_topic_review.html b/phpBB/styles/prosilver/template/posting_topic_review.html index 428a830ef3..0d68a02758 100644 --- a/phpBB/styles/prosilver/template/posting_topic_review.html +++ b/phpBB/styles/prosilver/template/posting_topic_review.html @@ -5,6 +5,11 @@
    + diff --git a/phpBB/styles/prosilver/template/quickreply_editor.html b/phpBB/styles/prosilver/template/quickreply_editor.html new file mode 100644 index 0000000000..1ec8e2b643 --- /dev/null +++ b/phpBB/styles/prosilver/template/quickreply_editor.html @@ -0,0 +1,79 @@ + + +
    + + +
    diff --git a/phpBB/styles/prosilver/template/search_body.html b/phpBB/styles/prosilver/template/search_body.html index f785fcf50a..612641b141 100644 --- a/phpBB/styles/prosilver/template/search_body.html +++ b/phpBB/styles/prosilver/template/search_body.html @@ -7,7 +7,7 @@

    {L_SEARCH_QUERY}

    - +

    {L_SEARCH_KEYWORDS_EXPLAIN}
    @@ -28,7 +28,7 @@

    {L_SEARCH_OPTIONS}

    - +

    {L_SEARCH_FORUMS_EXPLAIN}
    @@ -37,7 +37,7 @@
    - +
    @@ -54,14 +54,14 @@
    - +
    {S_SELECT_SORT_KEY}  - +
    @@ -82,7 +82,7 @@
    - {S_HIDDEN_FIELDS}  + {S_HIDDEN_FIELDS} 
    diff --git a/phpBB/styles/prosilver/template/search_results.html b/phpBB/styles/prosilver/template/search_results.html index 86b86e3d94..c38a37452b 100644 --- a/phpBB/styles/prosilver/template/search_results.html +++ b/phpBB/styles/prosilver/template/search_results.html @@ -18,7 +18,6 @@ diff --git a/phpBB/styles/prosilver/template/styleswitcher.js b/phpBB/styles/prosilver/template/styleswitcher.js index 203d8e4c21..bbcac9b69c 100644 --- a/phpBB/styles/prosilver/template/styleswitcher.js +++ b/phpBB/styles/prosilver/template/styleswitcher.js @@ -1,6 +1,12 @@ -function fontsizeup() +function fontsizeup(event) { + // Skip tabs; 9 being the ASCII code for a tab + if (event && getKeyCode(event) == 9) + { + return true; + } + var active = getActiveStyleSheet(); switch (active) @@ -29,11 +35,19 @@ function fontsizeup() setActiveStyleSheet('A'); break; } + + return false; } -function fontsizedown() +function fontsizedown(event) { - active = getActiveStyleSheet(); + // Skip tabs + if (event && getKeyCode(event) == 9) + { + return true; + } + + var active = getActiveStyleSheet(); switch (active) { @@ -60,6 +74,24 @@ function fontsizedown() setActiveStyleSheet('A--'); break; } + + return false; +} + +function getKeyCode(event) +{ + // IE doesn't fire the onkeypress event for tabs + // Reference: http://www.quirksmode.org/js/keys.html + + var code = (event.keyCode) ? event.keyCode : 0; + + // Probably using FF + if (!code && event.charCode) + { + code = event.charCode; + } + + return code; } function setActiveStyleSheet(title) diff --git a/phpBB/styles/prosilver/template/template.cfg b/phpBB/styles/prosilver/template/template.cfg index 0e5e8f0530..22328dd50b 100644 --- a/phpBB/styles/prosilver/template/template.cfg +++ b/phpBB/styles/prosilver/template/template.cfg @@ -19,7 +19,7 @@ # General Information about this template name = prosilver copyright = © phpBB Group, 2007 -version = 3.0.5 +version = 3.0.6 # Defining a different template bitfield template_bitfield = lNg= diff --git a/phpBB/styles/prosilver/template/ucp_agreement.html b/phpBB/styles/prosilver/template/ucp_agreement.html index 67dcb35e7b..3825abc08f 100644 --- a/phpBB/styles/prosilver/template/ucp_agreement.html +++ b/phpBB/styles/prosilver/template/ucp_agreement.html @@ -1,8 +1,33 @@ - + + + +
    +

    + + {S_HIDDEN_FIELDS} +

    +
    + +
    + + +
    @@ -45,4 +70,4 @@ - \ No newline at end of file + diff --git a/phpBB/styles/prosilver/template/ucp_avatar_options.html b/phpBB/styles/prosilver/template/ucp_avatar_options.html index d43e76e584..57aa82ca7b 100644 --- a/phpBB/styles/prosilver/template/ucp_avatar_options.html +++ b/phpBB/styles/prosilver/template/ucp_avatar_options.html @@ -13,21 +13,21 @@
    - +
    - +

    {L_UPLOAD_AVATAR_URL_EXPLAIN}
    - +

    {L_LINK_REMOTE_AVATAR_EXPLAIN}
    @@ -41,7 +41,7 @@
    - +
    @@ -50,7 +50,7 @@

    {L_AVATAR_GALLERY}

    - +
    @@ -63,7 +63,7 @@
    - +
    diff --git a/phpBB/styles/prosilver/template/ucp_groups_manage.html b/phpBB/styles/prosilver/template/ucp_groups_manage.html index 47a8acb13a..2171250621 100644 --- a/phpBB/styles/prosilver/template/ucp_groups_manage.html +++ b/phpBB/styles/prosilver/template/ucp_groups_manage.html @@ -170,7 +170,7 @@

    {L_ADD_USERS}

    -

    {L_ADD_USERS_EXPLAIN}

    +

    {L_ADD_USERS_UCP_EXPLAIN}

    diff --git a/phpBB/styles/prosilver/template/ucp_main_front.html b/phpBB/styles/prosilver/template/ucp_main_front.html index a1b9fa440e..39c5d4f396 100644 --- a/phpBB/styles/prosilver/template/ucp_main_front.html +++ b/phpBB/styles/prosilver/template/ucp_main_front.html @@ -33,7 +33,7 @@
    {L_JOINED}:
    {JOINED}
    {L_VISITED}:
    {LAST_VISIT_YOU}
    -
    {L_TOTAL_POSTS}:
    {POSTS} | {L_SEARCH_YOUR_POSTS}
    ({POSTS_DAY} / {POSTS_PCT}){POSTS}
    +
    {L_TOTAL_POSTS}:
    {POSTS} | {L_SEARCH_YOUR_POSTS}
    ({POSTS_DAY} / {POSTS_PCT}){POSTS}
    {L_ACTIVE_IN_FORUM}:
    {ACTIVE_FORUM}
    ({ACTIVE_FORUM_POSTS} / {ACTIVE_FORUM_PCT})
    {L_ACTIVE_IN_TOPIC}:
    {ACTIVE_TOPIC}
    ({ACTIVE_TOPIC_POSTS} / {ACTIVE_TOPIC_PCT})
    {L_YOUR_WARNINGS}:
    {WARNING_IMG} [{WARNINGS}]
    diff --git a/phpBB/styles/prosilver/template/ucp_pm_history.html b/phpBB/styles/prosilver/template/ucp_pm_history.html index d4ef61c4a9..88efcf95be 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_history.html +++ b/phpBB/styles/prosilver/template/ucp_pm_history.html @@ -17,9 +17,9 @@

    class="current">{history_row.SUBJECT}

    -

    {history_row.MINI_POST_IMG} {L_SENT_AT}: {history_row.SENT_DATE}
    +

    {history_row.MINI_POST_IMG} {L_SENT_AT}: {history_row.SENT_DATE}
    {L_MESSAGE_BY_AUTHOR} {history_row.MESSAGE_AUTHOR_FULL}

    -
    {history_row.MESSAGE}
    +
    {history_row.MESSAGE}
    diff --git a/phpBB/styles/prosilver/template/ucp_pm_message_header.html b/phpBB/styles/prosilver/template/ucp_pm_message_header.html index f9eb1cc102..fcebab0868 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_message_header.html +++ b/phpBB/styles/prosilver/template/ucp_pm_message_header.html @@ -1,22 +1,25 @@

    {L_TITLE}: {CUR_FOLDER_NAME}

    - - -
    + + + diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html b/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html index a8750a03f0..05d213f2ed 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html +++ b/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html @@ -2,9 +2,9 @@ +
    -

    {L_EXPORT_AS_CSV}

    @@ -82,6 +82,8 @@ + +

    {L_USER_NEW_PERMISSION_DISALLOWED}{L_NO_AUTH_SEND_MESSAGE}

    {L_NO_MESSAGES}

    diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html index ef9807f88a..df0cf25e82 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html +++ b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html @@ -1,27 +1,26 @@ - + -
    -
    -
    +
    {L_VIEW_PREVIOUS_HISTORY} {L_VIEW_NEXT_HISTORY}
    -
    -
    +
    +
    - + @@ -67,7 +66,7 @@
    {RANK_TITLE}
    {RANK_IMG}
     
    -
    {L_POSTS}: {AUTHOR_POSTS}
    +
    {L_POSTS}: {AUTHOR_POSTS}
    {L_JOINED}: {AUTHOR_JOINED}
    {L_LOCATION}: {AUTHOR_FROM}
    diff --git a/phpBB/styles/prosilver/template/ucp_profile_signature.html b/phpBB/styles/prosilver/template/ucp_profile_signature.html index dbaeac3254..5d25d2d9f4 100644 --- a/phpBB/styles/prosilver/template/ucp_profile_signature.html +++ b/phpBB/styles/prosilver/template/ucp_profile_signature.html @@ -8,7 +8,7 @@

    {L_SIGNATURE_PREVIEW}

    -
    +
    {SIGNATURE_PREVIEW}
    @@ -33,7 +33,7 @@
    - +
    @@ -41,8 +41,8 @@
    {S_HIDDEN_FIELDS} -   -   +   +   {S_FORM_TOKEN}
    diff --git a/phpBB/styles/prosilver/template/ucp_register.html b/phpBB/styles/prosilver/template/ucp_register.html index 3aeb92a5b0..e63abaec05 100644 --- a/phpBB/styles/prosilver/template/ucp_register.html +++ b/phpBB/styles/prosilver/template/ucp_register.html @@ -11,6 +11,10 @@ document.forms['register'].submit.click(); } + + onload_functions.push('apply_onkeypress_event()'); + + // ]]> @@ -26,10 +30,6 @@
    {L_REG_COND}
    - -
    {L_ITEMS_REQUIRED}
    - -

    {L_USERNAME_EXPLAIN}
    @@ -48,20 +48,23 @@
    -
    +

    -
    +
    -
    +
    + +
    {L_ITEMS_REQUIRED}
    +
    for="{profile_fields.FIELD_ID}">{profile_fields.LANG_NAME}: * @@ -70,32 +73,18 @@
    {profile_fields.FIELD}
    -
    + - + - -
    -
    - -

    {L_CONFIRMATION}

    -

    {L_CONFIRM_EXPLAIN}

    - -
    -
    -
    -
    {CONFIRM_IMG}
    -
    -
    {L_CONFIRM_CODE_EXPLAIN} {L_VC_REFRESH_EXPLAIN}
    -
    -
    -
    + + + -
    -
    +
    @@ -103,10 +92,9 @@

    {L_COPPA_COMPLIANCE}

    {L_COPPA_EXPLAIN}

    - -
    +
    @@ -114,7 +102,7 @@
    {S_HIDDEN_FIELDS}   - + {S_FORM_TOKEN}
    diff --git a/phpBB/styles/prosilver/template/viewforum_body.html b/phpBB/styles/prosilver/template/viewforum_body.html index 23c52a5ee0..70fd5c8496 100644 --- a/phpBB/styles/prosilver/template/viewforum_body.html +++ b/phpBB/styles/prosilver/template/viewforum_body.html @@ -3,11 +3,11 @@

    {FORUM_NAME}

    -

    +

    - {FORUM_DESC}
    +
    {FORUM_DESC}
    {L_MODERATOR}{L_MODERATORS}: {MODERATORS} -

    +
    diff --git a/phpBB/styles/prosilver/template/viewtopic_body.html b/phpBB/styles/prosilver/template/viewtopic_body.html index 17088bb16a..24c57b9a7e 100644 --- a/phpBB/styles/prosilver/template/viewtopic_body.html +++ b/phpBB/styles/prosilver/template/viewtopic_body.html @@ -2,7 +2,7 @@

    {L_MCP} ]

    {TOPIC_TITLE}

    -{FORUM_DESC}
    +
    {FORUM_DESC}

    @@ -123,7 +123,7 @@ - +

    -
    {postrow.BUMPED_MESSAGE}
    +


    {postrow.BUMPED_MESSAGE}
    {postrow.SIGNATURE}
    @@ -222,7 +222,9 @@
    - + + + diff --git a/phpBB/styles/prosilver/template/viewtopic_print.html b/phpBB/styles/prosilver/template/viewtopic_print.html index 2946d7645c..be1feb9208 100644 --- a/phpBB/styles/prosilver/template/viewtopic_print.html +++ b/phpBB/styles/prosilver/template/viewtopic_print.html @@ -25,7 +25,7 @@ diff --git a/phpBB/styles/prosilver/theme/bidi.css b/phpBB/styles/prosilver/theme/bidi.css index 561bba0717..be7cdab2b9 100644 --- a/phpBB/styles/prosilver/theme/bidi.css +++ b/phpBB/styles/prosilver/theme/bidi.css @@ -234,9 +234,33 @@ padding-right: 15px; } +.rtl .skiplink { + /* invisible skip link, used for accessibility */ + position: relative; + width: 1px; + height: 1px; + overflow: hidden; + display: block; + left: 0; +} + +.rtl a.feed-icon-forum { + float: left; +} + /** * content.css */ +.rtl ul.topiclist dfn { + /* Labels for post/view counts */ + position: relative; + width: 1px; + height: 1px; + overflow: hidden; + display: block; + left: 0; +} + .rtl ul.topiclist dt { float: right; } @@ -347,11 +371,12 @@ /* Quote block */ .rtl blockquote { margin: 0.5em 25px 0 1px; + background-position: 99% 5px; } .rtl blockquote blockquote { /* Nested quotes */ - margin: 0.5em 15px 0 1px; + margin: 0.5em 15px 0 1px; } .rtl blockquote cite { diff --git a/phpBB/styles/prosilver/theme/colours.css b/phpBB/styles/prosilver/theme/colours.css index d7ee0b21b7..2c0606001c 100644 --- a/phpBB/styles/prosilver/theme/colours.css +++ b/phpBB/styles/prosilver/theme/colours.css @@ -461,6 +461,10 @@ blockquote { border-color:#DBDBCE; } +.rtl blockquote { + background-image: url("{T_THEME_PATH}/images/quote_rtl.gif"); +} + blockquote blockquote { /* Nested quotes */ background-color:#EFEED9; @@ -786,6 +790,11 @@ ul.cplist { background-image: url("{T_THEME_PATH}/images/bg_menu.gif"); } +.rtl #navigation a { + background-image: url("{T_THEME_PATH}/images/bg_menu_rtl.gif"); + background-position: 0 100%; +} + #navigation a:hover { background-color: #aabac6; color: #BC2A4D; @@ -861,7 +870,13 @@ dl.mini dt { ----------------------------------------*/ /* PM Message history */ .current { - color: #999999 !important; + color: #000000 !important; +} + +/* PM panel adjustments */ +.pm-panel-header, +#cp-main .pm-message-nav { + border-bottom-color: #A4B3BF; } /* PM marking colours */ diff --git a/phpBB/styles/prosilver/theme/common.css b/phpBB/styles/prosilver/theme/common.css index 7178fa6e42..a86f723f81 100644 --- a/phpBB/styles/prosilver/theme/common.css +++ b/phpBB/styles/prosilver/theme/common.css @@ -10,8 +10,7 @@ html { font-size: 100%; /* Always show a scrollbar for short pages - stops the jump when the scrollbar appears. non-IE browsers */ - height: 100%; - margin-bottom: 1px; + height: 101%; } body { @@ -611,6 +610,7 @@ p.rules { p.rules img { vertical-align: middle; + padding-top: 5px; } p.rules a { diff --git a/phpBB/styles/prosilver/theme/content.css b/phpBB/styles/prosilver/theme/content.css index 19f5dfdb3b..417537e660 100644 --- a/phpBB/styles/prosilver/theme/content.css +++ b/phpBB/styles/prosilver/theme/content.css @@ -132,6 +132,18 @@ dd.posts, dd.topics, dd.views { font-size: 1.2em; } +/* List in forum description */ +dl.icon dt ol, +dl.icon dt ul { + list-style-position: inside; + margin-left: 1em; +} + +dl.icon dt li { + display: list-item; + list-style-type: inherit; +} + dd.lastpost { width: 25%; font-size: 1.1em; @@ -295,6 +307,7 @@ div[class].topic-actions { font-family: "Lucida Grande", "Trebuchet MS", Verdana, Helvetica, Arial, sans-serif; font-size: 1em; color: #333333; + padding-bottom: 1px; } .content h2, .panel h2 { diff --git a/phpBB/styles/prosilver/theme/cp.css b/phpBB/styles/prosilver/theme/cp.css index fa8899bae8..1e0edc616f 100644 --- a/phpBB/styles/prosilver/theme/cp.css +++ b/phpBB/styles/prosilver/theme/cp.css @@ -348,6 +348,34 @@ dl.mini dd { line-height: 2.5em; } +/* PM panel adjustments */ +.pm-panel-header { + margin: 0; + padding-bottom: 10px; + border-bottom: 1px dashed #A4B3BF; +} + +.reply-all { + display: block; + padding-top: 4px; + clear: both; + float: left; +} + +.pm-panel-message { + padding-top: 10px; +} + +.pm-return-to { + padding-top: 23px; +} + +#cp-main .pm-message-nav { + margin: 0; + padding: 2px 10px 5px 10px; + border-bottom: 1px dashed #A4B3BF; +} + /* PM Message history */ .current { color: #999999; diff --git a/phpBB/styles/prosilver/theme/images/bg_menu_rtl.gif b/phpBB/styles/prosilver/theme/images/bg_menu_rtl.gif new file mode 100644 index 0000000000..10add09a17 Binary files /dev/null and b/phpBB/styles/prosilver/theme/images/bg_menu_rtl.gif differ diff --git a/phpBB/styles/prosilver/theme/images/feed.gif b/phpBB/styles/prosilver/theme/images/feed.gif new file mode 100644 index 0000000000..ff19905874 Binary files /dev/null and b/phpBB/styles/prosilver/theme/images/feed.gif differ diff --git a/phpBB/styles/prosilver/theme/images/quote_rtl.gif b/phpBB/styles/prosilver/theme/images/quote_rtl.gif new file mode 100644 index 0000000000..ac719cf280 Binary files /dev/null and b/phpBB/styles/prosilver/theme/images/quote_rtl.gif differ diff --git a/phpBB/styles/prosilver/theme/links.css b/phpBB/styles/prosilver/theme/links.css index 0b23449bfb..4284157326 100644 --- a/phpBB/styles/prosilver/theme/links.css +++ b/phpBB/styles/prosilver/theme/links.css @@ -205,3 +205,9 @@ a.right:hover { left: -999px; width: 990px; } + +/* Feed icon in forumlist_body.html */ +a.feed-icon-forum { + float: right; + margin: 3px; +} diff --git a/phpBB/styles/prosilver/theme/print.css b/phpBB/styles/prosilver/theme/print.css index 3143b3cf9b..6dfb5c4726 100644 --- a/phpBB/styles/prosilver/theme/print.css +++ b/phpBB/styles/prosilver/theme/print.css @@ -25,6 +25,10 @@ a:visited { color: #000000; text-decoration: none; } a:active { color: #000000; text-decoration: none; } img, .noprint, #sub-header, #sub-footer, .navbar, .box1, .divider, .signature { display: none; } +/* Display smilies (Bug #47265) */ +.content img { + display: inline; +} /* Container for the main body */ #wrap { @@ -108,7 +112,7 @@ html>body .postbody h1 a:link:after, html>body .postbody h2 a:link:after { .grip-show { display:none; } /* Quote */ -.postquote { +.postquote, blockquote { font-size: 85%; margin: 1em 18% 1em 4%; padding: 0.5em; @@ -120,7 +124,16 @@ html>body .postbody h1 a:link:after, html>body .postbody h2 a:link:after { .postquote img { display: none; } .postquote span { display: block; } .postquote span .postquote { font-size: 100%; } -.quote-by { font-weight: bold; } +.quote-by, blockquote cite { + color: black; + display : block; + font-weight: bold; +} + +/* List */ +ol, ul { + margin-left: 15pt +} /* Misc page elements */ div.spacer { clear: both; } diff --git a/phpBB/styles/prosilver/theme/theme.cfg b/phpBB/styles/prosilver/theme/theme.cfg index 3a1dc6989a..91a35bbcc8 100644 --- a/phpBB/styles/prosilver/theme/theme.cfg +++ b/phpBB/styles/prosilver/theme/theme.cfg @@ -21,7 +21,7 @@ # General Information about this theme name = prosilver copyright = © phpBB Group, 2007 -version = 3.0.5 +version = 3.0.6 # Some configuration options diff --git a/phpBB/styles/prosilver/theme/tweaks.css b/phpBB/styles/prosilver/theme/tweaks.css index b6038f3f05..782e682b9d 100644 --- a/phpBB/styles/prosilver/theme/tweaks.css +++ b/phpBB/styles/prosilver/theme/tweaks.css @@ -67,6 +67,11 @@ dl.icon { height: 35px; } +* html li.row dl.icon dt { + height: 35px; + overflow: visible; +} + * html #search-box { width: 25%; } diff --git a/phpBB/styles/subsilver2/imageset/imageset.cfg b/phpBB/styles/subsilver2/imageset/imageset.cfg index 3462d3ae66..97fd0d8949 100644 --- a/phpBB/styles/subsilver2/imageset/imageset.cfg +++ b/phpBB/styles/subsilver2/imageset/imageset.cfg @@ -19,13 +19,13 @@ # General Information about this style name = subsilver2 copyright = © phpBB Group, 2003 -version = 3.0.5 +version = 3.0.6 # Images img_site_logo = site_logo.gif*94*170 img_upload_bar = upload_bar.gif*16*280 img_poll_left = poll_left.gif*12*4 -img_poll_center = poll_center.gif*12* +img_poll_center = poll_center.gif*12*1 img_poll_right = poll_right.gif*12*4 img_icon_friend = img_icon_foe = diff --git a/phpBB/styles/subsilver2/imageset/site_logo.gif b/phpBB/styles/subsilver2/imageset/site_logo.gif index 48c3b553da..abce3cd51d 100644 Binary files a/phpBB/styles/subsilver2/imageset/site_logo.gif and b/phpBB/styles/subsilver2/imageset/site_logo.gif differ diff --git a/phpBB/styles/subsilver2/imageset/topic_read_hot.gif b/phpBB/styles/subsilver2/imageset/topic_read_hot.gif index a7e8831e2c..a7a7e8fc78 100644 Binary files a/phpBB/styles/subsilver2/imageset/topic_read_hot.gif and b/phpBB/styles/subsilver2/imageset/topic_read_hot.gif differ diff --git a/phpBB/styles/subsilver2/imageset/topic_read_hot_mine.gif b/phpBB/styles/subsilver2/imageset/topic_read_hot_mine.gif index 335ae77645..853452a74b 100644 Binary files a/phpBB/styles/subsilver2/imageset/topic_read_hot_mine.gif and b/phpBB/styles/subsilver2/imageset/topic_read_hot_mine.gif differ diff --git a/phpBB/styles/subsilver2/imageset/topic_unread_hot.gif b/phpBB/styles/subsilver2/imageset/topic_unread_hot.gif index 25ced64b83..ceef4919d5 100644 Binary files a/phpBB/styles/subsilver2/imageset/topic_unread_hot.gif and b/phpBB/styles/subsilver2/imageset/topic_unread_hot.gif differ diff --git a/phpBB/styles/subsilver2/imageset/topic_unread_hot_mine.gif b/phpBB/styles/subsilver2/imageset/topic_unread_hot_mine.gif index 4d3937ae28..1c748f708a 100644 Binary files a/phpBB/styles/subsilver2/imageset/topic_unread_hot_mine.gif and b/phpBB/styles/subsilver2/imageset/topic_unread_hot_mine.gif differ diff --git a/phpBB/styles/subsilver2/style.cfg b/phpBB/styles/subsilver2/style.cfg index da64a05e5a..5eaaac782d 100644 --- a/phpBB/styles/subsilver2/style.cfg +++ b/phpBB/styles/subsilver2/style.cfg @@ -19,4 +19,4 @@ # General Information about this style name = subsilver2 copyright = © 2005 phpBB Group -version = 3.0.5 +version = 3.0.6 diff --git a/phpBB/styles/subsilver2/template/captcha_default.html b/phpBB/styles/subsilver2/template/captcha_default.html new file mode 100644 index 0000000000..eaf7a30944 --- /dev/null +++ b/phpBB/styles/subsilver2/template/captcha_default.html @@ -0,0 +1,15 @@ + + {L_CONFIRM_CODE} + + + {L_CONFIRM_EXPLAIN} + + + {L_CONFIRM_CODE} + + + + {L_CONFIRM_CODE}:
    {L_CONFIRM_CODE_EXPLAIN} + + + diff --git a/phpBB/styles/subsilver2/template/captcha_qa.html b/phpBB/styles/subsilver2/template/captcha_qa.html new file mode 100644 index 0000000000..dc8d5505a1 --- /dev/null +++ b/phpBB/styles/subsilver2/template/captcha_qa.html @@ -0,0 +1,8 @@ + + {QA_CONFIRM_QUESTION} + + + {QA_CONFIRM_QUESTION}:
    + + + diff --git a/phpBB/styles/subsilver2/template/captcha_recaptcha.html b/phpBB/styles/subsilver2/template/captcha_recaptcha.html new file mode 100644 index 0000000000..d8b06d2c51 --- /dev/null +++ b/phpBB/styles/subsilver2/template/captcha_recaptcha.html @@ -0,0 +1,26 @@ + + + {L_CONFIRM_CODE} + + + {L_CONFIRM_CODE}:
    {L_RECAPTCHA_EXPLAIN} + + + + + + + + +{L_RECAPTCHA_NOT_AVAILABLE} + diff --git a/phpBB/styles/subsilver2/template/editor.js b/phpBB/styles/subsilver2/template/editor.js index ae062d65a7..b4a426df4e 100644 --- a/phpBB/styles/subsilver2/template/editor.js +++ b/phpBB/styles/subsilver2/template/editor.js @@ -261,7 +261,7 @@ function addquote(post_id, username) */ function mozWrap(txtarea, open, close) { - var selLength = txtarea.textLength; + var selLength = (typeof(txtarea.textLength) == 'undefined') ? txtarea.value.length : txtarea.textLength; var selStart = txtarea.selectionStart; var selEnd = txtarea.selectionEnd; var scrollTop = txtarea.scrollTop; diff --git a/phpBB/styles/subsilver2/template/forumlist_body.html b/phpBB/styles/subsilver2/template/forumlist_body.html index 368610ebe1..a994e9e676 100644 --- a/phpBB/styles/subsilver2/template/forumlist_body.html +++ b/phpBB/styles/subsilver2/template/forumlist_body.html @@ -19,11 +19,10 @@ {forumrow.FORUM_FOLDER_IMG} -
    {forumrow.FORUM_IMAGE}
    +
    {forumrow.FORUM_IMAGE}
    {forumrow.FORUM_NAME}

    {forumrow.FORUM_DESC}

    -
    {L_REDIRECTS}: {forumrow.CLICKS} @@ -42,7 +41,7 @@ {forumrow.FORUM_FOLDER_IMG} -
    {forumrow.FORUM_IMAGE}
    +
    {forumrow.FORUM_IMAGE}
    {forumrow.FORUM_NAME}

    {forumrow.FORUM_DESC}

    @@ -52,13 +51,12 @@

    {forumrow.L_SUBFORUM_STR} {forumrow.SUBFORUMS}

    -

    {forumrow.TOPICS}

    {forumrow.POSTS}

    -

    {forumrow.LAST_POST_TIME}

    +

    {UNAPPROVED_IMG} {forumrow.LAST_POST_TIME}

    {forumrow.LAST_POSTER_FULL} {LAST_POST_IMG}

    diff --git a/phpBB/styles/subsilver2/template/login_body.html b/phpBB/styles/subsilver2/template/login_body.html index 86eed2dfc6..810a7376f2 100644 --- a/phpBB/styles/subsilver2/template/login_body.html +++ b/phpBB/styles/subsilver2/template/login_body.html @@ -65,26 +65,13 @@ - + - - - - - - - - - - - - - + + + diff --git a/phpBB/styles/subsilver2/template/mcp_front.html b/phpBB/styles/subsilver2/template/mcp_front.html index 029ba3cb3c..7c63039259 100644 --- a/phpBB/styles/subsilver2/template/mcp_front.html +++ b/phpBB/styles/subsilver2/template/mcp_front.html @@ -35,7 +35,7 @@ - +
    {L_LOGIN_CONFIRMATION}
    {L_LOGIN_CONFIRM_EXPLAIN}
    - - {CONFIRM_IMAGE} -
    {L_CONFIRM_CODE}:
    {L_CONFIRM_CODE_EXPLAIN}
    colspan="2" align="center">{S_HIDDEN_FIELDS}
      {S_HIDDEN_FIELDS}  
    {S_FORM_TOKEN} @@ -85,6 +85,43 @@

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    {L_LATEST_REPORTED_PMS}
     {L_PM_SUBJECT}  {L_PM_FROM}  {L_TO} & {L_BCC}  {L_SENT_AT}  {L_REPORTER}  {L_REPORT_TIME} 
    {pm_report.PM_SUBJECT}
    [ {L_VIEW_DETAILS} ]
    {pm_report.PM_AUTHOR_FULL}{pm_report.RECIPIENTS}{pm_report.PM_TIME}{pm_report.REPORTER_FULL}{pm_report.REPORT_TIME}
    {L_PM_REPORTS_ZERO_TOTAL}
    {L_PM_REPORTS_TOTAL}
    + +

    + + diff --git a/phpBB/styles/subsilver2/template/mcp_logs.html b/phpBB/styles/subsilver2/template/mcp_logs.html index f7c4a99fc1..6b78df3e5e 100644 --- a/phpBB/styles/subsilver2/template/mcp_logs.html +++ b/phpBB/styles/subsilver2/template/mcp_logs.html @@ -21,6 +21,9 @@ + + + diff --git a/phpBB/styles/subsilver2/template/mcp_notes_user.html b/phpBB/styles/subsilver2/template/mcp_notes_user.html index 5df3f50407..522c19fa05 100644 --- a/phpBB/styles/subsilver2/template/mcp_notes_user.html +++ b/phpBB/styles/subsilver2/template/mcp_notes_user.html @@ -54,6 +54,9 @@ + + + diff --git a/phpBB/styles/subsilver2/template/mcp_post.html b/phpBB/styles/subsilver2/template/mcp_post.html index 6260c79d7d..ecf4558b45 100644 --- a/phpBB/styles/subsilver2/template/mcp_post.html +++ b/phpBB/styles/subsilver2/template/mcp_post.html @@ -5,7 +5,7 @@
    {L_SEARCH_KEYWORDS}:  
    {L_DISPLAY_LOG}: {S_SELECT_SORT_DAYS} {L_SORT_BY} {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR} 
    {L_SEARCH_KEYWORDS}:  
    {L_DISPLAY_LOG}: {S_SELECT_SORT_DAYS} {L_SORT_BY}: {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR} 
    - + @@ -43,17 +43,17 @@
    {L_REPORT_DETAILS}{L_PM_REPORT_DETAILS}{L_REPORT_DETAILS}
    {L_REPORT_REASON}:
    - + - + - + - + @@ -69,9 +69,30 @@ - + + + + + + + + + + + + + + diff --git a/phpBB/styles/subsilver2/template/mcp_reports.html b/phpBB/styles/subsilver2/template/mcp_reports.html index 72b26e8751..1b6a3b82b6 100644 --- a/phpBB/styles/subsilver2/template/mcp_reports.html +++ b/phpBB/styles/subsilver2/template/mcp_reports.html @@ -7,11 +7,16 @@ - + + + + + + @@ -19,10 +24,17 @@ + + + + + diff --git a/phpBB/styles/subsilver2/template/mcp_topic.html b/phpBB/styles/subsilver2/template/mcp_topic.html index 2b66c8702a..12c0f73b97 100644 --- a/phpBB/styles/subsilver2/template/mcp_topic.html +++ b/phpBB/styles/subsilver2/template/mcp_topic.html @@ -61,9 +61,7 @@ - - - + @@ -81,19 +79,12 @@
    {L_POST_DETAILS}{L_PM}{L_POST_DETAILS}
    {RETURN_QUEUE} | {RETURN_TOPIC_SIMPLE} | {RETURN_POST}{RETURN_REPORTS} | {L_VIEW_POST} | {L_VIEW_TOPIC} | {L_VIEW_FORUM}{RETURN_TOPIC}{RETURN_QUEUE} | {RETURN_TOPIC_SIMPLE} | {RETURN_POST}{RETURN_REPORTS} | {L_VIEW_POST} | {L_VIEW_TOPIC} | {L_VIEW_FORUM}{RETURN_TOPIC}
    {L_POST_SUBJECT}: {L_PM_SUBJECT}{L_POST_SUBJECT}: {POST_SUBJECT} {UNAPPROVED_IMG} {L_POST_UNAPPROVED} {REPORTED_IMG} {L_POST_REPORTED}
    {L_POSTER}: {L_PM_FROM}{L_POSTER}: style="font-weight: bold; color: {POST_AUTHOR_COLOUR}">{POST_AUTHOR}   [ {L_READ_PROFILE} | {L_VIEW_NOTES} | {L_WARN_USER} ]
    {L_POSTED}: {L_SENT_AT}{L_POSTED}: {POST_DATE}
    {L_TO}: + + {to_recipient.NAME}{to_recipient.NAME_FULL}  + +
    {L_BCC}: + + {bcc_recipient.NAME}{bcc_recipient.NAME_FULL}  + +
    {L_PREVIEW}
    {L_DISPLAY_OPTIONS}
    {L_DISPLAY_POSTS}: {S_SELECT_SORT_DAYS} {L_SORT_BY} {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR} {L_FORUM}     {L_ONLY_TOPIC}   {L_DISPLAY_POSTS}: {S_SELECT_SORT_DAYS} {L_SORT_BY} {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR} {L_FORUM}     {L_ONLY_TOPIC}  
     {L_PM}  {L_TO} & {L_BCC}   {L_POST}   {L_AUTHOR}   {L_REPORTER}   {L_REPORT_TIME}   {L_SELECT} 

    {postrow.PM_SUBJECT}

    + {L_PM_FROM}: {postrow.PM_AUTHOR_FULL}
    {postrow.RECIPIENTS}
    + {L_SENT_AT}: {postrow.PM_TIME}

    {postrow.POST_SUBJECT}

    {L_FORUM}: {postrow.FORUM_NAME}{postrow.FORUM_NAME}
    {postrow.POST_AUTHOR_FULL}
    {postrow.POST_TIME}
    {postrow.REPORTER_FULL} {postrow.REPORT_TIME}
    [ {L_VIEW_DETAILS} ]
    {L_DISPLAY_POSTS}: {S_SELECT_SORT_DAYS} {L_SORT_BY} {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR} 
    {L_AUTHOR}{L_MESSAGE}{L_SELECT}{L_TOPIC_REVIEW}: {TOPIC_TITLE}
    {RETURN_TOPIC}
    - checked="checked" /> + {INFO_IMG} - - - - - -
    [ {L_POST_DETAILS} ]
    - - + + @@ -156,4 +148,4 @@
    @@ -120,8 +111,8 @@ @@ -131,6 +122,7 @@
    - {UNAPPROVED_IMG} {L_POST_UNAPPROVED} - {REPORTED_IMG}{L_POST_REPORTED} + {UNAPPROVED_IMG} {L_POST_UNAPPROVED}
    + {REPORTED_IMG} {L_POST_REPORTED}
    {postrow.MINI_POST_IMG} {L_POSTED}: {postrow.POST_DATE}
    checked="checked" />
    - \ No newline at end of file + diff --git a/phpBB/styles/subsilver2/template/memberlist_im.html b/phpBB/styles/subsilver2/template/memberlist_im.html index acbe1fec2f..e8d86128c7 100644 --- a/phpBB/styles/subsilver2/template/memberlist_im.html +++ b/phpBB/styles/subsilver2/template/memberlist_im.html @@ -14,7 +14,7 @@ {L_IM_RECIPIENT}: - {USERNAME} [ {IM_CONTACT} ] {PRESENCE_IMG} + {USERNAME} [ {IM_CONTACT} ] {PRESENCE_IMG} @@ -131,9 +131,9 @@ - {L_CLOSE_WINDOW} {S_FORM_TOKEN} +{L_CLOSE_WINDOW} \ No newline at end of file diff --git a/phpBB/styles/subsilver2/template/memberlist_view.html b/phpBB/styles/subsilver2/template/memberlist_view.html index c4536e4621..9ef2b85878 100644 --- a/phpBB/styles/subsilver2/template/memberlist_view.html +++ b/phpBB/styles/subsilver2/template/memberlist_view.html @@ -51,7 +51,15 @@ - [ {L_ADD_FRIEND} | {L_ADD_FOE}{L_REMOVE_FRIEND}{L_REMOVE_FOE} ] + [ + + {L_REMOVE_FRIEND} + + {L_REMOVE_FOE} + + {L_ADD_FRIEND} | {L_ADD_FOE} + + ] @@ -66,17 +74,17 @@ {L_VISITED}: {VISITED} - + {L_WARNINGS}: - {WARNINGS}
    [ {L_VIEW_NOTES} | {L_WARN_USER} ] + {WARNINGS}
    [ {L_VIEW_NOTES} | {L_WARN_USER} ] {L_TOTAL_POSTS}: {POSTS}
    [{POSTS_PCT} / {POSTS_DAY}]
    [{L_POSTS_IN_QUEUE}]
    [{L_POSTS_IN_QUEUE}] -
    {L_SEARCH_USER_POSTS}
    +
    {L_SEARCH_USER_POSTS} @@ -126,7 +134,7 @@ {L_JABBER}: - {JABBER_IMG}{USER_JABBER_IMG} + {JABBER_IMG}{USER_JABBER_IMG} diff --git a/phpBB/styles/subsilver2/template/overall_header.html b/phpBB/styles/subsilver2/template/overall_header.html index 6c12db897d..5972073011 100644 --- a/phpBB/styles/subsilver2/template/overall_header.html +++ b/phpBB/styles/subsilver2/template/overall_header.html @@ -15,6 +15,15 @@ {META} {SITENAME} • <!-- IF S_IN_MCP -->{L_MCP} • <!-- ELSEIF S_IN_UCP -->{L_UCP} • <!-- ENDIF -->{PAGE_TITLE} + + + + + + + + + + +
    + + + + +
    {L_LANGUAGE}:
    + {S_HIDDEN_FIELDS} +
    + +
    @@ -58,4 +81,4 @@ - \ No newline at end of file + diff --git a/phpBB/styles/subsilver2/template/ucp_groups_manage.html b/phpBB/styles/subsilver2/template/ucp_groups_manage.html index 6ae9816ca8..51e60c8b69 100644 --- a/phpBB/styles/subsilver2/template/ucp_groups_manage.html +++ b/phpBB/styles/subsilver2/template/ucp_groups_manage.html @@ -63,16 +63,19 @@ - + + + + @@ -81,6 +84,7 @@ + @@ -193,7 +197,7 @@

    {L_ADD_USERS}

    -

    {L_ADD_USERS_EXPLAIN}

    +

    {L_ADD_USERS_UCP_EXPLAIN}

    {AVATAR_IMAGE}

     {L_DELETE_AVATAR}

    {L_UPLOAD_AVATAR_URL_EXPLAIN}

    {L_LINK_REMOTE_AVATAR_EXPLAIN}

    {L_LINK_REMOTE_SIZE_EXPLAIN}
    px X px
    diff --git a/phpBB/styles/subsilver2/template/ucp_main_drafts.html b/phpBB/styles/subsilver2/template/ucp_main_drafts.html index 14ae52be53..e61c253b04 100644 --- a/phpBB/styles/subsilver2/template/ucp_main_drafts.html +++ b/phpBB/styles/subsilver2/template/ucp_main_drafts.html @@ -69,7 +69,7 @@
    - + - + diff --git a/phpBB/styles/subsilver2/template/ucp_pm_viewfolder.html b/phpBB/styles/subsilver2/template/ucp_pm_viewfolder.html index 36998f18c1..c86211bc7e 100644 --- a/phpBB/styles/subsilver2/template/ucp_pm_viewfolder.html +++ b/phpBB/styles/subsilver2/template/ucp_pm_viewfolder.html @@ -37,7 +37,7 @@ - +
    diff --git a/phpBB/styles/subsilver2/template/ucp_main_front.html b/phpBB/styles/subsilver2/template/ucp_main_front.html index 4dbe2353ae..fdef0bd949 100644 --- a/phpBB/styles/subsilver2/template/ucp_main_front.html +++ b/phpBB/styles/subsilver2/template/ucp_main_front.html @@ -43,7 +43,7 @@
    {L_TOTAL_POSTS}: {POSTS}
    [{POSTS_PCT} / {POSTS_DAY}]
    {L_SEARCH_YOUR_POSTS}
    {POSTS}
    {POSTS}
    [{POSTS_PCT} / {POSTS_DAY}]
    {L_SEARCH_YOUR_POSTS}
    {POSTS}
    @@ -74,7 +74,7 @@ - {messagerow.ATTACH_ICON_IMG} + {messagerow.ATTACH_ICON_IMG} {L_MESSAGE_REMOVED_FROM_OUTBOX}
    {L_DELETE_MESSAGE} @@ -92,7 +92,7 @@
    - +
    {L_NO_MESSAGES}{L_USER_NEW_PERMISSION_DISALLOWED}{L_NO_MESSAGES}
    diff --git a/phpBB/styles/subsilver2/template/ucp_pm_viewmessage.html b/phpBB/styles/subsilver2/template/ucp_pm_viewmessage.html index b3387681bc..4971506a6d 100644 --- a/phpBB/styles/subsilver2/template/ucp_pm_viewmessage.html +++ b/phpBB/styles/subsilver2/template/ucp_pm_viewmessage.html @@ -93,7 +93,7 @@ - +
    {DELETE_IMG} {REPORT_IMG} {DELETE_IMG}
    diff --git a/phpBB/styles/subsilver2/template/ucp_profile_signature.html b/phpBB/styles/subsilver2/template/ucp_profile_signature.html index 26b0804df1..2b396ea0df 100644 --- a/phpBB/styles/subsilver2/template/ucp_profile_signature.html +++ b/phpBB/styles/subsilver2/template/ucp_profile_signature.html @@ -27,7 +27,7 @@ - + diff --git a/phpBB/styles/subsilver2/template/ucp_register.html b/phpBB/styles/subsilver2/template/ucp_register.html index fd987f2d73..ebcdf2d76b 100644 --- a/phpBB/styles/subsilver2/template/ucp_register.html +++ b/phpBB/styles/subsilver2/template/ucp_register.html @@ -32,11 +32,6 @@ - - - - - @@ -66,6 +61,10 @@ + + + + + - - - - - - - - - - - - - - - + + + + diff --git a/phpBB/styles/subsilver2/template/viewtopic_body.html b/phpBB/styles/subsilver2/template/viewtopic_body.html index b177a15250..8f01c64c0e 100644 --- a/phpBB/styles/subsilver2/template/viewtopic_body.html +++ b/phpBB/styles/subsilver2/template/viewtopic_body.html @@ -118,9 +118,9 @@
    {L_REG_COND}
    {L_ITEMS_REQUIRED}
    {L_USERNAME}:
    {L_USERNAME_EXPLAIN}
    {L_TIMEZONE}:
    {L_ITEMS_REQUIRED}
    @@ -75,24 +74,14 @@ {profile_fields.FIELD}
    {profile_fields.ERROR}
    {L_CONFIRMATION}
    {L_CONFIRM_EXPLAIN}
    {CONFIRM_IMG}
    {L_CONFIRM_CODE}:
    {L_CONFIRM_CODE_EXPLAIN} {L_VC_REFRESH_EXPLAIN}
     
    {L_COPPA_COMPLIANCE}
    {S_HIDDEN_FIELDS} - + {S_FORM_TOKEN} - + @@ -155,7 +155,7 @@ - + @@ -179,6 +179,11 @@ {postrow.POSTER_AVATAR} + + + + + @@ -205,7 +210,7 @@ - +
    {UNAPPROVED_IMG} {L_POST_UNAPPROVED} {REPORTED_IMG} {L_POST_REPORTED}{UNAPPROVED_IMG} {L_POST_UNAPPROVED}
    {REPORTED_IMG} {L_POST_REPORTED}
    @@ -254,7 +259,7 @@ - {postrow.BUMPED_MESSAGE} +

    {postrow.BUMPED_MESSAGE}


    @@ -280,7 +285,7 @@ {L_BACK_TO_TOP} - + @@ -319,6 +324,9 @@
    + + + diff --git a/phpBB/styles/subsilver2/template/viewtopic_print.html b/phpBB/styles/subsilver2/template/viewtopic_print.html index 33d33f9c74..e1521c00a7 100644 --- a/phpBB/styles/subsilver2/template/viewtopic_print.html +++ b/phpBB/styles/subsilver2/template/viewtopic_print.html @@ -24,12 +24,20 @@ td { line-height: 150%; } -.code, -.quote { +.code, .codecontent, +.quote, .quotecontent { + margin: 0 5px 0 5px; + padding: 5px; font-size: smaller; border: black solid 1px; } +.quotetitle { + color: black; + display : block; + font-weight: bold; +} + .forum { font-family: Arial,Helvetica,sans-serif; font-weight: bold; diff --git a/phpBB/styles/subsilver2/theme/images/background.gif b/phpBB/styles/subsilver2/theme/images/background.gif index 158a625620..5c731e4fc2 100644 Binary files a/phpBB/styles/subsilver2/theme/images/background.gif and b/phpBB/styles/subsilver2/theme/images/background.gif differ diff --git a/phpBB/styles/subsilver2/theme/stylesheet.css b/phpBB/styles/subsilver2/theme/stylesheet.css index 62baa33566..ab19231595 100644 --- a/phpBB/styles/subsilver2/theme/stylesheet.css +++ b/phpBB/styles/subsilver2/theme/stylesheet.css @@ -34,12 +34,7 @@ body { } #wrapheader { - min-height: 120px; height: auto !important; - height: 120px; -/* background-image: url('./images/background.gif'); - background-repeat: repeat-x;*/ -/* padding: 0 25px 15px 25px;*/ padding: 0; } @@ -62,10 +57,11 @@ body { } #logodesc { - margin-bottom: 5px; - padding: 5px 25px; - background: #D9DFE4; - border-bottom: 1px solid #4787A7; + background-color: #C1CAD2; + background-image: url('./images/background.gif'); + background-repeat: repeat-x; + background-position: center bottom; + padding: 0 25px 15px 25px; } #menubar { @@ -227,6 +223,7 @@ p.topicdetails { .postapprove img, .postreported img { vertical-align: bottom; + padding-top: 5px; } .postauthor { diff --git a/phpBB/styles/subsilver2/theme/theme.cfg b/phpBB/styles/subsilver2/theme/theme.cfg index 4fe2824a32..57b7fa8c63 100644 --- a/phpBB/styles/subsilver2/theme/theme.cfg +++ b/phpBB/styles/subsilver2/theme/theme.cfg @@ -21,7 +21,7 @@ # General Information about this theme name = subsilver2 copyright = © phpBB Group, 2003 -version = 3.0.5 +version = 3.0.6 # Some configuration options diff --git a/phpBB/ucp.php b/phpBB/ucp.php index 908d4fb89a..994fe064a1 100644 --- a/phpBB/ucp.php +++ b/phpBB/ucp.php @@ -127,8 +127,8 @@ switch ($mode) 'AGREEMENT_TITLE' => $user->lang[$title], 'AGREEMENT_TEXT' => sprintf($user->lang[$message], $config['sitename'], generate_board_url()), 'U_BACK' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login'), - 'L_BACK' => $user->lang['BACK_TO_LOGIN']) - ); + 'L_BACK' => $user->lang['BACK_TO_LOGIN'], + )); page_footer(); @@ -143,6 +143,12 @@ switch ($mode) foreach ($_COOKIE as $cookie_name => $cookie_data) { + // Only delete board cookies, no other ones... + if (strpos($cookie_name, $config['cookie_name'] . '_') !== 0) + { + continue; + } + $cookie_name = str_replace($config['cookie_name'] . '_', '', $cookie_name); // Polls are stored as {cookie_name}_poll_{topic_id}, cookie_name_ got removed, therefore checking for poll_ @@ -186,7 +192,7 @@ switch ($mode) $user_row = $db->sql_fetchrow($result); $db->sql_freeresult($result); - if (!$auth->acl_get('a_switchperm') || !$user_row || $user_id == $user->data['user_id']) + if (!$auth->acl_get('a_switchperm') || !$user_row || $user_id == $user->data['user_id'] || !check_link_hash(request_var('hash', ''), 'switchperm')) { redirect(append_sid("{$phpbb_root_path}index.$phpEx")); } @@ -215,11 +221,6 @@ switch ($mode) $auth->acl_cache($user->data); - $sql = 'UPDATE ' . USERS_TABLE . " - SET user_perm_from = 0 - WHERE user_id = " . $user->data['user_id']; - $db->sql_query($sql); - $sql = 'SELECT username FROM ' . USERS_TABLE . ' WHERE user_id = ' . $user->data['user_perm_from']; diff --git a/phpBB/viewforum.php b/phpBB/viewforum.php index 507ea18d24..95c142d865 100644 --- a/phpBB/viewforum.php +++ b/phpBB/viewforum.php @@ -135,11 +135,14 @@ if ($forum_data['left_id'] != $forum_data['right_id'] - 1) else { $template->assign_var('S_HAS_SUBFORUM', false); - get_moderators($moderators, $forum_id); + if ($config['load_moderators']) + { + get_moderators($moderators, $forum_id); + } } // Dump out the page header and load viewforum template -page_header($user->lang['VIEW_FORUM'] . ' - ' . $forum_data['forum_name']); +page_header($user->lang['VIEW_FORUM'] . ' - ' . $forum_data['forum_name'], true, $forum_id); $template->set_filenames(array( 'body' => 'viewforum_body.html') @@ -163,8 +166,6 @@ if (!$auth->acl_get('f_read', $forum_id)) { $template->assign_vars(array( 'S_NO_READ_ACCESS' => true, - 'S_AUTOLOGIN_ENABLED' => ($config['allow_autologin']) ? true : false, - 'S_LOGIN_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=login') . '&redirect=' . urlencode(str_replace('&', '&', build_url())), )); page_footer(); @@ -176,7 +177,8 @@ if ($mark_read == 'topics') $token = request_var('hash', ''); if (check_link_hash($token, 'global')) { - markread('topics', $forum_id); + // Add 0 to forums array to mark global announcements correctly + markread('topics', array($forum_id, 0)); } $redirect_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id); meta_refresh(3, $redirect_url); @@ -615,8 +617,8 @@ if (sizeof($topic_list)) $view_topic_url_params = 'f=' . (($row['forum_id']) ? $row['forum_id'] : $forum_id) . '&t=' . $topic_id; $view_topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", $view_topic_url_params); - $topic_unapproved = (!$row['topic_approved'] && $auth->acl_get('m_approve', $forum_id)) ? true : false; - $posts_unapproved = ($row['topic_approved'] && $row['topic_replies'] < $row['topic_replies_real'] && $auth->acl_get('m_approve', $forum_id)) ? true : false; + $topic_unapproved = (!$row['topic_approved'] && $auth->acl_get('m_approve', (($row['forum_id']) ? $row['forum_id'] : $forum_id))) ? true : false; + $posts_unapproved = ($row['topic_approved'] && $row['topic_replies'] < $row['topic_replies_real'] && $auth->acl_get('m_approve', (($row['forum_id']) ? $row['forum_id'] : $forum_id))) ? true : false; $u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&mode=' . (($topic_unapproved) ? 'approve_details' : 'unapproved_posts') . "&t=$topic_id", true, $user->session_id) : ''; // Send vars to template diff --git a/phpBB/viewonline.php b/phpBB/viewonline.php index c42eeff57a..5eb2894441 100644 --- a/phpBB/viewonline.php +++ b/phpBB/viewonline.php @@ -187,7 +187,7 @@ while ($row = $db->sql_fetchrow($result)) continue; } - preg_match('#^([a-z/_]+)#i', $row['session_page'], $on_page); + preg_match('#^([a-z0-9/_-]+)#i', $row['session_page'], $on_page); if (!sizeof($on_page)) { $on_page[1] = ''; diff --git a/phpBB/viewtopic.php b/phpBB/viewtopic.php index 2bc8086efe..e7522841e3 100644 --- a/phpBB/viewtopic.php +++ b/phpBB/viewtopic.php @@ -28,6 +28,9 @@ $topic_id = request_var('t', 0); $post_id = request_var('p', 0); $voted_id = request_var('vote_id', array('' => 0)); +$voted_id = (sizeof($voted_id) > 1) ? array_unique($voted_id) : $voted_id; + + $start = request_var('start', 0); $view = request_var('view', ''); @@ -41,6 +44,7 @@ $sort_dir = request_var('sd', $default_sort_dir); $update = request_var('update', false); +$s_can_vote = false; /** * @todo normalize? */ @@ -82,6 +86,7 @@ if ($view && !$post_id) WHERE topic_id = $topic_id " . (($auth->acl_get('m_approve', $forum_id)) ? '' : 'AND post_approved = 1') . " AND post_time > $topic_last_read + AND forum_id = $forum_id ORDER BY post_time ASC"; $result = $db->sql_query_limit($sql, 1); $row = $db->sql_fetchrow($result); @@ -184,6 +189,7 @@ $sql_array = array( // The FROM-Order is quite important here, else t.* columns can not be correctly bound. if ($post_id) { + $sql_array['SELECT'] .= ', p.post_approved'; $sql_array['FROM'][POSTS_TABLE] = 'p'; } @@ -231,7 +237,7 @@ if (!$post_id) } else { - $sql_array['WHERE'] = "p.post_id = $post_id AND t.topic_id = p.topic_id" . ((!$auth->acl_get('m_approve', $forum_id)) ? ' AND p.post_approved = 1' : ''); + $sql_array['WHERE'] = "p.post_id = $post_id AND t.topic_id = p.topic_id"; } $sql_array['WHERE'] .= ' AND (f.forum_id = t.forum_id'; @@ -259,6 +265,7 @@ $result = $db->sql_query($sql); $topic_data = $db->sql_fetchrow($result); $db->sql_freeresult($result); +// link to unapproved post or incorrect link if (!$topic_data) { // If post_id was submitted, we try at least to display the topic as a last resort... @@ -270,9 +277,21 @@ if (!$topic_data) trigger_error('NO_TOPIC'); } +$forum_id = (int) $topic_data['forum_id']; // This is for determining where we are (page) if ($post_id) { + // are we where we are supposed to be? + if (!$topic_data['post_approved'] && !$auth->acl_get('m_approve', $topic_data['forum_id'])) + { + // If post_id was submitted, we try at least to display the topic as a last resort... + if ($topic_id) + { + redirect(append_sid("{$phpbb_root_path}viewtopic.$phpEx", "t=$topic_id" . (($forum_id) ? "&f=$forum_id" : ''))); + } + + trigger_error('NO_TOPIC'); + } if ($post_id == $topic_data['topic_first_post_id'] || $post_id == $topic_data['topic_last_post_id']) { $check_sort = ($post_id == $topic_data['topic_first_post_id']) ? 'd' : 'a'; @@ -303,9 +322,7 @@ if ($post_id) } } -$forum_id = (int) $topic_data['forum_id']; $topic_id = (int) $topic_data['topic_id']; - // $topic_replies = ($auth->acl_get('m_approve', $forum_id)) ? $topic_data['topic_replies_real'] : $topic_data['topic_replies']; @@ -394,7 +411,8 @@ if (!isset($topic_tracking_info)) $limit_days = array(0 => $user->lang['ALL_POSTS'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']); $sort_by_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 's' => $user->lang['SUBJECT']); -$sort_by_sql = array('a' => 'u.username_clean', 't' => 'p.post_time', 's' => 'p.post_subject'); +$sort_by_sql = array('a' => array('u.username_clean', 'p.post_id'), 't' => 'p.post_time', 's' => array('p.post_subject', 'p.post_id')); +$join_user_sql = array('a' => true, 't' => false, 's' => false); $s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = ''; @@ -549,7 +567,10 @@ generate_forum_rules($topic_data); // Moderators $forum_moderators = array(); -get_moderators($forum_moderators, $forum_id); +if ($config['load_moderators']) +{ + get_moderators($forum_moderators, $forum_id); +} // This is only used for print view so ... $server_path = (!$view) ? $phpbb_root_path : generate_board_url() . '/'; @@ -597,7 +618,7 @@ $template->assign_vars(array( 'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED'), 'WARN_IMG' => $user->img('icon_user_warn', 'WARN_USER'), - 'S_IS_LOCKED' =>($topic_data['topic_status'] == ITEM_UNLOCKED) ? false : true, + 'S_IS_LOCKED' => ($topic_data['topic_status'] == ITEM_UNLOCKED && $topic_data['forum_status'] == ITEM_UNLOCKED) ? false : true, 'S_SELECT_SORT_DIR' => $s_sort_dir, 'S_SELECT_SORT_KEY' => $s_sort_key, 'S_SELECT_SORT_DAYS' => $s_limit_days, @@ -612,6 +633,7 @@ $template->assign_vars(array( 'S_DISPLAY_POST_INFO' => ($topic_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_post', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false, 'S_DISPLAY_REPLY_INFO' => ($topic_data['forum_type'] == FORUM_POST && ($auth->acl_get('f_reply', $forum_id) || $user->data['user_id'] == ANONYMOUS)) ? true : false, + 'S_ENABLE_FEEDS_TOPIC' => ($config['feed_topic'] && !phpbb_optionget(FORUM_OPTION_FEED_EXCLUDE, $topic_data['forum_options'])) ? true : false, 'U_TOPIC' => "{$server_path}viewtopic.$phpEx?f=$forum_id&t=$topic_id", 'U_FORUM' => $server_path, @@ -683,13 +705,15 @@ if (!empty($topic_data['poll_start'])) $s_can_vote = ($auth->acl_get('f_vote', $forum_id) && (($topic_data['poll_length'] != 0 && $topic_data['poll_start'] + $topic_data['poll_length'] > time()) || $topic_data['poll_length'] == 0) && $topic_data['topic_status'] != ITEM_LOCKED && - $topic_data['forum_status'] != ITEM_LOCKED) ? true : false; + $topic_data['forum_status'] != ITEM_LOCKED && + (!sizeof($cur_voted_id) || + ($auth->acl_get('f_votechg', $forum_id) && $topic_data['poll_vote_change']))) ? true : false; $s_display_results = (!$s_can_vote || ($s_can_vote && sizeof($cur_voted_id)) || $view == 'viewpoll') ? true : false; if ($update && $s_can_vote) { - if (!sizeof($voted_id) || sizeof($voted_id) > $topic_data['poll_max_options'] || in_array(VOTE_CONVERTED, $cur_voted_id)) + if (!sizeof($voted_id) || sizeof($voted_id) > $topic_data['poll_max_options'] || in_array(VOTE_CONVERTED, $cur_voted_id) || !check_form_key('posting')) { $redirect_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&t=$topic_id&start=$start"); @@ -702,10 +726,14 @@ if (!empty($topic_data['poll_start'])) { $message = 'TOO_MANY_VOTE_OPTIONS'; } - else + else if (in_array(VOTE_CONVERTED, $cur_voted_id)) { $message = 'VOTE_CONVERTED'; } + else + { + $message = 'FORM_INVALID'; + } $message = $user->lang[$message] . '

    ' . sprintf($user->lang['RETURN_TOPIC'], '', ''); trigger_error($message); @@ -858,6 +886,7 @@ if (!empty($topic_data['poll_start'])) // If the user is trying to reach the second half of the topic, fetch it starting from the end $store_reverse = false; $sql_limit = $config['posts_per_page']; +$sql_sort_order = $direction = ''; if ($start > $total_posts / 2) { @@ -869,16 +898,25 @@ if ($start > $total_posts / 2) } // Select the sort order - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'ASC' : 'DESC'); + $direction = (($sort_dir == 'd') ? 'ASC' : 'DESC'); $sql_start = max(0, $total_posts - $sql_limit - $start); } else { // Select the sort order - $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . (($sort_dir == 'd') ? 'DESC' : 'ASC'); + $direction = (($sort_dir == 'd') ? 'DESC' : 'ASC'); $sql_start = $start; } +if (is_array($sort_by_sql[$sort_key])) +{ + $sql_sort_order = implode(' ' . $direction . ', ', $sort_by_sql[$sort_key]) . ' ' . $direction; +} +else +{ + $sql_sort_order = $sort_by_sql[$sort_key] . ' ' . $direction; +} + // Container for user details, only process once $post_list = $user_cache = $id_cache = $attachments = $attach_list = $rowset = $update_count = $post_edit_list = array(); $has_attachments = $display_notice = false; @@ -887,10 +925,10 @@ $i = $i_total = 0; // Go ahead and pull all data for this topic $sql = 'SELECT p.post_id - FROM ' . POSTS_TABLE . ' p' . (($sort_by_sql[$sort_key][0] == 'u') ? ', ' . USERS_TABLE . ' u': '') . " + FROM ' . POSTS_TABLE . ' p' . (($join_user_sql[$sort_key]) ? ', ' . USERS_TABLE . ' u': '') . " WHERE p.topic_id = $topic_id " . ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND p.post_approved = 1' : '') . " - " . (($sort_by_sql[$sort_key][0] == 'u') ? 'AND u.user_id = p.poster_id': '') . " + " . (($join_user_sql[$sort_key]) ? 'AND u.user_id = p.poster_id': '') . " $limit_posts_time ORDER BY $sql_sort_order"; $result = $db->sql_query_limit($sql, $sql_limit, $sql_start); @@ -1092,6 +1130,11 @@ while ($row = $db->sql_fetchrow($result)) 'yim' => ($row['user_yim']) ? 'http://edit.yahoo.com/config/send_webmesg?.target=' . urlencode($row['user_yim']) . '&.src=pg' : '', 'jabber' => ($row['user_jabber'] && $auth->acl_get('u_sendim')) ? append_sid("{$phpbb_root_path}memberlist.$phpEx", "mode=contact&action=jabber&u=$poster_id") : '', 'search' => ($auth->acl_get('u_search')) ? append_sid("{$phpbb_root_path}search.$phpEx", "author_id=$poster_id&sr=posts") : '', + + 'author_full' => get_username_string('full', $poster_id, $row['username'], $row['user_colour']), + 'author_colour' => get_username_string('colour', $poster_id, $row['username'], $row['user_colour']), + 'author_username' => get_username_string('username', $poster_id, $row['username'], $row['user_colour']), + 'author_profile' => get_username_string('profile', $poster_id, $row['username'], $row['user_colour']), ); get_user_rank($row['user_rank'], $row['user_posts'], $user_cache[$poster_id]['rank_title'], $user_cache[$poster_id]['rank_image'], $user_cache[$poster_id]['rank_image_src']); @@ -1150,7 +1193,22 @@ if ($config['load_cpf_viewtopic']) $cp = new custom_profile(); // Grab all profile fields from users in id cache for later use - similar to the poster cache - $profile_fields_cache = $cp->generate_profile_fields_template('grab', $id_cache); + $profile_fields_tmp = $cp->generate_profile_fields_template('grab', $id_cache); + + // filter out fields not to be displayed on viewtopic. Yes, it's a hack, but this shouldn't break any MODs. + $profile_fields_cache = array(); + foreach ($profile_fields_tmp as $profile_user_id => $profile_fields) + { + $profile_fields_cache[$profile_user_id] = array(); + foreach ($profile_fields as $used_ident => $profile_field) + { + if ($profile_field['data']['field_show_on_vt']) + { + $profile_fields_cache[$profile_user_id][$used_ident] = $profile_field; + } + } + } + unset($profile_fields_tmp); } // Generate online information for user @@ -1384,7 +1442,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) // It is safe to grab the username from the user cache array, we are at the last // post and only the topic poster and last poster are allowed to bump. // Admins and mods are bound to the above rules too... - $l_bumped_by = '

    ' . sprintf($user->lang['BUMPED_BY'], $user_cache[$topic_data['topic_bumper']]['username'], $user->format_date($topic_data['topic_last_post_time'], false, true)); + $l_bumped_by = sprintf($user->lang['BUMPED_BY'], $user_cache[$topic_data['topic_bumper']]['username'], $user->format_date($topic_data['topic_last_post_time'], false, true)); } else { @@ -1407,12 +1465,28 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) $s_first_unread = $first_unread = true; } + $edit_allowed = ($user->data['is_registered'] && ($auth->acl_get('m_edit', $forum_id) || ( + $user->data['user_id'] == $poster_id && + $auth->acl_get('f_edit', $forum_id) && + !$row['post_edit_locked'] && + ($row['post_time'] > time() - ($config['edit_time'] * 60) || !$config['edit_time']) + ))); + + $delete_allowed = ($user->data['is_registered'] && ($auth->acl_get('m_delete', $forum_id) || ( + $user->data['user_id'] == $poster_id && + $auth->acl_get('f_delete', $forum_id) && + $topic_data['topic_last_post_id'] == $row['post_id'] && + ($row['post_time'] > time() - ($config['delete_time'] * 60) || !$config['delete_time']) && + // we do not want to allow removal of the last post if a moderator locked it! + !$row['post_edit_locked'] + ))); + // $postrow = array( - 'POST_AUTHOR_FULL' => get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR_COLOUR' => get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'POST_AUTHOR' => get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), - 'U_POST_AUTHOR' => get_username_string('profile', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), + 'POST_AUTHOR_FULL' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_full'] : get_username_string('full', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), + 'POST_AUTHOR_COLOUR' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_colour'] : get_username_string('colour', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), + 'POST_AUTHOR' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_username'] : get_username_string('username', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), + 'U_POST_AUTHOR' => ($poster_id != ANONYMOUS) ? $user_cache[$poster_id]['author_profile'] : get_username_string('profile', $poster_id, $row['username'], $row['user_colour'], $row['post_username']), 'RANK_TITLE' => $user_cache[$poster_id]['rank_title'], 'RANK_IMG' => $user_cache[$poster_id]['rank_image'], @@ -1440,10 +1514,10 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i) 'ONLINE_IMG' => ($poster_id == ANONYMOUS || !$config['load_onlinetrack']) ? '' : (($user_cache[$poster_id]['online']) ? $user->img('icon_user_online', 'ONLINE') : $user->img('icon_user_offline', 'OFFLINE')), 'S_ONLINE' => ($poster_id == ANONYMOUS || !$config['load_onlinetrack']) ? false : (($user_cache[$poster_id]['online']) ? true : false), - 'U_EDIT' => (!$user->data['is_registered']) ? '' : ((($user->data['user_id'] == $poster_id && $auth->acl_get('f_edit', $forum_id) && ($row['post_time'] > time() - ($config['edit_time'] * 60) || !$config['edit_time'])) || $auth->acl_get('m_edit', $forum_id)) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=edit&f=$forum_id&p={$row['post_id']}") : ''), + 'U_EDIT' => ($edit_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=edit&f=$forum_id&p={$row['post_id']}") : '', 'U_QUOTE' => ($auth->acl_get('f_reply', $forum_id)) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=quote&f=$forum_id&p={$row['post_id']}") : '', 'U_INFO' => ($auth->acl_get('m_info', $forum_id)) ? append_sid("{$phpbb_root_path}mcp.$phpEx", "i=main&mode=post_details&f=$forum_id&p=" . $row['post_id'], true, $user->session_id) : '', - 'U_DELETE' => (!$user->data['is_registered']) ? '' : ((($user->data['user_id'] == $poster_id && $auth->acl_get('f_delete', $forum_id) && $topic_data['topic_last_post_id'] == $row['post_id'] && !$row['post_edit_locked'] && ($row['post_time'] > time() - ($config['edit_time'] * 60) || !$config['edit_time'])) || $auth->acl_get('m_delete', $forum_id)) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=delete&f=$forum_id&p={$row['post_id']}") : ''), + 'U_DELETE' => ($delete_allowed) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=delete&f=$forum_id&p={$row['post_id']}") : '', 'U_PROFILE' => $user_cache[$poster_id]['profile'], 'U_SEARCH' => $user_cache[$poster_id]['search'], @@ -1534,13 +1608,34 @@ if (isset($user->data['session_page']) && !$user->data['is_bot'] && (strpos($use } } +// Get last post time for all global announcements +// to keep proper forums tracking +if ($topic_data['topic_type'] == POST_GLOBAL) +{ + $sql = 'SELECT topic_last_post_time as forum_last_post_time + FROM ' . TOPICS_TABLE . ' + WHERE forum_id = 0 + ORDER BY topic_last_post_time DESC'; + $result = $db->sql_query_limit($sql, 1); + $topic_data['forum_last_post_time'] = (int) $db->sql_fetchfield('forum_last_post_time'); + $db->sql_freeresult($result); + + $sql = 'SELECT mark_time as forum_mark_time + FROM ' . FORUMS_TRACK_TABLE . ' + WHERE forum_id = 0 + AND user_id = ' . $user->data['user_id']; + $result = $db->sql_query($sql); + $topic_data['forum_mark_time'] = (int) $db->sql_fetchfield('forum_mark_time'); + $db->sql_freeresult($result); +} + // Only mark topic if it's currently unread. Also make sure we do not set topic tracking back if earlier pages are viewed. if (isset($topic_tracking_info[$topic_id]) && $topic_data['topic_last_post_time'] > $topic_tracking_info[$topic_id] && $max_post_time > $topic_tracking_info[$topic_id]) { - markread('topic', $forum_id, $topic_id, $max_post_time); + markread('topic', (($topic_data['topic_type'] == POST_GLOBAL) ? 0 : $forum_id), $topic_id, $max_post_time); // Update forum info - $all_marked_read = update_forum_tracking_info($forum_id, $topic_data['forum_last_post_time'], (isset($topic_data['forum_mark_time'])) ? $topic_data['forum_mark_time'] : false, false); + $all_marked_read = update_forum_tracking_info((($topic_data['topic_type'] == POST_GLOBAL) ? 0 : $forum_id), $topic_data['forum_last_post_time'], (isset($topic_data['forum_mark_time'])) ? $topic_data['forum_mark_time'] : false, false); } else { @@ -1582,6 +1677,45 @@ else if (!$all_marked_read) } } +// let's set up quick_reply +$s_quick_reply = $user->data['is_registered'] && $config['allow_quick_reply'] && ($topic_data['forum_flags'] & FORUM_FLAG_QUICK_REPLY) && $auth->acl_get('f_reply', $forum_id); + +if ($s_can_vote || $s_quick_reply) +{ + add_form_key('posting'); + + if ($s_quick_reply) + { + $s_attach_sig = $config['allow_sig'] && $user->optionget('attachsig') && $auth->acl_get('f_sigs', $forum_id) && $auth->acl_get('u_sig'); + $s_smilies = $config['allow_smilies'] && $user->optionget('smilies') && $auth->acl_get('f_smilies', $forum_id); + $s_bbcode = $config['allow_bbcode'] && $user->optionget('bbcode') && $auth->acl_get('f_bbcode', $forum_id); + $s_notify = $config['allow_topic_notify'] && $user->data['user_notify']; + + $qr_hidden_fields = array( + 'topic_cur_post_id' => (int) $topic_data['topic_last_post_id'], + 'lastclick' => (int) time(), + 'topic_id' => (int) $topic_data['topic_id'], + 'forum_id' => (int) $forum_id, + ); + + // Originally we use checkboxes and check with isset(), so we only provide them if they would be checked + (!$s_bbcode) ? $qr_hidden_fields['disable_bbcode'] = 1 : true; + (!$s_smilies) ? $qr_hidden_fields['disable_smilies'] = 1 : true; + (!$config['allow_post_links']) ? $qr_hidden_fields['disable_magic_url'] = 1 : true; + ($s_attach_sig) ? $qr_hidden_fields['attach_sig'] = 1 : true; + ($s_notify) ? $qr_hidden_fields['notify'] = 1 : true; + + $template->assign_vars(array( + 'S_QUICK_REPLY' => true, + 'U_QR_ACTION' => append_sid("{$phpbb_root_path}posting.$phpEx", "mode=reply&f=$forum_id&t=$topic_id"), + 'QR_HIDDEN_FIELDS' => build_hidden_fields($qr_hidden_fields), + 'SUBJECT' => 'Re: ' . censor_text($topic_data['topic_title']), + )); + } +} +// now I have the urge to wash my hands :( + + // We overwrite $_REQUEST['f'] if there is no forum specified // to be able to display the correct online list. // One downside is that the user currently viewing this topic/post is not taken into account. @@ -1591,7 +1725,7 @@ if (empty($_REQUEST['f'])) } // Output the page -page_header($user->lang['VIEW_TOPIC'] . ' - ' . $topic_data['topic_title']); +page_header($user->lang['VIEW_TOPIC'] . ' - ' . $topic_data['topic_title'], true, $forum_id); $template->set_filenames(array( 'body' => ($view == 'print') ? 'viewtopic_print.html' : 'viewtopic_body.html')