aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB/includes
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB/includes')
-rw-r--r--phpBB/includes/acp/acp_attachments.php19
-rw-r--r--phpBB/includes/acp/acp_bbcodes.php14
-rw-r--r--phpBB/includes/acp/acp_board.php268
-rw-r--r--phpBB/includes/acp/acp_captcha.php2
-rw-r--r--phpBB/includes/acp/acp_database.php4
-rw-r--r--phpBB/includes/acp/acp_extensions.php60
-rw-r--r--phpBB/includes/acp/acp_forums.php43
-rw-r--r--phpBB/includes/acp/acp_groups.php487
-rw-r--r--phpBB/includes/acp/acp_inactive.php5
-rw-r--r--phpBB/includes/acp/acp_main.php30
-rw-r--r--phpBB/includes/acp/acp_modules.php95
-rw-r--r--phpBB/includes/acp/acp_permission_roles.php44
-rw-r--r--phpBB/includes/acp/acp_permissions.php42
-rw-r--r--phpBB/includes/acp/acp_prune.php40
-rw-r--r--phpBB/includes/acp/acp_ranks.php14
-rw-r--r--phpBB/includes/acp/acp_search.php2
-rw-r--r--phpBB/includes/acp/acp_send_statistics.php2
-rw-r--r--phpBB/includes/acp/acp_styles.php25
-rw-r--r--phpBB/includes/acp/acp_update.php2
-rw-r--r--phpBB/includes/acp/acp_users.php170
-rw-r--r--phpBB/includes/acp/auth.php37
-rw-r--r--phpBB/includes/acp/info/acp_extensions.php4
-rw-r--r--phpBB/includes/acp/info/acp_language.php2
-rw-r--r--phpBB/includes/auth/auth.php1061
-rw-r--r--phpBB/includes/auth/auth_apache.php247
-rw-r--r--phpBB/includes/auth/auth_db.php289
-rw-r--r--phpBB/includes/auth/auth_ldap.php350
-rw-r--r--phpBB/includes/auth/index.htm10
-rw-r--r--phpBB/includes/bbcode.php9
-rw-r--r--phpBB/includes/cache/driver/apc.php75
-rw-r--r--phpBB/includes/cache/driver/base.php23
-rw-r--r--phpBB/includes/cache/driver/eaccelerator.php112
-rw-r--r--phpBB/includes/cache/driver/file.php742
-rw-r--r--phpBB/includes/cache/driver/interface.php143
-rw-r--r--phpBB/includes/cache/driver/memcache.php129
-rw-r--r--phpBB/includes/cache/driver/memory.php441
-rw-r--r--phpBB/includes/cache/driver/null.php154
-rw-r--r--phpBB/includes/cache/driver/redis.php166
-rw-r--r--phpBB/includes/cache/driver/wincache.php78
-rw-r--r--phpBB/includes/cache/driver/xcache.php112
-rw-r--r--phpBB/includes/cache/service.php411
-rw-r--r--phpBB/includes/captcha/captcha_factory.php3
-rw-r--r--phpBB/includes/captcha/captcha_non_gd.php2
-rw-r--r--phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php12
-rw-r--r--phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php2
-rw-r--r--phpBB/includes/class_loader.php170
-rw-r--r--phpBB/includes/config/config.php170
-rw-r--r--phpBB/includes/config/db.php207
-rw-r--r--phpBB/includes/constants.php10
-rw-r--r--phpBB/includes/controller/exception.php24
-rw-r--r--phpBB/includes/controller/helper.php117
-rw-r--r--phpBB/includes/controller/provider.php82
-rw-r--r--phpBB/includes/controller/resolver.php128
-rw-r--r--phpBB/includes/cron/manager.php138
-rw-r--r--phpBB/includes/cron/task/base.php76
-rw-r--r--phpBB/includes/cron/task/core/prune_all_forums.php93
-rw-r--r--phpBB/includes/cron/task/core/prune_forum.php163
-rw-r--r--phpBB/includes/cron/task/core/queue.php82
-rw-r--r--phpBB/includes/cron/task/core/tidy_cache.php76
-rw-r--r--phpBB/includes/cron/task/core/tidy_database.php70
-rw-r--r--phpBB/includes/cron/task/core/tidy_search.php109
-rw-r--r--phpBB/includes/cron/task/core/tidy_sessions.php63
-rw-r--r--phpBB/includes/cron/task/core/tidy_warnings.php84
-rw-r--r--phpBB/includes/cron/task/parametrized.php52
-rw-r--r--phpBB/includes/cron/task/task.php55
-rw-r--r--phpBB/includes/cron/task/wrapper.php108
-rw-r--r--phpBB/includes/datetime.php158
-rw-r--r--phpBB/includes/db/db_tools.php2457
-rw-r--r--phpBB/includes/db/dbal.php1049
-rw-r--r--phpBB/includes/db/firebird.php540
-rw-r--r--phpBB/includes/db/mssql.php456
-rw-r--r--phpBB/includes/db/mssql_odbc.php397
-rw-r--r--phpBB/includes/db/mssqlnative.php643
-rw-r--r--phpBB/includes/db/mysql.php567
-rw-r--r--phpBB/includes/db/mysqli.php568
-rw-r--r--phpBB/includes/db/oracle.php768
-rw-r--r--phpBB/includes/db/postgres.php498
-rw-r--r--phpBB/includes/db/schema_data.php1194
-rw-r--r--phpBB/includes/db/sqlite.php336
-rw-r--r--phpBB/includes/di/extension/config.php83
-rw-r--r--phpBB/includes/di/extension/core.php69
-rw-r--r--phpBB/includes/di/extension/ext.php69
-rw-r--r--phpBB/includes/di/pass/collection_pass.php46
-rw-r--r--phpBB/includes/di/pass/kernel_pass.php68
-rw-r--r--phpBB/includes/di/service_collection.php49
-rw-r--r--phpBB/includes/error_collector.php62
-rw-r--r--phpBB/includes/event/data.php68
-rw-r--r--phpBB/includes/event/dispatcher.php42
-rw-r--r--phpBB/includes/event/extension_subscriber_loader.php46
-rw-r--r--phpBB/includes/event/kernel_exception_subscriber.php85
-rw-r--r--phpBB/includes/event/kernel_request_subscriber.php83
-rw-r--r--phpBB/includes/event/kernel_terminate_subscriber.php43
-rw-r--r--phpBB/includes/extension/base.php57
-rw-r--r--phpBB/includes/extension/exception.php27
-rw-r--r--phpBB/includes/extension/finder.php436
-rw-r--r--phpBB/includes/extension/interface.php65
-rw-r--r--phpBB/includes/extension/manager.php493
-rw-r--r--phpBB/includes/extension/metadata_manager.php338
-rw-r--r--phpBB/includes/extension/provider.php76
-rw-r--r--phpBB/includes/functions.php468
-rw-r--r--phpBB/includes/functions_acp.php67
-rw-r--r--phpBB/includes/functions_admin.php596
-rw-r--r--phpBB/includes/functions_compatibility.php50
-rw-r--r--phpBB/includes/functions_container.php181
-rw-r--r--phpBB/includes/functions_content.php4
-rw-r--r--phpBB/includes/functions_convert.php6
-rw-r--r--phpBB/includes/functions_database_helper.php206
-rw-r--r--phpBB/includes/functions_display.php271
-rw-r--r--phpBB/includes/functions_download.php43
-rw-r--r--phpBB/includes/functions_install.php70
-rw-r--r--phpBB/includes/functions_jabber.php2
-rw-r--r--phpBB/includes/functions_messenger.php172
-rw-r--r--phpBB/includes/functions_module.php38
-rw-r--r--phpBB/includes/functions_posting.php955
-rw-r--r--phpBB/includes/functions_privmsgs.php136
-rw-r--r--phpBB/includes/functions_profile_fields.php18
-rw-r--r--phpBB/includes/functions_upload.php15
-rw-r--r--phpBB/includes/functions_url_matcher.php6
-rw-r--r--phpBB/includes/functions_user.php761
-rw-r--r--phpBB/includes/group_positions.php261
-rw-r--r--phpBB/includes/json_response.php41
-rw-r--r--phpBB/includes/lock/db.php138
-rw-r--r--phpBB/includes/lock/flock.php133
-rw-r--r--phpBB/includes/mcp/info/mcp_queue.php2
-rw-r--r--phpBB/includes/mcp/mcp_forum.php36
-rw-r--r--phpBB/includes/mcp/mcp_front.php4
-rw-r--r--phpBB/includes/mcp/mcp_main.php502
-rw-r--r--phpBB/includes/mcp/mcp_notes.php4
-rw-r--r--phpBB/includes/mcp/mcp_pm_reports.php19
-rw-r--r--phpBB/includes/mcp/mcp_post.php48
-rw-r--r--phpBB/includes/mcp/mcp_queue.php1107
-rw-r--r--phpBB/includes/mcp/mcp_reports.php74
-rw-r--r--phpBB/includes/mcp/mcp_topic.php115
-rw-r--r--phpBB/includes/mcp/mcp_warn.php23
-rw-r--r--phpBB/includes/message_parser.php11
-rw-r--r--phpBB/includes/php/ini.php175
-rw-r--r--phpBB/includes/questionnaire/questionnaire.php2
-rw-r--r--phpBB/includes/request/deactivated_super_global.php121
-rw-r--r--phpBB/includes/request/interface.php139
-rw-r--r--phpBB/includes/request/request.php415
-rw-r--r--phpBB/includes/request/type_cast_helper.php194
-rw-r--r--phpBB/includes/request/type_cast_helper_interface.php63
-rw-r--r--phpBB/includes/search/base.php317
-rw-r--r--phpBB/includes/search/fulltext_mysql.php931
-rw-r--r--phpBB/includes/search/fulltext_native.php1817
-rw-r--r--phpBB/includes/search/fulltext_postgres.php910
-rw-r--r--phpBB/includes/search/fulltext_sphinx.php892
-rw-r--r--phpBB/includes/search/index.htm10
-rw-r--r--phpBB/includes/search/sphinx/config.php288
-rw-r--r--phpBB/includes/search/sphinx/config_comment.php49
-rw-r--r--phpBB/includes/search/sphinx/config_section.php162
-rw-r--r--phpBB/includes/search/sphinx/config_variable.php80
-rw-r--r--phpBB/includes/session.php1521
-rw-r--r--phpBB/includes/sphinxapi.php3424
-rw-r--r--phpBB/includes/style/extension_path_provider.php119
-rw-r--r--phpBB/includes/style/path_provider.php62
-rw-r--r--phpBB/includes/style/path_provider_interface.php42
-rw-r--r--phpBB/includes/style/resource_locator.php348
-rw-r--r--phpBB/includes/style/style.php188
-rw-r--r--phpBB/includes/template/compile.php130
-rw-r--r--phpBB/includes/template/context.php359
-rw-r--r--phpBB/includes/template/filter.php1059
-rw-r--r--phpBB/includes/template/locator.php163
-rw-r--r--phpBB/includes/template/renderer.php35
-rw-r--r--phpBB/includes/template/renderer_eval.php60
-rw-r--r--phpBB/includes/template/renderer_include.php60
-rw-r--r--phpBB/includes/template/template.php484
-rw-r--r--phpBB/includes/ucp/info/ucp_notifications.php35
-rw-r--r--phpBB/includes/ucp/info/ucp_profile.php2
-rw-r--r--phpBB/includes/ucp/ucp_activate.php4
-rw-r--r--phpBB/includes/ucp/ucp_groups.php196
-rw-r--r--phpBB/includes/ucp/ucp_main.php6
-rw-r--r--phpBB/includes/ucp/ucp_notifications.php230
-rw-r--r--phpBB/includes/ucp/ucp_pm_compose.php13
-rw-r--r--phpBB/includes/ucp/ucp_pm_viewmessage.php37
-rw-r--r--phpBB/includes/ucp/ucp_prefs.php86
-rw-r--r--phpBB/includes/ucp/ucp_profile.php164
-rw-r--r--phpBB/includes/ucp/ucp_register.php10
-rw-r--r--phpBB/includes/ucp/ucp_remind.php10
-rw-r--r--phpBB/includes/ucp/ucp_resend.php5
-rw-r--r--phpBB/includes/update_helpers.php112
-rw-r--r--phpBB/includes/user.php857
182 files changed, 7624 insertions, 35340 deletions
diff --git a/phpBB/includes/acp/acp_attachments.php b/phpBB/includes/acp/acp_attachments.php
index 9d6c2d5de1..d0e8ff3882 100644
--- a/phpBB/includes/acp/acp_attachments.php
+++ b/phpBB/includes/acp/acp_attachments.php
@@ -117,8 +117,8 @@ class acp_attachments
'attachment_quota' => array('lang' => 'ATTACH_QUOTA', 'validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true),
'max_filesize' => array('lang' => 'ATTACH_MAX_FILESIZE', 'validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true),
'max_filesize_pm' => array('lang' => 'ATTACH_MAX_PM_FILESIZE','validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true),
- 'max_attachments' => array('lang' => 'MAX_ATTACHMENTS', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => false),
- 'max_attachments_pm' => array('lang' => 'MAX_ATTACHMENTS_PM', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => false),
+ 'max_attachments' => array('lang' => 'MAX_ATTACHMENTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => false),
+ 'max_attachments_pm' => array('lang' => 'MAX_ATTACHMENTS_PM', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => false),
'secure_downloads' => array('lang' => 'SECURE_DOWNLOADS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'secure_allow_deny' => array('lang' => 'SECURE_ALLOW_DENY', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_allow_deny', 'explain' => true),
'secure_allow_empty_referer' => array('lang' => 'SECURE_EMPTY_REFERRER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -128,11 +128,11 @@ class acp_attachments
'legend2' => $l_legend_cat_images,
'img_display_inlined' => array('lang' => 'DISPLAY_INLINED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'img_create_thumbnail' => array('lang' => 'CREATE_THUMBNAIL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'img_max_thumb_width' => array('lang' => 'MAX_THUMB_WIDTH', 'validate' => 'int', 'type' => 'text:7:15', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
- 'img_min_thumb_filesize' => array('lang' => 'MIN_THUMB_FILESIZE', 'validate' => 'int', 'type' => 'text:7:15', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']),
+ 'img_max_thumb_width' => array('lang' => 'MAX_THUMB_WIDTH', 'validate' => 'int:0:999999999999999', 'type' => 'number:0:999999999999999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'img_min_thumb_filesize' => array('lang' => 'MIN_THUMB_FILESIZE', 'validate' => 'int:0:999999999999999', 'type' => 'number:0:999999999999999', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']),
'img_imagick' => array('lang' => 'IMAGICK_PATH', 'validate' => 'string', 'type' => 'text:20:200', 'explain' => true, 'append' => '&nbsp;&nbsp;<span>[ <a href="' . $this->u_action . '&amp;action=imgmagick">' . $user->lang['SEARCH_IMAGICK'] . '</a> ]</span>'),
- 'img_max' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
- 'img_link' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'img_max' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int:0:9999', 'type' => 'dimension:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'img_link' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int:0:9999', 'type' => 'dimension:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
)
);
@@ -1203,8 +1203,8 @@ class acp_attachments
// Just get the files
$sql = 'SELECT a.*, u.username, u.user_colour, t.topic_title
- FROM ' . ATTACHMENTS_TABLE . ' a
- LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = a.poster_id)
+ FROM ' . ATTACHMENTS_TABLE . ' a
+ LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = a.poster_id)
LEFT JOIN ' . TOPICS_TABLE . " t ON (a.topic_id = t.topic_id)
WHERE a.is_orphan = 0
$limit_filetime
@@ -1670,7 +1670,8 @@ class acp_attachments
$size_var = $filesize['si_identifier'];
$value = $filesize['value'];
- return '<input type="text" id="' . $key . '" size="8" maxlength="15" name="config[' . $key . ']" value="' . $value . '" /> <select name="' . $key . '">' . size_select_options($size_var) . '</select>';
+ // size="8" and maxlength="15" attributes as a fallback for browsers that do not support type="number" yet.
+ return '<input type="number" id="' . $key . '" size="8" maxlength="15" min="0" name="config[' . $key . ']" value="' . $value . '" /> <select name="' . $key . '">' . size_select_options($size_var) . '</select>';
}
/**
diff --git a/phpBB/includes/acp/acp_bbcodes.php b/phpBB/includes/acp/acp_bbcodes.php
index e537d7a8b9..9c430b5a0b 100644
--- a/phpBB/includes/acp/acp_bbcodes.php
+++ b/phpBB/includes/acp/acp_bbcodes.php
@@ -112,8 +112,8 @@ class acp_bbcodes
{
$template->assign_block_vars('token', array(
'TOKEN' => '{' . $token . '}',
- 'EXPLAIN' => $token_explain)
- );
+ 'EXPLAIN' => ($token === 'LOCAL_URL') ? sprintf($token_explain, generate_board_url() . '/') : $token_explain,
+ ));
}
return;
@@ -347,6 +347,9 @@ class acp_bbcodes
'LOCAL_URL' => array(
'!(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('relative_url')) . ')!e' => "\$this->bbcode_specialchars('$1')"
),
+ 'RELATIVE_URL' => array(
+ '!(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('relative_url')) . ')!e' => "\$this->bbcode_specialchars('$1')"
+ ),
'EMAIL' => array(
'!(' . get_preg_expression('email') . ')!ie' => "\$this->bbcode_specialchars('$1')"
),
@@ -373,6 +376,7 @@ class acp_bbcodes
$sp_tokens = array(
'URL' => '(?i)((?:' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('url')) . ')|(?:' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('www_url')) . '))(?-i)',
'LOCAL_URL' => '(?i)(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('relative_url')) . ')(?-i)',
+ 'RELATIVE_URL' => '(?i)(' . str_replace(array('!', '\#'), array('\!', '#'), get_preg_expression('relative_url')) . ')(?-i)',
'EMAIL' => '(' . get_preg_expression('email') . ')',
'TEXT' => '(.*?)',
'SIMPLETEXT' => '([a-zA-Z0-9-+.,_ ]+)',
@@ -429,7 +433,11 @@ class acp_bbcodes
$fp_replace = str_replace($token, $replace, $fp_replace);
$sp_match = str_replace(preg_quote($token, '!'), $sp_tokens[$token_type], $sp_match);
- $sp_replace = str_replace($token, '${' . ($n + 1) . '}', $sp_replace);
+
+ // Prepend the board url to local relative links
+ $replace_prepend = ($token_type === 'LOCAL_URL') ? generate_board_url() . '/' : '';
+
+ $sp_replace = str_replace($token, $replace_prepend . '${' . ($n + 1) . '}', $sp_replace);
}
$fp_match = '!' . $fp_match . '!' . $modifiers;
diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php
index 322e1c55d8..12e2a1bf72 100644
--- a/phpBB/includes/acp/acp_board.php
+++ b/phpBB/includes/acp/acp_board.php
@@ -28,7 +28,7 @@ class acp_board
{
global $db, $user, $auth, $template;
global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
- global $cache;
+ global $cache, $phpbb_container;
$user->add_lang('acp/board');
@@ -53,8 +53,9 @@ class acp_board
'legend1' => 'ACP_BOARD_SETTINGS',
'sitename' => array('lang' => 'SITE_NAME', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => false),
'site_desc' => array('lang' => 'SITE_DESC', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => false),
- 'site_home_url' => array('lang' => 'SITE_HOME_URL', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true),
+ 'site_home_url' => array('lang' => 'SITE_HOME_URL', 'validate' => 'string', 'type' => 'url:40:255', 'explain' => true),
'site_home_text' => array('lang' => 'SITE_HOME_TEXT', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true),
+ 'board_index_text' => array('lang' => 'BOARD_INDEX_TEXT', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true),
'board_disable' => array('lang' => 'DISABLE_BOARD', 'validate' => 'bool', 'type' => 'custom', 'method' => 'board_disable', 'explain' => true),
'board_disable_msg' => false,
'default_lang' => array('lang' => 'DEFAULT_LANGUAGE', 'validate' => 'lang', 'type' => 'select', 'function' => 'language_select', 'params' => array('{CONFIG_VALUE}'), 'explain' => false),
@@ -64,7 +65,7 @@ class acp_board
'override_user_style' => array('lang' => 'OVERRIDE_STYLE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'legend2' => 'WARNINGS',
- 'warnings_expire_days' => array('lang' => 'WARNINGS_EXPIRE', 'validate' => 'int', 'type' => 'text:3:4', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
+ 'warnings_expire_days' => array('lang' => 'WARNINGS_EXPIRE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
'legend3' => 'ACP_SUBMIT_CHANGES',
)
@@ -107,6 +108,23 @@ class acp_board
break;
case 'avatar':
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_all_drivers();
+
+ $avatar_vars = array();
+ foreach ($avatar_drivers as $current_driver)
+ {
+ $driver = $phpbb_avatar_manager->get_driver($current_driver, false);
+
+ /*
+ * First grab the settings for enabling/disabling the avatar
+ * driver and afterwards grab additional settings the driver
+ * might have.
+ */
+ $avatar_vars += $phpbb_avatar_manager->get_avatar_settings($driver);
+ $avatar_vars += $driver->prepare_form_acp($user);
+ }
+
$display_vars = array(
'title' => 'ACP_AVATAR_SETTINGS',
'vars' => array(
@@ -118,17 +136,15 @@ class acp_board
'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']),
- 'avatar_path' => array('lang' => 'AVATAR_STORAGE_PATH', 'validate' => 'rwpath', 'type' => 'text:20:255', 'explain' => true),
- 'avatar_gallery_path' => array('lang' => 'AVATAR_GALLERY_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true),
+ 'avatar_min' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:0', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'avatar_max' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:0', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
)
);
+
+ if (!empty($avatar_vars))
+ {
+ $display_vars['vars'] += $avatar_vars;
+ }
break;
case 'message':
@@ -138,11 +154,11 @@ class acp_board
'vars' => array(
'legend1' => 'GENERAL_SETTINGS',
'allow_privmsg' => array('lang' => 'BOARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'pm_max_boxes' => array('lang' => 'BOXES_MAX', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true),
- 'pm_max_msgs' => array('lang' => 'BOXES_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true),
+ 'pm_max_boxes' => array('lang' => 'BOXES_MAX', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'pm_max_msgs' => array('lang' => 'BOXES_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
'full_folder_action' => array('lang' => 'FULL_FOLDER_ACTION', 'validate' => 'int', 'type' => 'select', 'method' => 'full_folder_select', 'explain' => true),
- 'pm_edit_time' => array('lang' => 'PM_EDIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
- 'pm_max_recipients' => array('lang' => 'PM_MAX_RECIPIENTS', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true),
+ 'pm_edit_time' => array('lang' => 'PM_EDIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
+ 'pm_max_recipients' => array('lang' => 'PM_MAX_RECIPIENTS', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true),
'legend2' => 'GENERAL_OPTIONS',
'allow_mass_pm' => array('lang' => 'ALLOW_MASS_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
@@ -179,24 +195,24 @@ class acp_board
'legend2' => 'POSTING',
'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']),
+ 'edit_time' => array('lang' => 'EDIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
+ 'delete_time' => array('lang' => 'DELETE_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', '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']),
+ 'flood_interval' => array('lang' => 'FLOOD_INTERVAL', 'validate' => 'int:0:9999999999', 'type' => 'number:0:9999999999', '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:1', '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']),
+ 'topics_per_page' => array('lang' => 'TOPICS_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false),
+ 'posts_per_page' => array('lang' => 'POSTS_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false),
+ 'smilies_per_page' => array('lang' => 'SMILIES_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false),
+ 'hot_threshold' => array('lang' => 'HOT_THRESHOLD', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_poll_options' => array('lang' => 'MAX_POLL_OPTIONS', 'validate' => 'int:2:127', 'type' => 'number:2:127', 'explain' => false),
+ 'max_post_chars' => array('lang' => 'CHAR_LIMIT', 'validate' => 'int:0:999999', 'type' => 'number:0:999999', 'explain' => true),
+ 'min_post_chars' => array('lang' => 'MIN_CHAR_LIMIT', 'validate' => 'int:1:999999', 'type' => 'number:1:999999', 'explain' => true),
+ 'max_post_smilies' => array('lang' => 'SMILIES_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_post_urls' => array('lang' => 'MAX_POST_URLS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_post_font_size' => array('lang' => 'MAX_POST_FONT_SIZE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' %'),
+ 'max_quote_depth' => array('lang' => 'QUOTE_DEPTH_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_post_img_width' => array('lang' => 'MAX_POST_IMG_WIDTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'max_post_img_height' => array('lang' => 'MAX_POST_IMG_HEIGHT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
'legend3' => 'ACP_SUBMIT_CHANGES',
)
@@ -216,12 +232,12 @@ class acp_board
'allow_sig_links' => array('lang' => 'ALLOW_SIG_LINKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'legend2' => 'GENERAL_SETTINGS',
- 'max_sig_chars' => array('lang' => 'MAX_SIG_LENGTH', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true),
- 'max_sig_urls' => array('lang' => 'MAX_SIG_URLS', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true),
- 'max_sig_font_size' => array('lang' => 'MAX_SIG_FONT_SIZE', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' %'),
- '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']),
+ 'max_sig_chars' => array('lang' => 'MAX_SIG_LENGTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_sig_urls' => array('lang' => 'MAX_SIG_URLS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_sig_font_size' => array('lang' => 'MAX_SIG_FONT_SIZE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' %'),
+ 'max_sig_smilies' => array('lang' => 'MAX_SIG_SMILIES', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_sig_img_width' => array('lang' => 'MAX_SIG_IMG_WIDTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'max_sig_img_height' => array('lang' => 'MAX_SIG_IMG_HEIGHT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
'legend3' => 'ACP_SUBMIT_CHANGES',
)
@@ -237,20 +253,20 @@ 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' => 'select', '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_post_limit' => array('lang' => 'NEW_MEMBER_POST_LIMIT', 'validate' => 'int:0:255', 'type' => 'number:0:255', '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),
'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true),
- 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
+ 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
'legend2' => 'GENERAL_OPTIONS',
'allow_namechange' => array('lang' => 'ALLOW_NAME_CHANGE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'allow_emailreuse' => array('lang' => 'ALLOW_EMAIL_REUSE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'enable_confirm' => array('lang' => 'VISUAL_CONFIRM_REG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true),
- 'max_reg_attempts' => array('lang' => 'REG_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true),
+ 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true),
+ 'max_reg_attempts' => array('lang' => 'REG_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
'legend3' => 'COPPA',
'coppa_enable' => array('lang' => 'ENABLE_COPPA', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -272,13 +288,13 @@ class acp_board
'feed_http_auth' => array('lang' => 'ACP_FEED_HTTP_AUTH', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true),
'legend2' => 'ACP_FEED_POST_BASED',
- 'feed_limit_post' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5', 'type' => 'text:3:4', 'explain' => true),
+ 'feed_limit_post' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5:9999', 'type' => 'number:5:9999', 'explain' => true),
'feed_overall' => array('lang' => 'ACP_FEED_OVERALL', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ),
'feed_forum' => array('lang' => 'ACP_FEED_FORUM', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ),
'feed_topic' => array('lang' => 'ACP_FEED_TOPIC', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ),
'legend3' => 'ACP_FEED_TOPIC_BASED',
- 'feed_limit_topic' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5', 'type' => 'text:3:4', 'explain' => true),
+ 'feed_limit_topic' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5:9999', 'type' => 'number:5:9999', 'explain' => true),
'feed_topics_new' => array('lang' => 'ACP_FEED_TOPICS_NEW', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ),
'feed_topics_active' => array('lang' => 'ACP_FEED_TOPICS_ACTIVE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ),
'feed_news_id' => array('lang' => 'ACP_FEED_NEWS', 'validate' => 'string', 'type' => 'custom', 'method' => 'select_news_forums', 'explain' => true),
@@ -308,12 +324,13 @@ class acp_board
'title' => 'ACP_LOAD_SETTINGS',
'vars' => array(
'legend1' => 'GENERAL_SETTINGS',
- 'limit_load' => array('lang' => 'LIMIT_LOAD', 'validate' => 'string', 'type' => 'text:4:4', 'explain' => true),
- 'session_length' => array('lang' => 'SESSION_LENGTH', 'validate' => 'int:60', 'type' => 'text:5:10', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
- 'active_sessions' => array('lang' => 'LIMIT_SESSIONS', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true),
- 'load_online_time' => array('lang' => 'ONLINE_LENGTH', 'validate' => 'int:0', 'type' => 'text:4:3', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
+ 'limit_load' => array('lang' => 'LIMIT_LOAD', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'session_length' => array('lang' => 'SESSION_LENGTH', 'validate' => 'int:60:9999999999', 'type' => 'number:60:9999999999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
+ 'active_sessions' => array('lang' => 'LIMIT_SESSIONS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'load_online_time' => array('lang' => 'ONLINE_LENGTH', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
'legend2' => 'GENERAL_OPTIONS',
+ 'load_notifications' => array('lang' => 'LOAD_NOTIFICATIONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'load_db_track' => array('lang' => 'YES_POST_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'load_db_lastread' => array('lang' => 'YES_READ_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'load_anon_lastread' => array('lang' => 'YES_ANON_READ_MARKING', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -367,7 +384,7 @@ class acp_board
'force_server_vars' => array('lang' => 'FORCE_SERVER_VARS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'server_protocol' => array('lang' => 'SERVER_PROTOCOL', 'validate' => 'string', 'type' => 'text:10:10', 'explain' => true),
'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),
+ 'server_port' => array('lang' => 'SERVER_PORT', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true),
'script_path' => array('lang' => 'SCRIPT_PATH', 'validate' => 'script_path', 'type' => 'text::255', 'explain' => true),
'legend4' => 'ACP_SUBMIT_CHANGES',
@@ -381,7 +398,8 @@ class acp_board
'vars' => array(
'legend1' => 'ACP_SECURITY_SETTINGS',
'allow_autologin' => array('lang' => 'ALLOW_AUTOLOGIN', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'max_autologin_time' => array('lang' => 'AUTOLOGIN_LENGTH', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
+ 'allow_password_reset' => array('lang' => 'ALLOW_PASSWORD_RESET', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
+ 'max_autologin_time' => array('lang' => 'AUTOLOGIN_LENGTH', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
'ip_check' => array('lang' => 'IP_VALID', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_ip_check', 'explain' => true),
'browser_check' => array('lang' => 'BROWSER_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'forwarded_for_check' => array('lang' => 'FORWARDED_FOR_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -391,13 +409,13 @@ class acp_board
'max_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:8:255', 'type' => false, 'method' => false, 'explain' => false,),
'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:1', 'type' => 'custom', 'method' => 'password_length', 'explain' => true),
'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true),
- 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
- 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true),
- 'ip_login_limit_max' => array('lang' => 'IP_LOGIN_LIMIT_MAX', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true),
- 'ip_login_limit_time' => array('lang' => 'IP_LOGIN_LIMIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
+ 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
+ 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true),
+ 'ip_login_limit_max' => array('lang' => 'IP_LOGIN_LIMIT_MAX', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true),
+ 'ip_login_limit_time' => array('lang' => 'IP_LOGIN_LIMIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
'ip_login_limit_use_forwarded' => array('lang' => 'IP_LOGIN_LIMIT_USE_FORWARDED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'tpl_allow_php' => array('lang' => 'TPL_ALLOW_PHP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'form_token_lifetime' => array('lang' => 'FORM_TIME_MAX', 'validate' => 'int:-1', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
+ 'form_token_lifetime' => array('lang' => 'FORM_TIME_MAX', 'validate' => 'int:-1:99999', 'type' => 'number:-1:99999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
'form_token_sid_guests' => array('lang' => 'FORM_SID_GUESTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
)
@@ -412,16 +430,16 @@ class acp_board
'email_enable' => array('lang' => 'ENABLE_EMAIL', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true),
'board_email_form' => array('lang' => 'BOARD_EMAIL_FORM', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true),
'email_function_name' => array('lang' => 'EMAIL_FUNCTION_NAME', 'validate' => 'string', 'type' => 'text:20:50', 'explain' => true),
- 'email_package_size' => array('lang' => 'EMAIL_PACKAGE_SIZE', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true),
- 'board_contact' => array('lang' => 'CONTACT_EMAIL', 'validate' => 'string', 'type' => 'text:25:100', 'explain' => true),
- 'board_email' => array('lang' => 'ADMIN_EMAIL', 'validate' => 'string', 'type' => 'text:25:100', 'explain' => true),
+ 'email_package_size' => array('lang' => 'EMAIL_PACKAGE_SIZE', 'validate' => 'int:0', 'type' => 'number:0:99999', 'explain' => true),
+ 'board_contact' => array('lang' => 'CONTACT_EMAIL', 'validate' => 'email', 'type' => 'email:25:100', 'explain' => true),
+ 'board_email' => array('lang' => 'ADMIN_EMAIL', 'validate' => 'email', 'type' => 'email:25:100', 'explain' => true),
'board_email_sig' => array('lang' => 'EMAIL_SIG', 'validate' => 'string', 'type' => 'textarea:5:30', 'explain' => true),
'board_hide_emails' => array('lang' => 'BOARD_HIDE_EMAILS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'legend2' => 'SMTP_SETTINGS',
'smtp_delivery' => array('lang' => 'USE_SMTP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'smtp_host' => array('lang' => 'SMTP_SERVER', 'validate' => 'string', 'type' => 'text:25:50', 'explain' => false),
- 'smtp_port' => array('lang' => 'SMTP_PORT', 'validate' => 'int:0', 'type' => 'text:4:5', 'explain' => true),
+ 'smtp_port' => array('lang' => 'SMTP_PORT', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', '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),
@@ -504,84 +522,54 @@ class acp_board
if ($mode == 'auth')
{
// Retrieve a list of auth plugins and check their config values
- $auth_plugins = array();
+ $auth_providers = $phpbb_container->get('auth.provider_collection');
- $dp = @opendir($phpbb_root_path . 'includes/auth');
-
- if ($dp)
+ $updated_auth_settings = false;
+ $old_auth_config = array();
+ foreach ($auth_providers as $provider)
{
- while (($file = readdir($dp)) !== false)
+ if ($fields = $provider->acp())
{
- if (preg_match('#^auth_(.*?)\.' . $phpEx . '$#', $file))
+ // Check if we need to create config fields for this plugin and save config when submit was pressed
+ foreach ($fields as $field)
{
- $auth_plugins[] = basename(preg_replace('#^auth_(.*?)\.' . $phpEx . '$#', '\1', $file));
- }
- }
- closedir($dp);
+ if (!isset($config[$field]))
+ {
+ set_config($field, '');
+ }
- sort($auth_plugins);
- }
+ if (!isset($cfg_array[$field]) || strpos($field, 'legend') !== false)
+ {
+ continue;
+ }
- $updated_auth_settings = false;
- $old_auth_config = array();
- foreach ($auth_plugins as $method)
- {
- if ($method && file_exists($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx))
- {
- include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
+ $old_auth_config[$field] = $this->new_config[$field];
+ $config_value = $cfg_array[$field];
+ $this->new_config[$field] = $config_value;
- $method = 'acp_' . $method;
- if (function_exists($method))
- {
- if ($fields = $method($this->new_config))
+ if ($submit)
{
- // Check if we need to create config fields for this plugin and save config when submit was pressed
- foreach ($fields['config'] as $field)
- {
- if (!isset($config[$field]))
- {
- set_config($field, '');
- }
-
- if (!isset($cfg_array[$field]) || strpos($field, 'legend') !== false)
- {
- continue;
- }
-
- $old_auth_config[$field] = $this->new_config[$field];
- $config_value = $cfg_array[$field];
- $this->new_config[$field] = $config_value;
-
- if ($submit)
- {
- $updated_auth_settings = true;
- set_config($field, $config_value);
- }
- }
+ $updated_auth_settings = true;
+ set_config($field, $config_value);
}
- unset($fields);
}
}
+ unset($fields);
}
if ($submit && (($cfg_array['auth_method'] != $this->new_config['auth_method']) || $updated_auth_settings))
{
$method = basename($cfg_array['auth_method']);
- if ($method && in_array($method, $auth_plugins))
+ if (array_key_exists('auth.provider.' . $method, $auth_providers))
{
- include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
-
- $method = 'init_' . $method;
- if (function_exists($method))
+ $provider = $auth_providers['auth.provider.' . $method];
+ if ($error = $provider->init())
{
- if ($error = $method())
+ foreach ($old_auth_config as $config_name => $config_value)
{
- foreach ($old_auth_config as $config_name => $config_value)
- {
- set_config($config_name, $config_value);
- }
- trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
+ set_config($config_name, $config_value);
}
+ trigger_error($error . adm_back_link($this->u_action), E_USER_WARNING);
}
set_config('auth_method', basename($cfg_array['auth_method']));
}
@@ -665,23 +653,15 @@ class acp_board
{
$template->assign_var('S_AUTH', true);
- foreach ($auth_plugins as $method)
+ foreach ($auth_providers as $provider)
{
- if ($method && file_exists($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx))
+ $auth_tpl = $provider->get_acp_template($this->new_config);
+ if ($auth_tpl)
{
- $method = 'acp_' . $method;
- if (function_exists($method))
- {
- $fields = $method($this->new_config);
-
- if ($fields['tpl'])
- {
- $template->assign_block_vars('auth_tpl', array(
- 'TPL' => $fields['tpl'])
- );
- }
- unset($fields);
- }
+ $template->assign_vars($auth_tpl['TEMPLATE_VARS']);
+ $template->assign_block_vars('auth_tpl', array(
+ 'TEMPLATE_FILE' => $auth_tpl['TEMPLATE_FILE'],
+ ));
}
}
}
@@ -692,25 +672,19 @@ class acp_board
*/
function select_auth_method($selected_method, $key = '')
{
- global $phpbb_root_path, $phpEx;
+ global $phpbb_root_path, $phpEx, $phpbb_container;
$auth_plugins = array();
+ $auth_providers = $phpbb_container->get('auth.provider_collection');
- $dp = @opendir($phpbb_root_path . 'includes/auth');
-
- if (!$dp)
- {
- return '';
- }
-
- while (($file = readdir($dp)) !== false)
+ foreach ($auth_providers as $key => $value)
{
- if (preg_match('#^auth_(.*?)\.' . $phpEx . '$#', $file))
+ if (!($value instanceof phpbb_auth_provider_interface))
{
- $auth_plugins[] = preg_replace('#^auth_(.*?)\.' . $phpEx . '$#', '\1', $file);
+ continue;
}
+ $auth_plugins[] = str_replace('auth.provider.', '', $key);
}
- closedir($dp);
sort($auth_plugins);
@@ -787,7 +761,7 @@ class acp_board
{
$act_ary['ACC_USER'] = USER_ACTIVATION_SELF;
$act_ary['ACC_ADMIN'] = USER_ACTIVATION_ADMIN;
- }
+ }
$act_options = '';
foreach ($act_ary as $key => $value)
@@ -806,7 +780,7 @@ class acp_board
{
global $user;
- return '<input id="' . $key . '" type="text" size="3" maxlength="3" name="config[min_name_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . '&nbsp;&nbsp;<input type="text" size="3" maxlength="3" name="config[max_name_chars]" value="' . $this->new_config['max_name_chars'] . '" /> ' . $user->lang['MAX_CHARS'];
+ return '<input id="' . $key . '" type="number" size="3" maxlength="3" min="1" max="999" name="config[min_name_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . '&nbsp;&nbsp;<input type="number" size="3" maxlength="3" min="8" max="180" name="config[max_name_chars]" value="' . $this->new_config['max_name_chars'] . '" /> ' . $user->lang['MAX_CHARS'];
}
/**
@@ -834,7 +808,7 @@ class acp_board
{
global $user;
- return '<input id="' . $key . '" type="text" size="3" maxlength="3" name="config[min_pass_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . '&nbsp;&nbsp;<input type="text" size="3" maxlength="3" name="config[max_pass_chars]" value="' . $this->new_config['max_pass_chars'] . '" /> ' . $user->lang['MAX_CHARS'];
+ return '<input id="' . $key . '" type="number" size="3" maxlength="3" min="1" max="999" name="config[min_pass_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . '&nbsp;&nbsp;<input type="number" size="3" maxlength="3" min="8" max="255" name="config[max_pass_chars]" value="' . $this->new_config['max_pass_chars'] . '" /> ' . $user->lang['MAX_CHARS'];
}
/**
diff --git a/phpBB/includes/acp/acp_captcha.php b/phpBB/includes/acp/acp_captcha.php
index c7c64ae56b..1a083c20ac 100644
--- a/phpBB/includes/acp/acp_captcha.php
+++ b/phpBB/includes/acp/acp_captcha.php
@@ -124,6 +124,8 @@ class acp_captcha
'CAPTCHA_PREVIEW_TPL' => $demo_captcha->get_demo_template($id),
'S_CAPTCHA_HAS_CONFIG' => $demo_captcha->has_config(),
'CAPTCHA_SELECT' => $captcha_select,
+
+ 'U_ACTION' => $this->u_action,
));
}
}
diff --git a/phpBB/includes/acp/acp_database.php b/phpBB/includes/acp/acp_database.php
index ebcbd28a87..5d191b3d0f 100644
--- a/phpBB/includes/acp/acp_database.php
+++ b/phpBB/includes/acp/acp_database.php
@@ -28,10 +28,6 @@ class acp_database
global $cache, $db, $user, $auth, $template, $table_prefix;
global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
- if (!class_exists('phpbb_db_tools'))
- {
- require($phpbb_root_path . 'includes/db/db_tools.' . $phpEx);
- }
$this->db_tools = new phpbb_db_tools($db);
$user->add_lang('acp/database');
diff --git a/phpBB/includes/acp/acp_extensions.php b/phpBB/includes/acp/acp_extensions.php
index a0bcf62ecc..379e779c2c 100644
--- a/phpBB/includes/acp/acp_extensions.php
+++ b/phpBB/includes/acp/acp_extensions.php
@@ -37,13 +37,17 @@ class acp_extensions
$this->template = $template;
$this->user = $user;
- $user->add_lang(array('install', 'acp/extensions'));
+ $user->add_lang(array('install', 'acp/extensions', 'migrator'));
$this->page_title = 'ACP_EXTENSIONS';
$action = $request->variable('action', 'list');
$ext_name = $request->variable('ext_name', '');
+ // What is a safe limit of execution time? Half the max execution time should be safe.
+ $safe_time_limit = (ini_get('max_execution_time') / 2);
+ $start_time = time();
+
// Cancel action
if ($request->is_set_post('cancel'))
{
@@ -54,7 +58,7 @@ class acp_extensions
// If they've specified an extension, let's load the metadata manager and validate it.
if ($ext_name)
{
- $md_manager = new phpbb_extension_metadata_manager($ext_name, $db, $phpbb_extension_manager, $phpbb_root_path, ".$phpEx", $template, $config);
+ $md_manager = new phpbb_extension_metadata_manager($ext_name, $config, $phpbb_extension_manager, $template, $phpbb_root_path);
try
{
@@ -81,7 +85,7 @@ class acp_extensions
case 'enable_pre':
if (!$md_manager->validate_enable())
{
- trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action));
+ trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if ($phpbb_extension_manager->enabled($ext_name))
@@ -100,14 +104,25 @@ class acp_extensions
case 'enable':
if (!$md_manager->validate_enable())
{
- trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action));
+ trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- if ($phpbb_extension_manager->enable_step($ext_name))
+ try
{
- $template->assign_var('S_NEXT_STEP', true);
-
- meta_refresh(0, $this->u_action . '&amp;action=enable&amp;ext_name=' . urlencode($ext_name));
+ while ($phpbb_extension_manager->enable_step($ext_name))
+ {
+ // Are we approaching the time limit? If so we want to pause the update and continue after refreshing
+ if ((time() - $start_time) >= $safe_time_limit)
+ {
+ $template->assign_var('S_NEXT_STEP', true);
+
+ meta_refresh(0, $this->u_action . '&amp;action=enable&amp;ext_name=' . urlencode($ext_name));
+ }
+ }
+ }
+ catch (phpbb_db_migration_exception $e)
+ {
+ $template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($user));
}
$this->tpl_name = 'acp_ext_enable';
@@ -132,11 +147,15 @@ class acp_extensions
break;
case 'disable':
- if ($phpbb_extension_manager->disable_step($ext_name))
+ while ($phpbb_extension_manager->disable_step($ext_name))
{
- $template->assign_var('S_NEXT_STEP', true);
+ // Are we approaching the time limit? If so we want to pause the update and continue after refreshing
+ if ((time() - $start_time) >= $safe_time_limit)
+ {
+ $template->assign_var('S_NEXT_STEP', true);
- meta_refresh(0, $this->u_action . '&amp;action=disable&amp;ext_name=' . urlencode($ext_name));
+ meta_refresh(0, $this->u_action . '&amp;action=disable&amp;ext_name=' . urlencode($ext_name));
+ }
}
$this->tpl_name = 'acp_ext_disable';
@@ -156,11 +175,22 @@ class acp_extensions
break;
case 'purge':
- if ($phpbb_extension_manager->purge_step($ext_name))
+ try
{
- $template->assign_var('S_NEXT_STEP', true);
-
- meta_refresh(0, $this->u_action . '&amp;action=purge&amp;ext_name=' . urlencode($ext_name));
+ while ($phpbb_extension_manager->purge_step($ext_name))
+ {
+ // Are we approaching the time limit? If so we want to pause the update and continue after refreshing
+ if ((time() - $start_time) >= $safe_time_limit)
+ {
+ $template->assign_var('S_NEXT_STEP', true);
+
+ meta_refresh(0, $this->u_action . '&amp;action=purge&amp;ext_name=' . urlencode($ext_name));
+ }
+ }
+ }
+ catch (phpbb_db_migration_exception $e)
+ {
+ $template->assign_var('MIGRATOR_ERROR', $e->getLocalisedMessage($user));
}
$this->tpl_name = 'acp_ext_purge';
diff --git a/phpBB/includes/acp/acp_forums.php b/phpBB/includes/acp/acp_forums.php
index c6dbf5eb9c..970b033995 100644
--- a/phpBB/includes/acp/acp_forums.php
+++ b/phpBB/includes/acp/acp_forums.php
@@ -206,7 +206,7 @@ class acp_forums
($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'))))
{
copy_forum_permissions($forum_perm_from, $forum_data['forum_id'], ($action == 'edit') ? true : false);
- cache_moderators();
+ phpbb_cache_moderators($db, $cache, $auth);
$copied_permissions = true;
}
/* Commented out because of questionable UI workflow - re-visit for 3.0.7
@@ -266,7 +266,7 @@ class acp_forums
add_log('admin', 'LOG_FORUM_' . strtoupper($action), $row['forum_name'], $move_forum_name);
$cache->destroy('sql', FORUMS_TABLE);
}
-
+
if ($request->is_ajax())
{
$json_response = new phpbb_json_response;
@@ -283,7 +283,7 @@ class acp_forums
@set_time_limit(0);
- $sql = 'SELECT forum_name, forum_topics_real
+ $sql = 'SELECT forum_name, (forum_topics_approved + forum_topics_unapproved + forum_topics_softdeleted) AS total_topics
FROM ' . FORUMS_TABLE . "
WHERE forum_id = $forum_id";
$result = $db->sql_query($sql);
@@ -295,7 +295,7 @@ class acp_forums
trigger_error($user->lang['NO_FORUM'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
}
- if ($row['forum_topics_real'])
+ if ($row['total_topics'])
{
$sql = 'SELECT MIN(topic_id) as min_topic_id, MAX(topic_id) as max_topic_id
FROM ' . TOPICS_TABLE . '
@@ -314,7 +314,6 @@ class acp_forums
$end = $start + $batch_size;
// Sync all topics in batch mode...
- sync('topic_approved', 'range', 'topic_id BETWEEN ' . $start . ' AND ' . $end, true, false);
sync('topic', 'range', 'topic_id BETWEEN ' . $start . ' AND ' . $end, true, true);
if ($end < $row2['max_topic_id'])
@@ -330,15 +329,15 @@ class acp_forums
$start += $batch_size;
- $url = $this->u_action . "&amp;parent_id={$this->parent_id}&amp;f=$forum_id&amp;action=sync&amp;start=$start&amp;topics_done=$topics_done&amp;total={$row['forum_topics_real']}";
+ $url = $this->u_action . "&amp;parent_id={$this->parent_id}&amp;f=$forum_id&amp;action=sync&amp;start=$start&amp;topics_done=$topics_done&amp;total={$row['total_topics']}";
meta_refresh(0, $url);
$template->assign_vars(array(
- 'U_PROGRESS_BAR' => $this->u_action . "&amp;action=progress_bar&amp;start=$topics_done&amp;total={$row['forum_topics_real']}",
- 'UA_PROGRESS_BAR' => addslashes($this->u_action . "&amp;action=progress_bar&amp;start=$topics_done&amp;total={$row['forum_topics_real']}"),
+ 'U_PROGRESS_BAR' => $this->u_action . "&amp;action=progress_bar&amp;start=$topics_done&amp;total={$row['total_topics']}",
+ 'UA_PROGRESS_BAR' => addslashes($this->u_action . "&amp;action=progress_bar&amp;start=$topics_done&amp;total={$row['total_topics']}"),
'S_CONTINUE_SYNC' => true,
- 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], $topics_done, $row['forum_topics_real']))
+ 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], $topics_done, $row['total_topics']))
);
return;
@@ -352,7 +351,7 @@ class acp_forums
'U_PROGRESS_BAR' => $this->u_action . '&amp;action=progress_bar',
'UA_PROGRESS_BAR' => addslashes($this->u_action . '&amp;action=progress_bar'),
'S_CONTINUE_SYNC' => true,
- 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], 0, $row['forum_topics_real']))
+ 'L_PROGRESS_EXPLAIN' => sprintf($user->lang['SYNC_IN_PROGRESS_EXPLAIN'], 0, $row['total_topics']))
);
return;
@@ -768,7 +767,7 @@ class acp_forums
if (!empty($forum_perm_from) && $forum_perm_from != $forum_id)
{
copy_forum_permissions($forum_perm_from, $forum_id, true);
- cache_moderators();
+ phpbb_cache_moderators($db, $cache, $auth);
$auth->acl_clear_prefetch();
$cache->destroy('sql', FORUMS_TABLE);
@@ -857,8 +856,8 @@ class acp_forums
'FORUM_IMAGE_SRC' => ($row['forum_image']) ? $phpbb_root_path . $row['forum_image'] : '',
'FORUM_NAME' => $row['forum_name'],
'FORUM_DESCRIPTION' => generate_text_for_display($row['forum_desc'], $row['forum_desc_uid'], $row['forum_desc_bitfield'], $row['forum_desc_options']),
- 'FORUM_TOPICS' => $row['forum_topics'],
- 'FORUM_POSTS' => $row['forum_posts'],
+ 'FORUM_TOPICS' => $row['forum_topics_approved'],
+ 'FORUM_POSTS' => $row['forum_posts_approved'],
'S_FORUM_LINK' => ($forum_type == FORUM_LINK) ? true : false,
'S_FORUM_POST' => ($forum_type == FORUM_POST) ? true : false,
@@ -1144,7 +1143,8 @@ class acp_forums
return array($user->lang['NO_FORUM_ACTION']);
}
- $forum_data_sql['forum_posts'] = $forum_data_sql['forum_topics'] = $forum_data_sql['forum_topics_real'] = $forum_data_sql['forum_last_post_id'] = $forum_data_sql['forum_last_poster_id'] = $forum_data_sql['forum_last_post_time'] = 0;
+ $forum_data_sql['forum_posts_approved'] = $forum_data_sql['forum_posts_unapproved'] = $forum_data_sql['forum_posts_softdeleted'] = $forum_data_sql['forum_topics_approved'] = $forum_data_sql['forum_topics_unapproved'] = $forum_data_sql['forum_topics_softdeleted'] = 0;
+ $forum_data_sql['forum_last_post_id'] = $forum_data_sql['forum_last_poster_id'] = $forum_data_sql['forum_last_post_time'] = 0;
$forum_data_sql['forum_last_poster_name'] = $forum_data_sql['forum_last_poster_colour'] = '';
}
else if ($row['forum_type'] == FORUM_CAT && $forum_data_sql['forum_type'] == FORUM_LINK)
@@ -1264,9 +1264,12 @@ class acp_forums
else if ($row['forum_type'] == FORUM_CAT && $forum_data_sql['forum_type'] == FORUM_POST)
{
// Changing a category to a forum? Reset the data (you can't post directly in a cat, you must use a forum)
- $forum_data_sql['forum_posts'] = 0;
- $forum_data_sql['forum_topics'] = 0;
- $forum_data_sql['forum_topics_real'] = 0;
+ $forum_data_sql['forum_posts_approved'] = 0;
+ $forum_data_sql['forum_posts_unapproved'] = 0;
+ $forum_data_sql['forum_posts_softdeleted'] = 0;
+ $forum_data_sql['forum_topics_approved'] = 0;
+ $forum_data_sql['forum_topics_unapproved'] = 0;
+ $forum_data_sql['forum_topics_softdeleted'] = 0;
$forum_data_sql['forum_last_post_id'] = 0;
$forum_data_sql['forum_last_post_subject'] = '';
$forum_data_sql['forum_last_post_time'] = 0;
@@ -1793,7 +1796,7 @@ class acp_forums
FROM ' . POSTS_TABLE . '
WHERE forum_id = ' . $forum_id . '
AND post_postcount = 1
- AND post_approved = 1';
+ AND post_visibility = ' . ITEM_APPROVED;
$result = $db->sql_query($sql);
$post_counts = array();
@@ -1931,7 +1934,7 @@ class acp_forums
// Make sure the overall post/topic count is correct...
$sql = 'SELECT COUNT(post_id) AS stat
FROM ' . POSTS_TABLE . '
- WHERE post_approved = 1';
+ WHERE post_visibility = ' . ITEM_APPROVED;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
@@ -1940,7 +1943,7 @@ class acp_forums
$sql = 'SELECT COUNT(topic_id) AS stat
FROM ' . TOPICS_TABLE . '
- WHERE topic_approved = 1';
+ WHERE topic_visibility = ' . ITEM_APPROVED;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
diff --git a/phpBB/includes/acp/acp_groups.php b/phpBB/includes/acp/acp_groups.php
index b604e20094..e6a36c97a8 100644
--- a/phpBB/includes/acp/acp_groups.php
+++ b/phpBB/includes/acp/acp_groups.php
@@ -26,7 +26,7 @@ class acp_groups
{
global $config, $db, $user, $auth, $template, $cache;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix, $file_uploads;
- global $request;
+ global $request, $phpbb_container;
$user->add_lang('acp/groups');
$this->tpl_name = 'acp_groups';
@@ -55,15 +55,16 @@ class acp_groups
// Clear some vars
- $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false;
$group_row = array();
// Grab basic data for group, if group_id is set and exists
if ($group_id)
{
- $sql = 'SELECT *
- FROM ' . GROUPS_TABLE . "
- WHERE group_id = $group_id";
+ $sql = 'SELECT g.*, t.teampage_position AS group_teampage
+ FROM ' . GROUPS_TABLE . ' g
+ LEFT JOIN ' . TEAMPAGE_TABLE . ' t
+ ON (t.group_id = g.group_id)
+ WHERE g.group_id = ' . $group_id;
$result = $db->sql_query($sql);
$group_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
@@ -86,6 +87,11 @@ class acp_groups
case 'approve':
case 'demote':
case 'promote':
+ if (!check_form_key($form_key))
+ {
+ trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+
if (!$group_id)
{
trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING);
@@ -126,48 +132,64 @@ class acp_groups
{
trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING);
}
+ else if (empty($mark_ary))
+ {
+ trigger_error($user->lang['NO_USERS'] . adm_back_link($this->u_action . '&amp;action=list&amp;g=' . $group_id), E_USER_WARNING);
+ }
if (confirm_box(true))
{
$group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'];
+ group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row);
+ trigger_error($user->lang['GROUP_DEFS_UPDATED'] . adm_back_link($this->u_action . '&amp;action=list&amp;g=' . $group_id));
+ }
+ else
+ {
+ confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
+ 'mark' => $mark_ary,
+ 'g' => $group_id,
+ 'i' => $id,
+ 'mode' => $mode,
+ 'action' => $action))
+ );
+ }
+ break;
- if (!sizeof($mark_ary))
- {
- $start = 0;
+ case 'set_default_on_all':
+ if (confirm_box(true))
+ {
+ $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'];
+
+ $start = 0;
- do
+ do
+ {
+ $sql = 'SELECT user_id
+ FROM ' . USER_GROUP_TABLE . "
+ WHERE group_id = $group_id
+ ORDER BY user_id";
+ $result = $db->sql_query_limit($sql, 200, $start);
+
+ $mark_ary = array();
+ if ($row = $db->sql_fetchrow($result))
{
- $sql = 'SELECT user_id
- FROM ' . USER_GROUP_TABLE . "
- WHERE group_id = $group_id
- ORDER BY user_id";
- $result = $db->sql_query_limit($sql, 200, $start);
-
- $mark_ary = array();
- if ($row = $db->sql_fetchrow($result))
+ do
{
- do
- {
- $mark_ary[] = $row['user_id'];
- }
- while ($row = $db->sql_fetchrow($result));
+ $mark_ary[] = $row['user_id'];
+ }
+ while ($row = $db->sql_fetchrow($result));
- group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row);
+ group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row);
- $start = (sizeof($mark_ary) < 200) ? 0 : $start + 200;
- }
- else
- {
- $start = 0;
- }
- $db->sql_freeresult($result);
+ $start = (sizeof($mark_ary) < 200) ? 0 : $start + 200;
}
- while ($start);
- }
- else
- {
- group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row);
+ else
+ {
+ $start = 0;
+ }
+ $db->sql_freeresult($result);
}
+ while ($start);
trigger_error($user->lang['GROUP_DEFS_UPDATED'] . adm_back_link($this->u_action . '&amp;action=list&amp;g=' . $group_id));
}
@@ -181,10 +203,13 @@ class acp_groups
'action' => $action))
);
}
-
break;
case 'deleteusers':
+ if (empty($mark_ary))
+ {
+ trigger_error($user->lang['NO_USERS'] . adm_back_link($this->u_action . '&amp;action=list&amp;g=' . $group_id), E_USER_WARNING);
+ }
case 'delete':
if (!$group_id)
{
@@ -239,6 +264,11 @@ class acp_groups
break;
case 'addusers':
+ if (!check_form_key($form_key))
+ {
+ trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+
if (!$group_id)
{
trigger_error($user->lang['NO_GROUP'] . adm_back_link($this->u_action), E_USER_WARNING);
@@ -282,8 +312,21 @@ class acp_groups
$error = array();
$user->add_lang('ucp');
- $avatar_select = basename(request_var('avatar_select', ''));
- $category = basename(request_var('category', ''));
+ // Setup avatar data for later
+ $avatars_enabled = false;
+ $avatar_drivers = null;
+ $avatar_data = null;
+ $avatar_error = array();
+
+ if ($config['allow_avatar'])
+ {
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers();
+
+ // This is normalised data, without the group_ prefix
+ $avatar_data = phpbb_avatar_manager::clean_row($group_row);
+ }
+
// Did we submit?
if ($update)
@@ -301,12 +344,6 @@ class acp_groups
$allow_desc_urls = request_var('desc_parse_urls', false);
$allow_desc_smilies = request_var('desc_parse_smilies', false);
- $data['uploadurl'] = request_var('uploadurl', '');
- $data['remotelink'] = request_var('remotelink', '');
- $data['width'] = request_var('width', '');
- $data['height'] = request_var('height', '');
- $delete = request_var('delete', '');
-
$submit_ary = array(
'colour' => request_var('group_colour', ''),
'rank' => request_var('group_rank', 0),
@@ -324,91 +361,56 @@ class acp_groups
$submit_ary['founder_manage'] = isset($_REQUEST['group_founder_manage']) ? 1 : 0;
}
- $uploadfile = $request->file('uploadfile');
- if (!empty($uploadfile['tmp_name']) || $data['uploadurl'] || $data['remotelink'])
+ if ($config['allow_avatar'])
{
- // Avatar stuff
- $var_ary = array(
- 'uploadurl' => array('string', true, 5, 255),
- 'remotelink' => array('string', true, 5, 255),
- 'width' => array('string', true, 1, 3),
- 'height' => array('string', true, 1, 3),
- );
+ // Handle avatar
+ $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', ''));
- if (!($error = validate_data($data, $var_ary)))
+ if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete'))
{
- $data['user_id'] = "g$group_id";
+ $driver = $phpbb_avatar_manager->get_driver($driver_name);
+ $result = $driver->process_form($request, $template, $user, $avatar_data, $avatar_error);
- if ((!empty($uploadfile['tmp_name']) || $data['uploadurl']) && $can_upload)
+ if ($result && empty($avatar_error))
{
- list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_upload($data, $error);
- }
- else if ($data['remotelink'])
- {
- list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_remote($data, $error);
+ $result['avatar_type'] = $driver_name;
+ $submit_ary = array_merge($submit_ary, $result);
}
}
- }
- else if ($avatar_select && $config['allow_avatar_local'])
- {
- // check avatar gallery
- if (is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category))
+ else
{
- $submit_ary['avatar_type'] = AVATAR_GALLERY;
-
- list($submit_ary['avatar_width'], $submit_ary['avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . $avatar_select);
- $submit_ary['avatar'] = $category . '/' . $avatar_select;
- }
- }
- else if ($delete)
- {
- $submit_ary['avatar'] = '';
- $submit_ary['avatar_type'] = $submit_ary['avatar_width'] = $submit_ary['avatar_height'] = 0;
- }
- else if ($data['width'] && $data['height'])
- {
- // Only update the dimensions?
- if ($config['avatar_max_width'] || $config['avatar_max_height'])
- {
- if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height'])
+ $driver = $phpbb_avatar_manager->get_driver($user->data['user_avatar_type']);
+ if ($driver)
{
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
+ $driver->delete($avatar_data);
}
- }
- if (!sizeof($error))
- {
- if ($config['avatar_min_width'] || $config['avatar_min_height'])
- {
- if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
- }
- }
+ // Removing the avatar
+ $submit_ary['avatar_type'] = '';
+ $submit_ary['avatar'] = '';
+ $submit_ary['avatar_width'] = 0;
+ $submit_ary['avatar_height'] = 0;
}
- if (!sizeof($error))
- {
- $submit_ary['avatar_width'] = $data['width'];
- $submit_ary['avatar_height'] = $data['height'];
- }
+ // Merge any avatar errors into the primary error array
+ $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error));
}
- if ((isset($submit_ary['avatar']) && $submit_ary['avatar'] && (!isset($group_row['group_avatar']))) || $delete)
- {
- if (isset($group_row['group_avatar']) && $group_row['group_avatar'])
- {
- avatar_delete('group', $group_row, true);
- }
- }
+ /*
+ * Validate the length of "Maximum number of allowed recipients per
+ * private message" setting. We use 16777215 as a maximum because it matches
+ * MySQL unsigned mediumint maximum value which is the lowest amongst DBMSes
+ * supported by phpBB3. Also validate the submitted colour value.
+ */
+ $validation_checks = array(
+ 'max_recipients' => array('num', false, 0, 16777215),
+ 'colour' => array('hex_colour', true),
+ );
- // Validate the length of "Maximum number of allowed recipients per private message" setting.
- // We use 16777215 as a maximum because it matches MySQL unsigned mediumint maximum value
- // which is the lowest amongst DBMSes supported by phpBB3
- if ($max_recipients_error = validate_data($submit_ary, array('max_recipients' => array('num', false, 0, 16777215))))
+ if ($validation_error = validate_data($submit_ary, $validation_checks))
{
// Replace "error" string with its real, localised form
- $error = array_merge($error, array_map(array(&$user, 'lang'), $max_recipients_error));
+ $error = array_merge($error, $validation_error);
}
if (!sizeof($error))
@@ -425,7 +427,7 @@ class acp_groups
'rank' => 'int',
'colour' => 'string',
'avatar' => 'string',
- 'avatar_type' => 'int',
+ 'avatar_type' => 'string',
'avatar_width' => 'int',
'avatar_height' => 'int',
'receive_pm' => 'int',
@@ -439,7 +441,7 @@ class acp_groups
foreach ($test_variables as $test => $type)
{
- if (isset($submit_ary[$test]) && ($action == 'add' || $group_row['group_' . $test] != $submit_ary[$test] || in_array($test, $set_attributes)))
+ if (isset($submit_ary[$test]) && ($action == 'add' || $group_row['group_' . $test] != $submit_ary[$test] || isset($group_attributes['group_avatar']) && strpos($test, 'avatar') === 0 || in_array($test, $set_attributes)))
{
settype($submit_ary[$test], $type);
$group_attributes['group_' . $test] = $group_row['group_' . $test] = $submit_ary[$test];
@@ -496,7 +498,7 @@ class acp_groups
}
}
- $cache->destroy('sql', GROUPS_TABLE);
+ $cache->destroy('sql', array(GROUPS_TABLE, TEAMPAGE_TABLE));
$message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED';
trigger_error($user->lang[$message] . adm_back_link($this->u_action));
@@ -505,6 +507,7 @@ class acp_groups
if (sizeof($error))
{
+ $error = array_map(array(&$user, 'lang'), $error);
$group_rank = $submit_ary['rank'];
$group_desc_data = array(
@@ -555,13 +558,44 @@ class acp_groups
$type_closed = ($group_type == GROUP_CLOSED) ? ' checked="checked"' : '';
$type_hidden = ($group_type == GROUP_HIDDEN) ? ' checked="checked"' : '';
- $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') : '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />';
+ // Load up stuff for avatars
+ if ($config['allow_avatar'])
+ {
+ $avatars_enabled = false;
+ $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $avatar_data['avatar_type']));
- $display_gallery = (isset($_POST['display_gallery'])) ? true : false;
+ foreach ($avatar_drivers as $current_driver)
+ {
+ $driver = $phpbb_avatar_manager->get_driver($current_driver);
+
+ $avatars_enabled = true;
+ $config_name = $phpbb_avatar_manager->get_driver_config_name($driver);
+ $template->set_filenames(array(
+ 'avatar' => "acp_avatar_options_{$config_name}.html",
+ ));
+
+ if ($driver->prepare_form($request, $template, $user, $avatar_data, $avatar_error))
+ {
+ $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver);
+ $driver_upper = strtoupper($driver_name);
+ $template->assign_block_vars('avatar_drivers', array(
+ 'L_TITLE' => $user->lang($driver_upper . '_TITLE'),
+ 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'),
+
+ 'DRIVER' => $driver_name,
+ 'SELECTED' => $current_driver == $selected_driver,
+ 'OUTPUT' => $template->assign_display('avatar'),
+ ));
+ }
+ }
+ }
+
+ $avatar = phpbb_get_group_avatar($group_row, 'GROUP_AVATAR', true);
- if ($config['allow_avatar_local'] && $display_gallery)
+ if (isset($phpbb_avatar_manager) && !$update)
{
- avatar_gallery($category, $avatar_select, 4);
+ // Merge any avatar errors into the primary error array
+ $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error));
}
$back_link = request_var('back_link', '');
@@ -582,12 +616,10 @@ class acp_groups
'S_ADD_GROUP' => ($action == 'add') ? true : false,
'S_GROUP_PERM' => ($action == 'add' && $auth->acl_get('a_authgroups') && $auth->acl_gets('a_aauth', 'a_fauth', 'a_mauth', 'a_uauth')) ? true : false,
'S_INCLUDE_SWATCH' => true,
- 'S_CAN_UPLOAD' => $can_upload,
'S_ERROR' => (sizeof($error)) ? true : false,
'S_SPECIAL_GROUP' => ($group_type == GROUP_SPECIAL) ? 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_USER_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false,
+ 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
'GROUP_NAME' => ($group_type == GROUP_SPECIAL) ? $user->lang['G_' . $group_name] : $group_name,
@@ -608,8 +640,7 @@ class acp_groups
'S_RANK_OPTIONS' => $rank_options,
'S_GROUP_OPTIONS' => group_select_options(false, false, (($user->data['user_type'] == USER_FOUNDER) ? false : 0)),
- 'AVATAR' => $avatar_img,
- 'AVATAR_IMAGE' => $avatar_img,
+ 'AVATAR' => empty($avatar) ? '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />' : $avatar,
'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'],
'AVATAR_WIDTH' => (isset($group_row['group_avatar_width'])) ? $group_row['group_avatar_width'] : '',
'AVATAR_HEIGHT' => (isset($group_row['group_avatar_height'])) ? $group_row['group_avatar_height'] : '',
@@ -698,7 +729,7 @@ class acp_groups
'U_ACTION' => $this->u_action . "&amp;g=$group_id",
'U_BACK' => $this->u_action,
'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&amp;form=list&amp;field=usernames'),
- 'U_DEFAULT_ALL' => "{$this->u_action}&amp;action=default&amp;g=$group_id",
+ 'U_DEFAULT_ALL' => "{$this->u_action}&amp;action=set_default_on_all&amp;g=$group_id",
));
// Grab the members
@@ -811,56 +842,114 @@ class acp_groups
public function manage_position()
{
- global $config, $db, $template, $user;
+ global $config, $db, $template, $user, $request, $phpbb_container;
$this->tpl_name = 'acp_groups_position';
$this->page_title = 'ACP_GROUPS_POSITION';
- $field = request_var('field', '');
- $action = request_var('action', '');
- $group_id = request_var('g', 0);
+ $field = $request->variable('field', '');
+ $action = $request->variable('action', '');
+ $group_id = $request->variable('g', 0);
+ $teampage_id = $request->variable('t', 0);
+ $category_id = $request->variable('c', 0);
if ($field && !in_array($field, array('legend', 'teampage')))
{
// Invalid mode
trigger_error($user->lang['NO_MODE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- else if ($field)
+ else if ($field && in_array($field, array('legend', 'teampage')))
{
- $group_position = new phpbb_group_positions($db, $field, $this->u_action);
+
+ $group_position = $phpbb_container->get('groupposition.' . $field);
}
- switch ($action)
+ if ($field == 'teampage')
{
- case 'set_config_legend':
- set_config('legend_sort_groupname', request_var('legend_sort_groupname', 0));
- break;
+ try
+ {
+ switch ($action)
+ {
+ case 'add':
+ $group_position->add_group_teampage($group_id, $category_id);
+ break;
- case 'set_config_teampage':
- set_config('teampage_forums', request_var('teampage_forums', 0));
- set_config('teampage_memberships', request_var('teampage_memberships', 0));
- break;
+ case 'add_category':
+ $group_position->add_category_teampage($request->variable('category_name', '', true));
+ break;
- case 'add':
- $group_position->add_group($group_id);
- break;
+ case 'delete':
+ $group_position->delete_teampage($teampage_id);
+ break;
- case 'delete':
- $group_position->delete_group($group_id);
- break;
+ case 'move_up':
+ $group_position->move_up_teampage($teampage_id);
+ break;
- case 'move_up':
- $group_position->move_up($group_id);
- break;
+ case 'move_down':
+ $group_position->move_down_teampage($teampage_id);
+ break;
+ }
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()) . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+ }
+ else if ($field == 'legend')
+ {
+ try
+ {
+ switch ($action)
+ {
+ case 'add':
+ $group_position->add_group($group_id);
+ break;
- case 'move_down':
- $group_position->move_down($group_id);
- break;
+ case 'delete':
+ $group_position->delete_group($group_id);
+ break;
+
+ case 'move_up':
+ $group_position->move_up($group_id);
+ break;
+
+ case 'move_down':
+ $group_position->move_down($group_id);
+ break;
+ }
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()) . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+ }
+ else
+ {
+ switch ($action)
+ {
+ case 'set_config_teampage':
+ $config->set('teampage_forums', $request->variable('teampage_forums', 0));
+ $config->set('teampage_memberships', $request->variable('teampage_memberships', 0));
+ trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action));
+ break;
+
+ case 'set_config_legend':
+ $config->set('legend_sort_groupname', $request->variable('legend_sort_groupname', 0));
+ trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action));
+ break;
+ }
+ }
+
+ if (($action == 'move_up' || $action == 'move_down') && $request->is_ajax())
+ {
+ $json_response = new phpbb_json_response;
+ $json_response->send(array('success' => true));
}
$sql = 'SELECT group_id, group_name, group_colour, group_type, group_legend
FROM ' . GROUPS_TABLE . '
- ORDER BY group_legend, group_name ASC';
+ ORDER BY group_legend ASC, group_type DESC, group_name ASC';
$result = $db->sql_query($sql);
$s_group_select_legend = '';
@@ -870,57 +959,99 @@ class acp_groups
if ($row['group_legend'])
{
$template->assign_block_vars('legend', array(
- 'GROUP_NAME' => $group_name,
- 'GROUP_COLOUR' => ($row['group_colour']) ? ' style="color: #' . $row['group_colour'] . '"' : '',
- 'GROUP_TYPE' => $user->lang[phpbb_group_positions::group_type_language($row['group_type'])],
+ 'GROUP_NAME' => $group_name,
+ 'GROUP_COLOUR' => ($row['group_colour']) ? '#' . $row['group_colour'] : '',
+ 'GROUP_TYPE' => $user->lang[phpbb_groupposition_legend::group_type_language($row['group_type'])],
- 'U_MOVE_DOWN' => "{$this->u_action}&amp;field=legend&amp;action=move_down&amp;g=" . $row['group_id'],
- 'U_MOVE_UP' => "{$this->u_action}&amp;field=legend&amp;action=move_up&amp;g=" . $row['group_id'],
- 'U_DELETE' => "{$this->u_action}&amp;field=legend&amp;action=delete&amp;g=" . $row['group_id'],
+ 'U_MOVE_DOWN' => "{$this->u_action}&amp;field=legend&amp;action=move_down&amp;g=" . $row['group_id'],
+ 'U_MOVE_UP' => "{$this->u_action}&amp;field=legend&amp;action=move_up&amp;g=" . $row['group_id'],
+ 'U_DELETE' => "{$this->u_action}&amp;field=legend&amp;action=delete&amp;g=" . $row['group_id'],
));
}
else
{
- $s_group_select_legend .= '<option value="' . (int) $row['group_id'] . '">' . $group_name . '</option>';
+ $template->assign_block_vars('add_legend', array(
+ 'GROUP_ID' => (int) $row['group_id'],
+ 'GROUP_NAME' => $group_name,
+ 'GROUP_SPECIAL' => ($row['group_type'] == GROUP_SPECIAL),
+ ));
}
}
$db->sql_freeresult($result);
- $sql = 'SELECT group_id, group_name, group_colour, group_type, group_teampage
- FROM ' . GROUPS_TABLE . '
- ORDER BY group_teampage, group_name ASC';
+ $category_url_param = (($category_id) ? '&amp;c=' . $category_id : '');
+
+ $sql = 'SELECT t.*, g.group_name, g.group_colour, g.group_type
+ FROM ' . TEAMPAGE_TABLE . ' t
+ LEFT JOIN ' . GROUPS_TABLE . ' g
+ ON (t.group_id = g.group_id)
+ WHERE t.teampage_parent = ' . $category_id . '
+ OR t.teampage_id = ' . $category_id . '
+ ORDER BY t.teampage_position ASC';
$result = $db->sql_query($sql);
- $s_group_select_teampage = '';
+ $category_data = array();
while ($row = $db->sql_fetchrow($result))
{
- $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
- if ($row['group_teampage'])
+ if ($row['teampage_id'] == $category_id)
{
- $template->assign_block_vars('teampage', array(
- 'GROUP_NAME' => $group_name,
- 'GROUP_COLOUR' => ($row['group_colour']) ? ' style="color: #' . $row['group_colour'] . '"' : '',
- 'GROUP_TYPE' => $user->lang[phpbb_group_positions::group_type_language($row['group_type'])],
-
- 'U_MOVE_DOWN' => "{$this->u_action}&amp;field=teampage&amp;action=move_down&amp;g=" . $row['group_id'],
- 'U_MOVE_UP' => "{$this->u_action}&amp;field=teampage&amp;action=move_up&amp;g=" . $row['group_id'],
- 'U_DELETE' => "{$this->u_action}&amp;field=teampage&amp;action=delete&amp;g=" . $row['group_id'],
+ $template->assign_vars(array(
+ 'CURRENT_CATEGORY_NAME' => $row['teampage_name'],
));
+ continue;
+ }
+
+ if ($row['group_id'])
+ {
+ $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $group_type = $user->lang[phpbb_groupposition_teampage::group_type_language($row['group_type'])];
}
else
{
- $s_group_select_teampage .= '<option value="' . (int) $row['group_id'] . '">' . $group_name . '</option>';
+ $group_name = $row['teampage_name'];
+ $group_type = '';
}
+
+ $template->assign_block_vars('teampage', array(
+ 'GROUP_NAME' => $group_name,
+ 'GROUP_COLOUR' => ($row['group_colour']) ? '#' . $row['group_colour'] : '',
+ 'GROUP_TYPE' => $group_type,
+
+ 'U_CATEGORY' => (!$row['group_id']) ? "{$this->u_action}&amp;c=" . $row['teampage_id'] : '',
+ 'U_MOVE_DOWN' => "{$this->u_action}&amp;field=teampage&amp;action=move_down{$category_url_param}&amp;t=" . $row['teampage_id'],
+ 'U_MOVE_UP' => "{$this->u_action}&amp;field=teampage&amp;action=move_up{$category_url_param}&amp;t=" . $row['teampage_id'],
+ 'U_DELETE' => "{$this->u_action}&amp;field=teampage&amp;action=delete{$category_url_param}&amp;t=" . $row['teampage_id'],
+ ));
+ }
+ $db->sql_freeresult($result);
+
+ $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type
+ FROM ' . GROUPS_TABLE . ' g
+ LEFT JOIN ' . TEAMPAGE_TABLE . ' t
+ ON (t.group_id = g.group_id)
+ WHERE t.teampage_id IS NULL
+ ORDER BY g.group_type DESC, g.group_name ASC';
+ $result = $db->sql_query($sql);
+
+ $s_group_select_teampage = '';
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $template->assign_block_vars('add_teampage', array(
+ 'GROUP_ID' => (int) $row['group_id'],
+ 'GROUP_NAME' => $group_name,
+ 'GROUP_SPECIAL' => ($row['group_type'] == GROUP_SPECIAL),
+ ));
}
$db->sql_freeresult($result);
$template->assign_vars(array(
- 'U_ACTION' => $this->u_action,
- 'U_ACTION_LEGEND' => $this->u_action . '&amp;field=legend',
- 'U_ACTION_TEAMPAGE' => $this->u_action . '&amp;field=teampage',
+ 'U_ACTION' => $this->u_action,
+ 'U_ACTION_LEGEND' => $this->u_action . '&amp;field=legend',
+ 'U_ACTION_TEAMPAGE' => $this->u_action . '&amp;field=teampage' . $category_url_param,
+ 'U_ACTION_TEAMPAGE_CAT' => $this->u_action . '&amp;field=teampage_cat',
- 'S_GROUP_SELECT_LEGEND' => $s_group_select_legend,
- 'S_GROUP_SELECT_TEAMPAGE' => $s_group_select_teampage,
+ 'S_TEAMPAGE_CATEGORY' => $category_id,
'DISPLAY_FORUMS' => ($config['teampage_forums']) ? true : false,
'DISPLAY_MEMBERSHIPS' => $config['teampage_memberships'],
'LEGEND_SORT_GROUPNAME' => ($config['legend_sort_groupname']) ? true : false,
diff --git a/phpBB/includes/acp/acp_inactive.php b/phpBB/includes/acp/acp_inactive.php
index e61115f681..de4679b58d 100644
--- a/phpBB/includes/acp/acp_inactive.php
+++ b/phpBB/includes/acp/acp_inactive.php
@@ -115,7 +115,7 @@ class acp_inactive
{
$messenger->template('admin_welcome_activated', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->anti_abuse_headers($config, $user);
@@ -203,8 +203,7 @@ class acp_inactive
{
$messenger->template('user_remind_inactive', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->anti_abuse_headers($config, $user);
diff --git a/phpBB/includes/acp/acp_main.php b/phpBB/includes/acp/acp_main.php
index d419bc3b99..eecd8c72dc 100644
--- a/phpBB/includes/acp/acp_main.php
+++ b/phpBB/includes/acp/acp_main.php
@@ -24,7 +24,7 @@ class acp_main
function main($id, $mode)
{
- global $config, $db, $user, $auth, $template, $request;
+ global $config, $db, $cache, $user, $auth, $template, $request;
global $phpbb_root_path, $phpbb_admin_path, $phpEx;
// Show restore permissions notice
@@ -63,9 +63,7 @@ class acp_main
if ($action === 'admlogout')
{
$user->unset_admin();
- $redirect_url = append_sid("{$phpbb_root_path}index.$phpEx");
- meta_refresh(3, $redirect_url);
- trigger_error($user->lang['ADM_LOGGED_OUT'] . '<br /><br />' . sprintf($user->lang['RETURN_INDEX'], '<a href="' . $redirect_url . '">', '</a>'));
+ redirect(append_sid("{$phpbb_root_path}index.$phpEx"));
}
if (!confirm_box(true))
@@ -129,7 +127,7 @@ class acp_main
set_config('record_online_users', 1, true);
set_config('record_online_date', time(), true);
add_log('admin', 'LOG_RESET_ONLINE');
-
+
if ($request->is_ajax())
{
trigger_error('RESET_ONLINE_SUCCESS');
@@ -144,14 +142,14 @@ class acp_main
$sql = 'SELECT COUNT(post_id) AS stat
FROM ' . POSTS_TABLE . '
- WHERE post_approved = 1';
+ WHERE post_visibility = ' . ITEM_APPROVED;
$result = $db->sql_query($sql);
set_config('num_posts', (int) $db->sql_fetchfield('stat'), true);
$db->sql_freeresult($result);
$sql = 'SELECT COUNT(topic_id) AS stat
FROM ' . TOPICS_TABLE . '
- WHERE topic_approved = 1';
+ WHERE topic_visibility = ' . ITEM_APPROVED;
$result = $db->sql_query($sql);
set_config('num_topics', (int) $db->sql_fetchfield('stat'), true);
$db->sql_freeresult($result);
@@ -184,7 +182,7 @@ class acp_main
update_last_username();
add_log('admin', 'LOG_RESYNC_STATS');
-
+
if ($request->is_ajax())
{
trigger_error('RESYNC_STATS_SUCCESS');
@@ -232,7 +230,7 @@ class acp_main
$sql = 'SELECT COUNT(post_id) AS num_posts, poster_id
FROM ' . POSTS_TABLE . '
WHERE post_id BETWEEN ' . ($start + 1) . ' AND ' . ($start + $step) . '
- AND post_postcount = 1 AND post_approved = 1
+ AND post_postcount = 1 AND post_visibility = ' . ITEM_APPROVED . '
GROUP BY poster_id';
$result = $db->sql_query($sql);
@@ -251,7 +249,7 @@ class acp_main
}
add_log('admin', 'LOG_RESYNC_POSTCOUNTS');
-
+
if ($request->is_ajax())
{
trigger_error('RESYNC_POSTCOUNTS_SUCCESS');
@@ -266,7 +264,7 @@ class acp_main
set_config('board_startdate', time() - 1);
add_log('admin', 'LOG_RESET_DATE');
-
+
if ($request->is_ajax())
{
trigger_error('RESET_DATE_SUCCESS');
@@ -346,7 +344,7 @@ class acp_main
}
add_log('admin', 'LOG_RESYNC_POST_MARKING');
-
+
if ($request->is_ajax())
{
trigger_error('RESYNC_POST_MARKING_SUCCESS');
@@ -359,10 +357,10 @@ class acp_main
// Clear permissions
$auth->acl_clear_prefetch();
- cache_moderators();
+ phpbb_cache_moderators($db, $cache, $auth);
add_log('admin', 'LOG_PURGE_CACHE');
-
+
if ($request->is_ajax())
{
trigger_error('PURGE_CACHE_SUCCESS');
@@ -413,7 +411,7 @@ class acp_main
$db->sql_query($sql);
add_log('admin', 'LOG_PURGE_SESSIONS');
-
+
if ($request->is_ajax())
{
trigger_error('PURGE_SESSIONS_SUCCESS');
@@ -430,7 +428,7 @@ class acp_main
{
$template->assign_vars(array(
'S_PHP_VERSION_OLD' => true,
- 'L_PHP_VERSION_OLD' => sprintf($user->lang['PHP_VERSION_OLD'], '<a href="http://www.phpbb.com/community/viewtopic.php?f=14&amp;t=2152375">', '</a>'),
+ 'L_PHP_VERSION_OLD' => sprintf($user->lang['PHP_VERSION_OLD'], '<a href="https://www.phpbb.com/community/viewtopic.php?f=14&amp;t=2152375">', '</a>'),
));
}
diff --git a/phpBB/includes/acp/acp_modules.php b/phpBB/includes/acp/acp_modules.php
index 8528dc91c4..7a1d30196d 100644
--- a/phpBB/includes/acp/acp_modules.php
+++ b/phpBB/includes/acp/acp_modules.php
@@ -379,6 +379,7 @@ class acp_modules
$json_response->send(array(
'MESSAGE_TITLE' => $user->lang('ERROR'),
'MESSAGE_TEXT' => implode('<br />', $errors),
+ 'SUCCESS' => false,
));
}
@@ -535,84 +536,76 @@ class acp_modules
/**
* Get available module information from module files
+ *
+ * @param string $module
+ * @param bool|string $module_class
+ * @param bool $use_all_available Use all available instead of just all
+ * enabled extensions
+ * @return array
*/
- function get_module_infos($module = '', $module_class = false)
+ function get_module_infos($module = '', $module_class = false, $use_all_available = false)
{
- global $phpbb_root_path, $phpEx;
+ global $phpbb_extension_manager, $phpbb_root_path, $phpEx;
$module_class = ($module_class === false) ? $this->module_class : $module_class;
$directory = $phpbb_root_path . 'includes/' . $module_class . '/info/';
$fileinfo = array();
- if (!$module)
- {
- global $phpbb_extension_manager;
-
- $finder = $phpbb_extension_manager->get_finder();
+ $finder = $phpbb_extension_manager->get_finder();
- $modules = $finder
- ->extension_suffix('_module')
- ->extension_directory("/$module_class")
- ->core_path("includes/$module_class/info/")
- ->core_prefix($module_class . '_')
- ->get_classes();
+ $modules = $finder
+ ->extension_suffix('_module')
+ ->extension_directory("/$module_class")
+ ->core_path("includes/$module_class/info/")
+ ->core_prefix($module_class . '_')
+ ->get_classes(true, $use_all_available);
- foreach ($modules as $module)
+ foreach ($modules as $cur_module)
+ {
+ // Skip entries we do not need if we know the module we are
+ // looking for
+ if ($module && strpos($cur_module, $module) === false)
{
- $info_class = preg_replace('/_module$/', '_info', $module);
-
- // If the class does not exist it might be following the old
- // format. phpbb_acp_info_acp_foo needs to be turned into
- // acp_foo_info and the respective file has to be included
- // manually because it does not support auto loading
- if (!class_exists($info_class))
- {
- $info_class = str_replace("phpbb_{$module_class}_info_", '', $module) . '_info';
- if (file_exists($directory . $info_class . '.' . $phpEx))
- {
- include($directory . $info_class . '.' . $phpEx);
- }
- }
+ continue;
+ }
- if (class_exists($info_class))
- {
- $info = new $info_class();
- $module_info = $info->module();
+ $info_class = preg_replace('/_module$/', '_info', $cur_module);
- $main_class = (isset($module_info['filename'])) ? $module_info['filename'] : $module;
+ // If the class does not exist it might be following the old
+ // format. phpbb_acp_info_acp_foo needs to be turned into
+ // acp_foo_info and the respective file has to be included
+ // manually because it does not support auto loading
+ $old_info_class_file = str_replace("phpbb_{$module_class}_info_", '', $cur_module);
+ $old_info_class = $old_info_class_file . '_info';
- $fileinfo[$main_class] = $module_info;
- }
+ if (class_exists($old_info_class))
+ {
+ $info_class = $old_info_class;
}
-
- ksort($fileinfo);
- }
- else
- {
- $info_class = preg_replace('/_module$/', '_info', $module);
-
- if (!class_exists($info_class))
+ else if (!class_exists($info_class))
{
- if (file_exists($directory . $module . '.' . $phpEx))
+ $info_class = $old_info_class;
+ // need to check class exists again because previous checks triggered autoloading
+ if (!class_exists($info_class) && file_exists($directory . $old_info_class_file . '.' . $phpEx))
{
- include($directory . $module . '.' . $phpEx);
+ include($directory . $old_info_class_file . '.' . $phpEx);
}
- $info_class = $module . '_info';
}
- // Get module title tag
if (class_exists($info_class))
{
$info = new $info_class();
$module_info = $info->module();
- $main_class = (isset($module_info['filename'])) ? $module_info['filename'] : $module;
+ $main_class = (isset($module_info['filename'])) ? $module_info['filename'] : $cur_module;
$fileinfo[$main_class] = $module_info;
}
}
+ ksort($fileinfo);
+
return $fileinfo;
}
@@ -740,15 +733,15 @@ class acp_modules
*/
function remove_cache_file()
{
- global $cache;
+ global $phpbb_container;
// Sanitise for future path use, it's escaped as appropriate for queries
$p_class = str_replace(array('.', '/', '\\'), '', basename($this->module_class));
- $cache->destroy('_modules_' . $p_class);
+ $phpbb_container->get('cache.driver')->destroy('_modules_' . $p_class);
// Additionally remove sql cache
- $cache->destroy('sql', MODULES_TABLE);
+ $phpbb_container->get('cache.driver')->destroy('sql', MODULES_TABLE);
}
/**
diff --git a/phpBB/includes/acp/acp_permission_roles.php b/phpBB/includes/acp/acp_permission_roles.php
index 004187af84..17e48d6576 100644
--- a/phpBB/includes/acp/acp_permission_roles.php
+++ b/phpBB/includes/acp/acp_permission_roles.php
@@ -21,16 +21,17 @@ if (!defined('IN_PHPBB'))
class acp_permission_roles
{
var $u_action;
+ protected $auth_admin;
function main($id, $mode)
{
- global $db, $user, $auth, $template, $cache;
+ global $db, $user, $auth, $template, $cache, $phpbb_container;
global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx);
include_once($phpbb_root_path . 'includes/acp/auth.' . $phpEx);
- $auth_admin = new auth_admin();
+ $this->auth_admin = new auth_admin();
$user->add_lang('acp/permissions');
add_permission_language();
@@ -210,7 +211,7 @@ class acp_permission_roles
}
// Now add the auth settings
- $auth_admin->acl_set_role($role_id, $auth_settings);
+ $this->auth_admin->acl_set_role($role_id, $auth_settings);
$role_name = (!empty($user->lang[$role_name])) ? $user->lang[$role_name] : $role_name;
add_log('admin', 'LOG_' . strtoupper($permission_type) . 'ROLE_' . strtoupper($action), $role_name);
@@ -305,6 +306,8 @@ class acp_permission_roles
trigger_error($user->lang['NO_ROLE_SELECTED'] . adm_back_link($this->u_action), E_USER_WARNING);
}
+ $phpbb_permissions = $phpbb_container->get('acl.permissions');
+
$template->assign_vars(array(
'S_EDIT' => true,
@@ -313,9 +316,8 @@ class acp_permission_roles
'ROLE_NAME' => $role_row['role_name'],
'ROLE_DESCRIPTION' => $role_row['role_description'],
- 'L_ACL_TYPE' => $user->lang['ACL_TYPE_' . strtoupper($permission_type)],
- )
- );
+ 'L_ACL_TYPE' => $phpbb_permissions->get_type_lang($permission_type),
+ ));
// We need to fill the auth options array with ACL_NO options ;)
$sql = 'SELECT auth_option_id, auth_option
@@ -343,7 +345,7 @@ class acp_permission_roles
// Get users/groups/forums using this preset...
if ($action == 'edit')
{
- $hold_ary = $auth_admin->get_role_mask($role_id);
+ $hold_ary = $this->auth_admin->get_role_mask($role_id);
if (sizeof($hold_ary))
{
@@ -354,7 +356,7 @@ class acp_permission_roles
'L_ROLE_ASSIGNED_TO' => sprintf($user->lang['ROLE_ASSIGNED_TO'], $role_name))
);
- $auth_admin->display_role_mask($hold_ary);
+ $this->auth_admin->display_role_mask($hold_ary);
}
}
@@ -445,8 +447,8 @@ class acp_permission_roles
'S_DISPLAY_ROLE_MASK' => true)
);
- $hold_ary = $auth_admin->get_role_mask($display_item);
- $auth_admin->display_role_mask($hold_ary);
+ $hold_ary = $this->auth_admin->get_role_mask($display_item);
+ $this->auth_admin->display_role_mask($hold_ary);
}
}
@@ -455,14 +457,16 @@ class acp_permission_roles
*/
function display_auth_options($auth_options)
{
- global $template, $user;
+ global $template, $user, $phpbb_container;
+
+ $phpbb_permissions = $phpbb_container->get('acl.permissions');
$content_array = $categories = array();
$key_sort_array = array(0);
$auth_options = array(0 => $auth_options);
// Making use of auth_admin method here (we do not really want to change two similar code fragments)
- auth_admin::build_permission_array($auth_options, $content_array, $categories, $key_sort_array);
+ $this->auth_admin->build_permission_array($auth_options, $content_array, $categories, $key_sort_array);
$content_array = $content_array[0];
@@ -472,7 +476,7 @@ class acp_permission_roles
foreach ($content_array as $cat => $cat_array)
{
$template->assign_block_vars('auth', array(
- 'CAT_NAME' => $user->lang['permission_cat'][$cat],
+ 'CAT_NAME' => $phpbb_permissions->get_category_lang($cat),
'S_YES' => ($cat_array['S_YES'] && !$cat_array['S_NEVER'] && !$cat_array['S_NO']) ? true : false,
'S_NEVER' => ($cat_array['S_NEVER'] && !$cat_array['S_YES'] && !$cat_array['S_NO']) ? true : false,
@@ -487,8 +491,8 @@ class acp_permission_roles
'S_NO' => ($allowed == ACL_NO) ? true : false,
'FIELD_NAME' => $permission,
- 'PERMISSION' => $user->lang['acl_' . $permission]['lang'])
- );
+ 'PERMISSION' => $phpbb_permissions->get_permission_lang($permission),
+ ));
}
}
}
@@ -500,8 +504,6 @@ class acp_permission_roles
{
global $db;
- $auth_admin = new auth_admin();
-
// Get complete auth array
$sql = 'SELECT auth_option, auth_option_id
FROM ' . ACL_OPTIONS_TABLE . "
@@ -529,19 +531,19 @@ class acp_permission_roles
$db->sql_freeresult($result);
// Get role assignments
- $hold_ary = $auth_admin->get_role_mask($role_id);
+ $hold_ary = $this->auth_admin->get_role_mask($role_id);
// Re-assign permissions
foreach ($hold_ary as $forum_id => $forum_ary)
{
if (isset($forum_ary['users']))
{
- $auth_admin->acl_set('user', $forum_id, $forum_ary['users'], $auth_settings, 0, false);
+ $this->auth_admin->acl_set('user', $forum_id, $forum_ary['users'], $auth_settings, 0, false);
}
if (isset($forum_ary['groups']))
{
- $auth_admin->acl_set('group', $forum_id, $forum_ary['groups'], $auth_settings, 0, false);
+ $this->auth_admin->acl_set('group', $forum_id, $forum_ary['groups'], $auth_settings, 0, false);
}
}
@@ -563,6 +565,6 @@ class acp_permission_roles
WHERE role_id = ' . $role_id;
$db->sql_query($sql);
- $auth_admin->acl_clear_prefetch();
+ $this->auth_admin->acl_clear_prefetch();
}
}
diff --git a/phpBB/includes/acp/acp_permissions.php b/phpBB/includes/acp/acp_permissions.php
index dd071074de..ed7159996a 100644
--- a/phpBB/includes/acp/acp_permissions.php
+++ b/phpBB/includes/acp/acp_permissions.php
@@ -22,15 +22,18 @@ class acp_permissions
{
var $u_action;
var $permission_dropdown;
+ protected $permissions;
function main($id, $mode)
{
- global $db, $user, $auth, $template, $cache;
+ global $db, $user, $auth, $template, $cache, $phpbb_container;
global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
include_once($phpbb_root_path . 'includes/functions_user.' . $phpEx);
include_once($phpbb_root_path . 'includes/acp/auth.' . $phpEx);
+ $this->permissions = $phpbb_container->get('acl.permissions');
+
$auth_admin = new auth_admin();
$user->add_lang('acp/permissions');
@@ -49,7 +52,7 @@ class acp_permissions
if ($user_id && isset($auth_admin->acl_options['id'][$permission]) && $auth->acl_get('a_viewauth'))
{
- $this->page_title = sprintf($user->lang['TRACE_PERMISSION'], $user->lang['acl_' . $permission]['lang']);
+ $this->page_title = sprintf($user->lang['TRACE_PERMISSION'], $this->permissions->get_permission_lang($permission));
$this->permission_trace($user_id, $forum_id, $permission);
return;
}
@@ -512,7 +515,7 @@ class acp_permissions
$template->assign_vars(array(
'S_PERMISSION_DROPDOWN' => (sizeof($this->permission_dropdown) > 1) ? $this->build_permission_dropdown($this->permission_dropdown, $permission_type, $permission_scope) : false,
- 'L_PERMISSION_TYPE' => $user->lang['ACL_TYPE_' . strtoupper($permission_type)],
+ 'L_PERMISSION_TYPE' => $this->permissions->get_type_lang($permission_type),
'U_ACTION' => $this->u_action,
'S_HIDDEN_FIELDS' => $s_hidden_fields)
@@ -587,7 +590,7 @@ class acp_permissions
*/
function build_permission_dropdown($options, $default_option, $permission_scope)
{
- global $user, $auth;
+ global $auth;
$s_dropdown_options = '';
foreach ($options as $setting)
@@ -598,7 +601,7 @@ class acp_permissions
}
$selected = ($setting == $default_option) ? ' selected="selected"' : '';
- $l_setting = (isset($user->lang['permission_type'][$permission_scope][$setting])) ? $user->lang['permission_type'][$permission_scope][$setting] : $user->lang['permission_type'][$setting];
+ $l_setting = $this->permissions->get_type_lang($setting, $permission_scope);
$s_dropdown_options .= '<option value="' . $setting . '"' . $selected . '>' . $l_setting . '</option>';
}
@@ -656,7 +659,7 @@ class acp_permissions
*/
function set_permissions($mode, $permission_type, &$auth_admin, &$user_id, &$group_id)
{
- global $user, $auth;
+ global $db, $cache, $user, $auth;
global $request;
$psubmit = request_var('psubmit', array(0 => array(0 => 0)));
@@ -726,13 +729,13 @@ class acp_permissions
// Do we need to recache the moderator lists?
if ($permission_type == 'm_')
{
- cache_moderators();
+ phpbb_cache_moderators($db, $cache, $auth);
}
// Remove users who are now moderators or admins from everyones foes list
if ($permission_type == 'm_' || $permission_type == 'a_')
{
- update_foes($group_id, $user_id);
+ phpbb_update_foes($db, $auth, $group_id, $user_id);
}
$this->log_action($mode, 'add', $permission_type, $ug_type, $ug_id, $forum_id);
@@ -745,7 +748,7 @@ class acp_permissions
*/
function set_all_permissions($mode, $permission_type, &$auth_admin, &$user_id, &$group_id)
{
- global $user, $auth;
+ global $db, $cache, $user, $auth;
global $request;
// User or group to be set?
@@ -794,13 +797,13 @@ class acp_permissions
// Do we need to recache the moderator lists?
if ($permission_type == 'm_')
{
- cache_moderators();
+ phpbb_cache_moderators($db, $cache, $auth);
}
// Remove users who are now moderators or admins from everyones foes list
if ($permission_type == 'm_' || $permission_type == 'a_')
{
- update_foes($group_id, $user_id);
+ phpbb_update_foes($db, $auth, $group_id, $user_id);
}
$this->log_action($mode, 'add', $permission_type, $ug_type, $ug_ids, $forum_ids);
@@ -858,7 +861,7 @@ class acp_permissions
*/
function remove_permissions($mode, $permission_type, &$auth_admin, &$user_id, &$group_id, &$forum_id)
{
- global $user, $db, $auth;
+ global $user, $db, $cache, $auth;
// User or group to be set?
$ug_type = (sizeof($user_id)) ? 'user' : 'group';
@@ -874,7 +877,7 @@ class acp_permissions
// Do we need to recache the moderator lists?
if ($permission_type == 'm_')
{
- cache_moderators();
+ phpbb_cache_moderators($db, $cache, $auth);
}
$this->log_action($mode, 'del', $permission_type, $ug_type, (($ug_type == 'user') ? $user_id : $group_id), (sizeof($forum_id) ? $forum_id : array(0 => 0)));
@@ -952,12 +955,7 @@ class acp_permissions
if ($user_id != $user->data['user_id'])
{
- $sql = 'SELECT user_id, username, user_permissions, user_type
- FROM ' . USERS_TABLE . '
- WHERE user_id = ' . $user_id;
- $result = $db->sql_query($sql);
- $userdata = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
+ $userdata = $auth->obtain_user_data($user_id);
}
else
{
@@ -984,7 +982,7 @@ class acp_permissions
$back = request_var('back', 0);
$template->assign_vars(array(
- 'PERMISSION' => $user->lang['acl_' . $permission]['lang'],
+ 'PERMISSION' => $this->permissions->get_permission_lang($permission),
'PERMISSION_USERNAME' => $userdata['username'],
'FORUM_NAME' => $forum_name,
@@ -1172,7 +1170,7 @@ class acp_permissions
*/
function copy_forum_permissions()
{
- global $auth, $cache, $template, $user;
+ global $db, $auth, $cache, $template, $user;
$user->add_lang('acp/forums');
@@ -1187,7 +1185,7 @@ class acp_permissions
{
if (copy_forum_permissions($src, $dest))
{
- cache_moderators();
+ phpbb_cache_moderators($db, $cache, $auth);
$auth->acl_clear_prefetch();
$cache->destroy('sql', FORUMS_TABLE);
diff --git a/phpBB/includes/acp/acp_prune.php b/phpBB/includes/acp/acp_prune.php
index a5dc02849a..4234ec1505 100644
--- a/phpBB/includes/acp/acp_prune.php
+++ b/phpBB/includes/acp/acp_prune.php
@@ -331,7 +331,7 @@ class acp_prune
$s_find_active_time .= '<option value="' . $key . '">' . $value . '</option>';
}
- $s_group_list = '';
+ $s_group_list = '<option value="0"></option>';
$sql = 'SELECT group_id, group_name
FROM ' . GROUPS_TABLE . '
WHERE group_type <> ' . GROUP_SPECIAL . '
@@ -340,7 +340,7 @@ class acp_prune
while ($row = $db->sql_fetchrow($result))
{
- $s_group_list .= '<option value="' . $row['group_id'] . '">' . $row['group_name'] . '</select>';
+ $s_group_list .= '<option value="' . $row['group_id'] . '">' . $row['group_name'] . '</option>';
}
$db->sql_freeresult($result);
@@ -491,11 +491,12 @@ class acp_prune
if ($group_id)
{
- $sql = 'SELECT user_id
- FROM ' . USER_GROUP_TABLE . '
- WHERE group_id = ' . (int) $group_id . '
- AND user_pending = 0
- AND ' . $db->sql_in_set('user_id', $user_ids, false, true);
+ $sql = 'SELECT u.user_id, u.username
+ FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u
+ WHERE ug.group_id = ' . (int) $group_id . '
+ AND ug.user_pending = 0
+ AND ' . $db->sql_in_set('ug.user_id', $user_ids, false, true) . '
+ AND u.user_id = ug.user_id';
$result = $db->sql_query($sql);
// we're performing an intersection operation, so all the relevant users
@@ -504,24 +505,19 @@ class acp_prune
$user_ids = $usernames = array();
while ($row = $db->sql_fetchrow($result))
{
- $user_ids[] = $row['poster_id'];
+ $user_ids[] = $row['user_id'];
+ $usernames[$row['user_id']] = $row['username'];
}
$db->sql_freeresult($result);
-
- // only get usernames if they are needed (not part of some later query)
- if (!$posts_on_queue)
- {
- // this is an additional query aginst the users table
- user_get_id_name($user_ids, $usernames);
- }
}
if ($posts_on_queue)
{
- $sql = 'SELECT poster_id, COUNT(post_id) AS queue_posts
- FROM ' . POSTS_TABLE . '
- WHERE ' . $db->sql_in_set('poster_id', $user_ids, false, true) . '
- GROUP BY poster_id
+ $sql = 'SELECT u.user_id, u.username, COUNT(p.post_id) AS queue_posts
+ FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
+ WHERE ' . $db->sql_in_set('p.poster_id', $user_ids, false, true) . '
+ AND u.user_id = p.poster_id
+ GROUP BY p.poster_id
HAVING queue_posts ' . $key_match[$queue_select] . ' ' . $posts_on_queue;
$result = $db->sql_query($result);
@@ -529,12 +525,10 @@ class acp_prune
$user_ids = $usernames = array();
while ($row = $db->sql_fetchrow($result))
{
- $user_ids[] = $row['poster_id'];
+ $user_ids[] = $row['user_id'];
+ $usernames[$row['user_id']] = $row['username'];
}
$db->sql_freeresult($result);
-
- // do an additional query to get the correct set of usernames
- user_get_id_name($user_ids, $usernames);
}
}
}
diff --git a/phpBB/includes/acp/acp_ranks.php b/phpBB/includes/acp/acp_ranks.php
index d9ed5b17f1..6b06d03f52 100644
--- a/phpBB/includes/acp/acp_ranks.php
+++ b/phpBB/includes/acp/acp_ranks.php
@@ -71,7 +71,7 @@ class acp_ranks
'rank_min' => $min_posts,
'rank_image' => htmlspecialchars_decode($rank_image)
);
-
+
if ($rank_id)
{
$sql = 'UPDATE ' . RANKS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . " WHERE rank_id = $rank_id";
@@ -122,7 +122,7 @@ class acp_ranks
$cache->destroy('_ranks');
add_log('admin', 'LOG_RANK_REMOVED', $rank_title);
-
+
if ($request->is_ajax())
{
$json_response = new phpbb_json_response;
@@ -151,7 +151,7 @@ class acp_ranks
case 'add':
$data = $ranks = $existing_imgs = array();
-
+
$sql = 'SELECT *
FROM ' . RANKS_TABLE . '
ORDER BY rank_min ASC, rank_special ASC';
@@ -209,17 +209,17 @@ class acp_ranks
'RANK_TITLE' => (isset($ranks['rank_title'])) ? $ranks['rank_title'] : '',
'S_FILENAME_LIST' => $filename_list,
- 'RANK_IMAGE' => ($edit_img) ? $phpbb_root_path . $config['ranks_path'] . '/' . $edit_img : $phpbb_admin_path . 'images/spacer.gif',
+ 'RANK_IMAGE' => ($edit_img) ? $phpbb_root_path . $config['ranks_path'] . '/' . $edit_img : htmlspecialchars($phpbb_admin_path) . 'images/spacer.gif',
'S_SPECIAL_RANK' => (isset($ranks['rank_special']) && $ranks['rank_special']) ? true : false,
'MIN_POSTS' => (isset($ranks['rank_min']) && !$ranks['rank_special']) ? $ranks['rank_min'] : 0)
);
-
+
return;
break;
}
-
+
$template->assign_vars(array(
'U_ACTION' => $this->u_action)
);
@@ -241,7 +241,7 @@ class acp_ranks
'U_EDIT' => $this->u_action . '&amp;action=edit&amp;id=' . $row['rank_id'],
'U_DELETE' => $this->u_action . '&amp;action=delete&amp;id=' . $row['rank_id'])
- );
+ );
}
$db->sql_freeresult($result);
diff --git a/phpBB/includes/acp/acp_search.php b/phpBB/includes/acp/acp_search.php
index 6618e2c3f9..11a2511aee 100644
--- a/phpBB/includes/acp/acp_search.php
+++ b/phpBB/includes/acp/acp_search.php
@@ -560,7 +560,7 @@ class acp_search
return $finder
->extension_suffix('_backend')
->extension_directory('/search')
- ->core_path('includes/search/')
+ ->core_path('phpbb/search/')
->get_classes();
}
diff --git a/phpBB/includes/acp/acp_send_statistics.php b/phpBB/includes/acp/acp_send_statistics.php
index 4421fbef18..39140b8da4 100644
--- a/phpBB/includes/acp/acp_send_statistics.php
+++ b/phpBB/includes/acp/acp_send_statistics.php
@@ -28,7 +28,7 @@ class acp_send_statistics
include($phpbb_root_path . 'includes/questionnaire/questionnaire.' . $phpEx);
- $collect_url = "http://www.phpbb.com/stats/receive_stats.php";
+ $collect_url = "https://www.phpbb.com/stats/receive_stats.php";
$this->tpl_name = 'acp_send_statistics';
$this->page_title = 'ACP_SEND_STATISTICS';
diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php
index db77825ae7..094d84de40 100644
--- a/phpBB/includes/acp/acp_styles.php
+++ b/phpBB/includes/acp/acp_styles.php
@@ -68,13 +68,20 @@ class acp_styles
$action = $this->request->variable('action', '');
$post_actions = array('install', 'activate', 'deactivate', 'uninstall');
+
+ if ($action && in_array($action, $post_actions) && !check_link_hash($request->variable('hash', ''), $action))
+ {
+ trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+
foreach ($post_actions as $key)
{
- if (isset($_POST[$key]))
+ if ($this->request->is_set_post($key))
{
$action = $key;
}
}
+
if ($action != '')
{
$this->s_hidden_fields['action'] = $action;
@@ -137,11 +144,13 @@ class acp_styles
*/
protected function action_cache()
{
+ global $db, $cache, $auth;
+
$this->cache->purge();
// Clear permissions
$this->auth->acl_clear_prefetch();
- cache_moderators();
+ phpbb_cache_moderators($db, $cache, $auth);
add_log('admin', 'LOG_PURGE_CACHE');
@@ -919,21 +928,23 @@ class acp_styles
'L_ACTION' => $this->user->lang['DETAILS']
);
- // Activate
+ // Activate/Deactive
+ $action_name = ($style['style_active'] ? 'de' : '') . 'activate';
+
$actions[] = array(
- 'U_ACTION' => $this->u_action . '&amp;action=' . ($style['style_active'] ? 'de' : '') . 'activate&amp;id=' . $style['style_id'],
+ 'U_ACTION' => $this->u_action . '&amp;action=' . $action_name . '&amp;hash=' . generate_link_hash($action_name) . '&amp;id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['STYLE_' . ($style['style_active'] ? 'DE' : '') . 'ACTIVATE']
);
/* // Export
$actions[] = array(
- 'U_ACTION' => $this->u_action . '&amp;action=export&amp;id=' . $style['style_id'],
+ 'U_ACTION' => $this->u_action . '&amp;action=export&amp;hash=' . generate_link_hash('export') . '&amp;id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['EXPORT']
); */
// Uninstall
$actions[] = array(
- 'U_ACTION' => $this->u_action . '&amp;action=uninstall&amp;id=' . $style['style_id'],
+ 'U_ACTION' => $this->u_action . '&amp;action=uninstall&amp;hash=' . generate_link_hash('uninstall') . '&amp;id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['STYLE_UNINSTALL']
);
@@ -955,7 +966,7 @@ class acp_styles
else
{
$actions[] = array(
- 'U_ACTION' => $this->u_action . '&amp;action=install&amp;dir=' . urlencode($style['style_path']),
+ 'U_ACTION' => $this->u_action . '&amp;action=install&amp;hash=' . generate_link_hash('install') . '&amp;dir=' . urlencode($style['style_path']),
'L_ACTION' => $this->user->lang['INSTALL_STYLE']
);
}
diff --git a/phpBB/includes/acp/acp_update.php b/phpBB/includes/acp/acp_update.php
index f7f003781d..6b5407067d 100644
--- a/phpBB/includes/acp/acp_update.php
+++ b/phpBB/includes/acp/acp_update.php
@@ -38,7 +38,7 @@ class acp_update
$info = obtain_latest_version_info(request_var('versioncheck_force', false));
- if ($info === false)
+ if (empty($info))
{
trigger_error('VERSIONCHECK_FAIL', E_USER_WARNING);
}
diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php
index 82d8ef5cbb..cbfd578d87 100644
--- a/phpBB/includes/acp/acp_users.php
+++ b/phpBB/includes/acp/acp_users.php
@@ -33,6 +33,7 @@ class acp_users
global $config, $db, $user, $auth, $template, $cache;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix, $file_uploads;
global $phpbb_dispatcher, $request;
+ global $phpbb_container;
$user->add_lang(array('posting', 'ucp', 'acp/users'));
$this->tpl_name = 'acp_users';
@@ -346,7 +347,7 @@ class acp_users
$messenger->template($email_template, $user_row['user_lang']);
- $messenger->to($user_row['user_email'], $user_row['username']);
+ $messenger->set_addresses($user_row);
$messenger->anti_abuse_headers($config, $user);
@@ -401,7 +402,7 @@ class acp_users
$messenger->template('admin_welcome_activated', $user_row['user_lang']);
- $messenger->to($user_row['user_email'], $user_row['username']);
+ $messenger->set_addresses($user_row);
$messenger->anti_abuse_headers($config, $user);
@@ -456,7 +457,7 @@ class acp_users
$sql_ary = array(
'user_avatar' => '',
- 'user_avatar_type' => 0,
+ 'user_avatar_type' => '',
'user_avatar_width' => 0,
'user_avatar_height' => 0,
);
@@ -467,9 +468,11 @@ class acp_users
$db->sql_query($sql);
// Delete old avatar if present
- if ($user_row['user_avatar'] && $user_row['user_avatar_type'] != AVATAR_GALLERY)
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $driver = $phpbb_avatar_manager->get_driver($user_row['user_avatar_type']);
+ if ($driver)
{
- avatar_delete('user', $user_row);
+ $driver->delete($user_row);
}
add_log('admin', 'LOG_USER_DEL_AVATAR', $user_row['username']);
@@ -621,29 +624,31 @@ class acp_users
$topic_id_ary = $move_topic_ary = $move_post_ary = $new_topic_id_ary = array();
$forum_id_ary = array($new_forum_id);
- $sql = 'SELECT topic_id, COUNT(post_id) AS total_posts
+ $sql = 'SELECT topic_id, post_visibility, COUNT(post_id) AS total_posts
FROM ' . POSTS_TABLE . "
WHERE poster_id = $user_id
AND forum_id <> $new_forum_id
- GROUP BY topic_id";
+ GROUP BY topic_id, post_visibility";
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
- $topic_id_ary[$row['topic_id']] = $row['total_posts'];
+ $topic_id_ary[$row['topic_id']][$row['post_visibility']] = $row['total_posts'];
}
$db->sql_freeresult($result);
if (sizeof($topic_id_ary))
{
- $sql = 'SELECT topic_id, forum_id, topic_title, topic_replies, topic_replies_real, topic_attachment
+ $sql = 'SELECT topic_id, forum_id, topic_title, topic_posts_approved, topic_posts_unapproved, topic_posts_softdeleted, topic_attachment
FROM ' . TOPICS_TABLE . '
WHERE ' . $db->sql_in_set('topic_id', array_keys($topic_id_ary));
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
- if (max($row['topic_replies'], $row['topic_replies_real']) + 1 == $topic_id_ary[$row['topic_id']])
+ if ($topic_id_ary[$row['topic_id']][ITEM_APPROVED] == $row['topic_posts_approved']
+ && $topic_id_ary[$row['topic_id']][ITEM_UNAPPROVED] == $row['topic_posts_unapproved']
+ && $topic_id_ary[$row['topic_id']][ITEM_DELETED] == $row['topic_posts_softdeleted'])
{
$move_topic_ary[] = $row['topic_id'];
}
@@ -676,7 +681,7 @@ class acp_users
'topic_time' => time(),
'forum_id' => $new_forum_id,
'icon_id' => 0,
- 'topic_approved' => 1,
+ 'topic_visibility' => ITEM_APPROVED,
'topic_title' => $post_ary['title'],
'topic_first_poster_name' => $user_row['username'],
'topic_type' => POST_NORMAL,
@@ -1033,7 +1038,7 @@ class acp_users
$sql = 'SELECT COUNT(post_id) as posts_in_queue
FROM ' . POSTS_TABLE . '
WHERE poster_id = ' . $user_id . '
- AND post_approved = 0';
+ AND post_visibility = ' . ITEM_UNAPPROVED;
$result = $db->sql_query($sql);
$user_row['posts_in_queue'] = (int) $db->sql_fetchfield('posts_in_queue');
$db->sql_freeresult($result);
@@ -1728,65 +1733,120 @@ class acp_users
case 'avatar':
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
- include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
- $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false;
+ $avatars_enabled = false;
- if ($submit)
+ if ($config['allow_avatar'])
{
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers();
- if (!check_form_key($form_name))
+ // This is normalised data, without the user_ prefix
+ $avatar_data = phpbb_avatar_manager::clean_row($user_row);
+
+ if ($submit)
{
+ if (check_form_key($form_name))
+ {
+ $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', ''));
+
+ if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete'))
+ {
+ $driver = $phpbb_avatar_manager->get_driver($driver_name);
+ $result = $driver->process_form($request, $template, $user, $avatar_data, $error);
+
+ if ($result && empty($error))
+ {
+ // Success! Lets save the result in the database
+ $result = array(
+ 'user_avatar_type' => $driver_name,
+ 'user_avatar' => $result['avatar'],
+ 'user_avatar_width' => $result['avatar_width'],
+ 'user_avatar_height' => $result['avatar_height'],
+ );
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $result) . '
+ WHERE user_id = ' . (int) $user_id;
+
+ $db->sql_query($sql);
+ trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
+ }
+ }
+ else
+ {
+ $driver = $phpbb_avatar_manager->get_driver($user->data['user_avatar_type']);
+ if ($driver)
+ {
+ $driver->delete($avatar_data);
+ }
+
+ // Removing the avatar
+ $result = array(
+ 'user_avatar' => '',
+ 'user_avatar_type' => '',
+ 'user_avatar_width' => 0,
+ 'user_avatar_height' => 0,
+ );
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $result) . '
+ WHERE user_id = ' . (int) $user_id;
+
+ $db->sql_query($sql);
+ trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
+ }
+ }
+ else
+ {
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&amp;u=' . $user_id), E_USER_WARNING);
+ }
}
- if (avatar_process_user($error, $user_row, $can_upload))
- {
- trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&amp;u=' . $user_row['user_id']));
- }
+ $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user_row['user_avatar_type']));
- // Replace "error" strings with their real, localised form
- $error = array_map(array($user, 'lang'), $error);
- }
+ foreach ($avatar_drivers as $current_driver)
+ {
+ $driver = $phpbb_avatar_manager->get_driver($current_driver);
- 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'];
- }
+ $avatars_enabled = true;
+ $config_name = $phpbb_avatar_manager->get_driver_config_name($driver);
+ $template->set_filenames(array(
+ 'avatar' => "acp_avatar_options_{$config_name}.html",
+ ));
- // 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'], 'USER_AVATAR', true) : '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />';
+ if ($driver->prepare_form($request, $template, $user, $avatar_data, $error))
+ {
+ $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver);
+ $driver_upper = strtoupper($driver_name);
- $display_gallery = (isset($_POST['display_gallery'])) ? true : false;
- $avatar_select = basename(request_var('avatar_select', ''));
- $category = basename(request_var('category', ''));
+ $template->assign_block_vars('avatar_drivers', array(
+ 'L_TITLE' => $user->lang($driver_upper . '_TITLE'),
+ 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'),
- if ($config['allow_avatar_local'] && $display_gallery)
- {
- avatar_gallery($category, $avatar_select, 4);
+ 'DRIVER' => $driver_name,
+ 'SELECTED' => $current_driver == $selected_driver,
+ 'OUTPUT' => $template->assign_display('avatar'),
+ ));
+ }
+ }
}
+ // Replace "error" strings with their real, localised form
+ $error = $phpbb_avatar_manager->localize_errors($user, $error);
+
+ $avatar = phpbb_get_user_avatar($user_row, 'USER_AVATAR', true);
+
$template->assign_vars(array(
- 'S_AVATAR' => true,
- 'S_CAN_UPLOAD' => $can_upload,
- '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'],
- 'USER_AVATAR_WIDTH' => $user_row['user_avatar_width'],
- 'USER_AVATAR_HEIGHT' => $user_row['user_avatar_height'],
-
- 'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(),
+ 'S_AVATAR' => true,
+ 'ERROR' => (!empty($error)) ? implode('<br />', $error) : '',
+ 'AVATAR' => (empty($avatar) ? '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />' : $avatar),
+
+ 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"',
+
+ 'L_AVATAR_EXPLAIN' => sprintf($user->lang['AVATAR_EXPLAIN'], $config['avatar_max_width'], $config['avatar_max_height'], $config['avatar_filesize'] / 1024),
+
+ 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
));
break;
diff --git a/phpBB/includes/acp/auth.php b/phpBB/includes/acp/auth.php
index 6b1da46a12..4ade9cab13 100644
--- a/phpBB/includes/acp/auth.php
+++ b/phpBB/includes/acp/auth.php
@@ -261,7 +261,8 @@ class auth_admin extends phpbb_auth
*/
function display_mask($mode, $permission_type, &$hold_ary, $user_mode = 'user', $local = false, $group_display = true)
{
- global $template, $user, $db, $phpbb_root_path, $phpEx;
+ global $template, $user, $db, $phpbb_root_path, $phpEx, $phpbb_container;
+ $phpbb_permissions = $phpbb_container->get('acl.permissions');
// Define names for template loops, might be able to be set
$tpl_pmask = 'p_mask';
@@ -269,7 +270,7 @@ class auth_admin extends phpbb_auth
$tpl_category = 'category';
$tpl_mask = 'mask';
- $l_acl_type = (isset($user->lang['ACL_TYPE_' . (($local) ? 'LOCAL' : 'GLOBAL') . '_' . strtoupper($permission_type)])) ? $user->lang['ACL_TYPE_' . (($local) ? 'LOCAL' : 'GLOBAL') . '_' . strtoupper($permission_type)] : 'ACL_TYPE_' . (($local) ? 'LOCAL' : 'GLOBAL') . '_' . strtoupper($permission_type);
+ $l_acl_type = $phpbb_permissions->get_type_lang($permission_type, (($local) ? 'local' : 'global'));
// Allow trace for viewing permissions and in user mode
$show_trace = ($mode == 'view' && $user_mode == 'user') ? true : false;
@@ -1100,7 +1101,9 @@ class auth_admin extends phpbb_auth
*/
function assign_cat_array(&$category_array, $tpl_cat, $tpl_mask, $ug_id, $forum_id, $show_trace = false, $s_view)
{
- global $template, $user, $phpbb_admin_path, $phpEx;
+ global $template, $user, $phpbb_admin_path, $phpEx, $phpbb_container;
+
+ $phpbb_permissions = $phpbb_container->get('acl.permissions');
@reset($category_array);
while (list($cat, $cat_array) = each($category_array))
@@ -1110,8 +1113,8 @@ class auth_admin extends phpbb_auth
'S_NEVER' => ($cat_array['S_NEVER'] && !$cat_array['S_YES'] && !$cat_array['S_NO']) ? true : false,
'S_NO' => ($cat_array['S_NO'] && !$cat_array['S_NEVER'] && !$cat_array['S_YES']) ? true : false,
- 'CAT_NAME' => $user->lang['permission_cat'][$cat])
- );
+ 'CAT_NAME' => $phpbb_permissions->get_category_lang($cat),
+ ));
/* Sort permissions by name (more naturaly and user friendly than sorting by a primary key)
* Commented out due to it's memory consumption and time needed
@@ -1145,8 +1148,8 @@ class auth_admin extends phpbb_auth
'U_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&amp;mode=trace&amp;u=$ug_id&amp;f=$forum_id&amp;auth=$permission") : '',
'UA_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission", false) : '',
- 'PERMISSION' => $user->lang['acl_' . $permission]['lang'])
- );
+ 'PERMISSION' => $phpbb_permissions->get_permission_lang($permission),
+ ));
}
else
{
@@ -1163,8 +1166,8 @@ class auth_admin extends phpbb_auth
'U_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&amp;mode=trace&amp;u=$ug_id&amp;f=$forum_id&amp;auth=$permission") : '',
'UA_TRACE' => ($show_trace) ? append_sid("{$phpbb_admin_path}index.$phpEx", "i=permissions&mode=trace&u=$ug_id&f=$forum_id&auth=$permission", false) : '',
- 'PERMISSION' => $user->lang['acl_' . $permission]['lang'])
- );
+ 'PERMISSION' => $phpbb_permissions->get_permission_lang($permission),
+ ));
}
}
}
@@ -1176,7 +1179,9 @@ class auth_admin extends phpbb_auth
*/
function build_permission_array(&$permission_row, &$content_array, &$categories, $key_sort_array)
{
- global $user;
+ global $user, $phpbb_container;
+
+ $phpbb_permissions = $phpbb_container->get('acl.permissions');
foreach ($key_sort_array as $forum_id)
{
@@ -1191,20 +1196,12 @@ class auth_admin extends phpbb_auth
@reset($permissions);
while (list($permission, $auth_setting) = each($permissions))
{
- if (!isset($user->lang['acl_' . $permission]))
- {
- $user->lang['acl_' . $permission] = array(
- 'cat' => 'misc',
- 'lang' => '{ acl_' . $permission . ' }'
- );
- }
-
- $cat = $user->lang['acl_' . $permission]['cat'];
+ $cat = $phpbb_permissions->get_permission_category($permission);
// Build our categories array
if (!isset($categories[$cat]))
{
- $categories[$cat] = $user->lang['permission_cat'][$cat];
+ $categories[$cat] = $phpbb_permissions->get_category_lang($cat);
}
// Build our content array
diff --git a/phpBB/includes/acp/info/acp_extensions.php b/phpBB/includes/acp/info/acp_extensions.php
index f5953fb1dd..174b365af0 100644
--- a/phpBB/includes/acp/info/acp_extensions.php
+++ b/phpBB/includes/acp/info/acp_extensions.php
@@ -16,10 +16,10 @@ class acp_extensions_info
{
return array(
'filename' => 'acp_extensions',
- 'title' => 'ACP_EXTENSIONS',
+ 'title' => 'ACP_EXTENSION_MANAGEMENT',
'version' => '1.0.0',
'modes' => array(
- 'main' => array('title' => 'ACP_EXTENSIONS', 'auth' => 'acl_a_extensions', 'cat' => array('ACP_GENERAL_TASKS')),
+ 'main' => array('title' => 'ACP_EXTENSIONS', 'auth' => 'acl_a_extensions', 'cat' => array('ACP_EXTENSION_MANAGEMENT')),
),
);
}
diff --git a/phpBB/includes/acp/info/acp_language.php b/phpBB/includes/acp/info/acp_language.php
index 85dfb119ea..7f33a22fa6 100644
--- a/phpBB/includes/acp/info/acp_language.php
+++ b/phpBB/includes/acp/info/acp_language.php
@@ -19,7 +19,7 @@ class acp_language_info
'title' => 'ACP_LANGUAGE',
'version' => '1.0.0',
'modes' => array(
- 'lang_packs' => array('title' => 'ACP_LANGUAGE_PACKS', 'auth' => 'acl_a_language', 'cat' => array('ACP_GENERAL_TASKS')),
+ 'lang_packs' => array('title' => 'ACP_LANGUAGE_PACKS', 'auth' => 'acl_a_language', 'cat' => array('ACP_LANGUAGE')),
),
);
}
diff --git a/phpBB/includes/auth/auth.php b/phpBB/includes/auth/auth.php
deleted file mode 100644
index e3bccaf47b..0000000000
--- a/phpBB/includes/auth/auth.php
+++ /dev/null
@@ -1,1061 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Permission/Auth class
-* @package phpBB3
-*/
-class phpbb_auth
-{
- var $acl = array();
- var $cache = array();
- var $acl_options = array();
- var $acl_forum_ids = false;
-
- /**
- * Init permissions
- */
- function acl(&$userdata)
- {
- global $db, $cache;
-
- $this->acl = $this->cache = $this->acl_options = array();
- $this->acl_forum_ids = false;
-
- if (($this->acl_options = $cache->get('_acl_options')) === false)
- {
- $sql = 'SELECT auth_option_id, auth_option, is_global, is_local
- FROM ' . ACL_OPTIONS_TABLE . '
- ORDER BY auth_option_id';
- $result = $db->sql_query($sql);
-
- $global = $local = 0;
- $this->acl_options = array();
- while ($row = $db->sql_fetchrow($result))
- {
- if ($row['is_global'])
- {
- $this->acl_options['global'][$row['auth_option']] = $global++;
- }
-
- if ($row['is_local'])
- {
- $this->acl_options['local'][$row['auth_option']] = $local++;
- }
-
- $this->acl_options['id'][$row['auth_option']] = (int) $row['auth_option_id'];
- $this->acl_options['option'][(int) $row['auth_option_id']] = $row['auth_option'];
- }
- $db->sql_freeresult($result);
-
- $cache->put('_acl_options', $this->acl_options);
- }
-
- if (!trim($userdata['user_permissions']))
- {
- $this->acl_cache($userdata);
- }
-
- // Fill ACL array
- $this->_fill_acl($userdata['user_permissions']);
-
- // Verify bitstring length with options provided...
- $renew = false;
- $global_length = sizeof($this->acl_options['global']);
- $local_length = sizeof($this->acl_options['local']);
-
- // Specify comparing length (bitstring is padded to 31 bits)
- $global_length = ($global_length % 31) ? ($global_length - ($global_length % 31) + 31) : $global_length;
- $local_length = ($local_length % 31) ? ($local_length - ($local_length % 31) + 31) : $local_length;
-
- // You thought we are finished now? Noooo... now compare them.
- foreach ($this->acl as $forum_id => $bitstring)
- {
- if (($forum_id && strlen($bitstring) != $local_length) || (!$forum_id && strlen($bitstring) != $global_length))
- {
- $renew = true;
- break;
- }
- }
-
- // If a bitstring within the list does not match the options, we have a user with incorrect permissions set and need to renew them
- if ($renew)
- {
- $this->acl_cache($userdata);
- $this->_fill_acl($userdata['user_permissions']);
- }
-
- return;
- }
-
- /**
- * Fill ACL array with relevant bitstrings from user_permissions column
- * @access private
- */
- function _fill_acl($user_permissions)
- {
- $seq_cache = array();
- $this->acl = array();
- $user_permissions = explode("\n", $user_permissions);
-
- foreach ($user_permissions as $f => $seq)
- {
- if ($seq)
- {
- $i = 0;
-
- if (!isset($this->acl[$f]))
- {
- $this->acl[$f] = '';
- }
-
- while ($subseq = substr($seq, $i, 6))
- {
- if (isset($seq_cache[$subseq]))
- {
- $converted = $seq_cache[$subseq];
- }
- else
- {
- $converted = $seq_cache[$subseq] = str_pad(base_convert($subseq, 36, 2), 31, 0, STR_PAD_LEFT);
- }
-
- // We put the original bitstring into the acl array
- $this->acl[$f] .= $converted;
- $i += 6;
- }
- }
- }
- }
-
- /**
- * Look up an option
- * if the option is prefixed with !, then the result becomes negated
- *
- * If a forum id is specified the local option will be combined with a global option if one exist.
- * If a forum id is not specified, only the global option will be checked.
- */
- function acl_get($opt, $f = 0)
- {
- $negate = false;
-
- if (strpos($opt, '!') === 0)
- {
- $negate = true;
- $opt = substr($opt, 1);
- }
-
- if (!isset($this->cache[$f][$opt]))
- {
- // We combine the global/local option with an OR because some options are global and local.
- // If the user has the global permission the local one is true too and vice versa
- $this->cache[$f][$opt] = false;
-
- // Is this option a global permission setting?
- if (isset($this->acl_options['global'][$opt]))
- {
- if (isset($this->acl[0]))
- {
- $this->cache[$f][$opt] = $this->acl[0][$this->acl_options['global'][$opt]];
- }
- }
-
- // Is this option a local permission setting?
- // But if we check for a global option only, we won't combine the options...
- if ($f != 0 && isset($this->acl_options['local'][$opt]))
- {
- if (isset($this->acl[$f]) && isset($this->acl[$f][$this->acl_options['local'][$opt]]))
- {
- $this->cache[$f][$opt] |= $this->acl[$f][$this->acl_options['local'][$opt]];
- }
- }
- }
-
- // Founder always has all global options set to true...
- return ($negate) ? !$this->cache[$f][$opt] : $this->cache[$f][$opt];
- }
-
- /**
- * Get forums with the specified permission setting
- * if the option is prefixed with !, then the result becomes nagated
- *
- * @param bool $clean set to true if only values needs to be returned which are set/unset
- */
- function acl_getf($opt, $clean = false)
- {
- $acl_f = array();
- $negate = false;
-
- if (strpos($opt, '!') === 0)
- {
- $negate = true;
- $opt = substr($opt, 1);
- }
-
- // If we retrieve a list of forums not having permissions in, we need to get every forum_id
- if ($negate)
- {
- if ($this->acl_forum_ids === false)
- {
- global $db;
-
- $sql = 'SELECT forum_id
- FROM ' . FORUMS_TABLE;
-
- if (sizeof($this->acl))
- {
- $sql .= ' WHERE ' . $db->sql_in_set('forum_id', array_keys($this->acl), true);
- }
- $result = $db->sql_query($sql);
-
- $this->acl_forum_ids = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $this->acl_forum_ids[] = $row['forum_id'];
- }
- $db->sql_freeresult($result);
- }
- }
-
- if (isset($this->acl_options['local'][$opt]))
- {
- foreach ($this->acl as $f => $bitstring)
- {
- // Skip global settings
- if (!$f)
- {
- continue;
- }
-
- $allowed = (!isset($this->cache[$f][$opt])) ? $this->acl_get($opt, $f) : $this->cache[$f][$opt];
-
- if (!$clean)
- {
- $acl_f[$f][$opt] = ($negate) ? !$allowed : $allowed;
- }
- else
- {
- if (($negate && !$allowed) || (!$negate && $allowed))
- {
- $acl_f[$f][$opt] = 1;
- }
- }
- }
- }
-
- // If we get forum_ids not having this permission, we need to fill the remaining parts
- if ($negate && sizeof($this->acl_forum_ids))
- {
- foreach ($this->acl_forum_ids as $f)
- {
- $acl_f[$f][$opt] = 1;
- }
- }
-
- return $acl_f;
- }
-
- /**
- * Get local permission state for any forum.
- *
- * Returns true if user has the permission in one or more forums, false if in no forum.
- * If global option is checked it returns the global state (same as acl_get($opt))
- * Local option has precedence...
- */
- function acl_getf_global($opt)
- {
- if (is_array($opt))
- {
- // evaluates to true as soon as acl_getf_global is true for one option
- foreach ($opt as $check_option)
- {
- if ($this->acl_getf_global($check_option))
- {
- return true;
- }
- }
-
- return false;
- }
-
- if (isset($this->acl_options['local'][$opt]))
- {
- foreach ($this->acl as $f => $bitstring)
- {
- // Skip global settings
- if (!$f)
- {
- continue;
- }
-
- // as soon as the user has any permission we're done so return true
- if ((!isset($this->cache[$f][$opt])) ? $this->acl_get($opt, $f) : $this->cache[$f][$opt])
- {
- return true;
- }
- }
- }
- else if (isset($this->acl_options['global'][$opt]))
- {
- return $this->acl_get($opt);
- }
-
- return false;
- }
-
- /**
- * Get permission settings (more than one)
- */
- function acl_gets()
- {
- $args = func_get_args();
- $f = array_pop($args);
-
- if (!is_numeric($f))
- {
- $args[] = $f;
- $f = 0;
- }
-
- // alternate syntax: acl_gets(array('m_', 'a_'), $forum_id)
- if (is_array($args[0]))
- {
- $args = $args[0];
- }
-
- $acl = 0;
- foreach ($args as $opt)
- {
- $acl |= $this->acl_get($opt, $f);
- }
-
- return $acl;
- }
-
- /**
- * Get permission listing based on user_id/options/forum_ids
- *
- * Be careful when using this function with permissions a_, m_, u_ and f_ !
- * It may not work correctly. When a user group grants an a_* permission,
- * e.g. a_foo, but the user's a_foo permission is set to "Never", then
- * the user does not in fact have the a_ permission.
- * But the user will still be listed as having the a_ permission.
- *
- * For more information see: http://tracker.phpbb.com/browse/PHPBB3-10252
- */
- function acl_get_list($user_id = false, $opts = false, $forum_id = false)
- {
- if ($user_id !== false && !is_array($user_id) && $opts === false && $forum_id === false)
- {
- $hold_ary = array($user_id => $this->acl_raw_data_single_user($user_id));
- }
- else
- {
- $hold_ary = $this->acl_raw_data($user_id, $opts, $forum_id);
- }
-
- $auth_ary = array();
- foreach ($hold_ary as $user_id => $forum_ary)
- {
- foreach ($forum_ary as $forum_id => $auth_option_ary)
- {
- foreach ($auth_option_ary as $auth_option => $auth_setting)
- {
- if ($auth_setting)
- {
- $auth_ary[$forum_id][$auth_option][] = $user_id;
- }
- }
- }
- }
-
- return $auth_ary;
- }
-
- /**
- * Cache data to user_permissions row
- */
- function acl_cache(&$userdata)
- {
- global $db;
-
- // Empty user_permissions
- $userdata['user_permissions'] = '';
-
- $hold_ary = $this->acl_raw_data_single_user($userdata['user_id']);
-
- // Key 0 in $hold_ary are global options, all others are forum_ids
-
- // If this user is founder we're going to force fill the admin options ...
- if ($userdata['user_type'] == USER_FOUNDER)
- {
- foreach ($this->acl_options['global'] as $opt => $id)
- {
- if (strpos($opt, 'a_') === 0)
- {
- $hold_ary[0][$this->acl_options['id'][$opt]] = ACL_YES;
- }
- }
- }
-
- $hold_str = $this->build_bitstring($hold_ary);
-
- if ($hold_str)
- {
- $userdata['user_permissions'] = $hold_str;
-
- $sql = 'UPDATE ' . USERS_TABLE . "
- SET user_permissions = '" . $db->sql_escape($userdata['user_permissions']) . "',
- user_perm_from = 0
- WHERE user_id = " . $userdata['user_id'];
- $db->sql_query($sql);
- }
-
- return;
- }
-
- /**
- * Build bitstring from permission set
- */
- function build_bitstring(&$hold_ary)
- {
- $hold_str = '';
-
- if (sizeof($hold_ary))
- {
- ksort($hold_ary);
-
- $last_f = 0;
-
- foreach ($hold_ary as $f => $auth_ary)
- {
- $ary_key = (!$f) ? 'global' : 'local';
-
- $bitstring = array();
- foreach ($this->acl_options[$ary_key] as $opt => $id)
- {
- if (isset($auth_ary[$this->acl_options['id'][$opt]]))
- {
- $bitstring[$id] = $auth_ary[$this->acl_options['id'][$opt]];
-
- $option_key = substr($opt, 0, strpos($opt, '_') + 1);
-
- // If one option is allowed, the global permission for this option has to be allowed too
- // example: if the user has the a_ permission this means he has one or more a_* permissions
- if ($auth_ary[$this->acl_options['id'][$opt]] == ACL_YES && (!isset($bitstring[$this->acl_options[$ary_key][$option_key]]) || $bitstring[$this->acl_options[$ary_key][$option_key]] == ACL_NEVER))
- {
- $bitstring[$this->acl_options[$ary_key][$option_key]] = ACL_YES;
- }
- }
- else
- {
- $bitstring[$id] = ACL_NEVER;
- }
- }
-
- // Now this bitstring defines the permission setting for the current forum $f (or global setting)
- $bitstring = implode('', $bitstring);
-
- // The line number indicates the id, therefore we have to add empty lines for those ids not present
- $hold_str .= str_repeat("\n", $f - $last_f);
-
- // Convert bitstring for storage - we do not use binary/bytes because PHP's string functions are not fully binary safe
- for ($i = 0, $bit_length = strlen($bitstring); $i < $bit_length; $i += 31)
- {
- $hold_str .= str_pad(base_convert(str_pad(substr($bitstring, $i, 31), 31, 0, STR_PAD_RIGHT), 2, 36), 6, 0, STR_PAD_LEFT);
- }
-
- $last_f = $f;
- }
- unset($bitstring);
-
- $hold_str = rtrim($hold_str);
- }
-
- return $hold_str;
- }
-
- /**
- * Clear one or all users cached permission settings
- */
- function acl_clear_prefetch($user_id = false)
- {
- global $db, $cache;
-
- // Rebuild options cache
- $cache->destroy('_role_cache');
-
- $sql = 'SELECT *
- FROM ' . ACL_ROLES_DATA_TABLE . '
- ORDER BY role_id ASC';
- $result = $db->sql_query($sql);
-
- $this->role_cache = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $this->role_cache[$row['role_id']][$row['auth_option_id']] = (int) $row['auth_setting'];
- }
- $db->sql_freeresult($result);
-
- foreach ($this->role_cache as $role_id => $role_options)
- {
- $this->role_cache[$role_id] = serialize($role_options);
- }
-
- $cache->put('_role_cache', $this->role_cache);
-
- // Now empty user permissions
- $where_sql = '';
-
- if ($user_id !== false)
- {
- $user_id = (!is_array($user_id)) ? $user_id = array((int) $user_id) : array_map('intval', $user_id);
- $where_sql = ' WHERE ' . $db->sql_in_set('user_id', $user_id);
- }
-
- $sql = 'UPDATE ' . USERS_TABLE . "
- SET user_permissions = '',
- user_perm_from = 0
- $where_sql";
- $db->sql_query($sql);
-
- return;
- }
-
- /**
- * Get assigned roles
- */
- function acl_role_data($user_type, $role_type, $ug_id = false, $forum_id = false)
- {
- global $db;
-
- $roles = array();
-
- $sql_id = ($user_type == 'user') ? 'user_id' : 'group_id';
-
- $sql_ug = ($ug_id !== false) ? ((!is_array($ug_id)) ? "AND a.$sql_id = $ug_id" : 'AND ' . $db->sql_in_set("a.$sql_id", $ug_id)) : '';
- $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? "AND a.forum_id = $forum_id" : 'AND ' . $db->sql_in_set('a.forum_id', $forum_id)) : '';
-
- // Grab assigned roles...
- $sql = 'SELECT a.auth_role_id, a.' . $sql_id . ', a.forum_id
- FROM ' . (($user_type == 'user') ? ACL_USERS_TABLE : ACL_GROUPS_TABLE) . ' a, ' . ACL_ROLES_TABLE . " r
- WHERE a.auth_role_id = r.role_id
- AND r.role_type = '" . $db->sql_escape($role_type) . "'
- $sql_ug
- $sql_forum
- ORDER BY r.role_order ASC";
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $roles[$row[$sql_id]][$row['forum_id']] = $row['auth_role_id'];
- }
- $db->sql_freeresult($result);
-
- return $roles;
- }
-
- /**
- * Get raw acl data based on user/option/forum
- */
- function acl_raw_data($user_id = false, $opts = false, $forum_id = false)
- {
- global $db;
-
- $sql_user = ($user_id !== false) ? ((!is_array($user_id)) ? 'user_id = ' . (int) $user_id : $db->sql_in_set('user_id', array_map('intval', $user_id))) : '';
- $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : '';
-
- $sql_opts = $sql_opts_select = $sql_opts_from = '';
- $hold_ary = array();
-
- if ($opts !== false)
- {
- $sql_opts_select = ', ao.auth_option';
- $sql_opts_from = ', ' . ACL_OPTIONS_TABLE . ' ao';
- $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts);
- }
-
- $sql_ary = array();
-
- // Grab non-role settings - user-specific
- $sql_ary[] = 'SELECT a.user_id, a.forum_id, a.auth_setting, a.auth_option_id' . $sql_opts_select . '
- FROM ' . ACL_USERS_TABLE . ' a' . $sql_opts_from . '
- WHERE a.auth_role_id = 0 ' .
- (($sql_opts_from) ? 'AND a.auth_option_id = ao.auth_option_id ' : '') .
- (($sql_user) ? 'AND a.' . $sql_user : '') . "
- $sql_forum
- $sql_opts";
-
- // Now the role settings - user-specific
- $sql_ary[] = 'SELECT a.user_id, a.forum_id, r.auth_option_id, r.auth_setting, r.auth_option_id' . $sql_opts_select . '
- FROM ' . ACL_USERS_TABLE . ' a, ' . 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 ' : '') .
- (($sql_user) ? 'AND a.' . $sql_user : '') . "
- $sql_forum
- $sql_opts";
-
- foreach ($sql_ary as $sql)
- {
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $option = ($sql_opts_select) ? $row['auth_option'] : $this->acl_options['option'][$row['auth_option_id']];
- $hold_ary[$row['user_id']][$row['forum_id']][$option] = $row['auth_setting'];
- }
- $db->sql_freeresult($result);
- }
-
- $sql_ary = array();
-
- // 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, ' . 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, ' . 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";
-
- foreach ($sql_ary as $sql)
- {
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $option = ($sql_opts_select) ? $row['auth_option'] : $this->acl_options['option'][$row['auth_option_id']];
-
- if (!isset($hold_ary[$row['user_id']][$row['forum_id']][$option]) || (isset($hold_ary[$row['user_id']][$row['forum_id']][$option]) && $hold_ary[$row['user_id']][$row['forum_id']][$option] != ACL_NEVER))
- {
- $hold_ary[$row['user_id']][$row['forum_id']][$option] = $row['auth_setting'];
-
- // If we detect ACL_NEVER, we will unset the flag option (within building the bitstring it is correctly set again)
- if ($row['auth_setting'] == ACL_NEVER)
- {
- $flag = substr($option, 0, strpos($option, '_') + 1);
-
- if (isset($hold_ary[$row['user_id']][$row['forum_id']][$flag]) && $hold_ary[$row['user_id']][$row['forum_id']][$flag] == ACL_YES)
- {
- unset($hold_ary[$row['user_id']][$row['forum_id']][$flag]);
-
-/* if (in_array(ACL_YES, $hold_ary[$row['user_id']][$row['forum_id']]))
- {
- $hold_ary[$row['user_id']][$row['forum_id']][$flag] = ACL_YES;
- }
-*/
- }
- }
- }
- }
- $db->sql_freeresult($result);
- }
-
- return $hold_ary;
- }
-
- /**
- * Get raw user based permission settings
- */
- function acl_user_raw_data($user_id = false, $opts = false, $forum_id = false)
- {
- global $db;
-
- $sql_user = ($user_id !== false) ? ((!is_array($user_id)) ? 'user_id = ' . (int) $user_id : $db->sql_in_set('user_id', array_map('intval', $user_id))) : '';
- $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : '';
-
- $sql_opts = '';
- $hold_ary = $sql_ary = array();
-
- if ($opts !== false)
- {
- $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts);
- }
-
- // Grab user settings - non-role specific...
- $sql_ary[] = 'SELECT a.user_id, a.forum_id, a.auth_setting, a.auth_option_id, ao.auth_option
- FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . ' ao
- WHERE a.auth_role_id = 0
- AND a.auth_option_id = ao.auth_option_id ' .
- (($sql_user) ? 'AND a.' . $sql_user : '') . "
- $sql_forum
- $sql_opts
- ORDER BY a.forum_id, ao.auth_option";
-
- // Now the role settings - user-specific
- $sql_ary[] = 'SELECT a.user_id, a.forum_id, r.auth_option_id, r.auth_setting, r.auth_option_id, ao.auth_option
- FROM ' . ACL_USERS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' ao
- WHERE a.auth_role_id = r.role_id
- AND r.auth_option_id = ao.auth_option_id ' .
- (($sql_user) ? 'AND a.' . $sql_user : '') . "
- $sql_forum
- $sql_opts
- ORDER BY a.forum_id, ao.auth_option";
-
- foreach ($sql_ary as $sql)
- {
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $hold_ary[$row['user_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting'];
- }
- $db->sql_freeresult($result);
- }
-
- return $hold_ary;
- }
-
- /**
- * Get raw group based permission settings
- */
- function acl_group_raw_data($group_id = false, $opts = false, $forum_id = false)
- {
- global $db;
-
- $sql_group = ($group_id !== false) ? ((!is_array($group_id)) ? 'group_id = ' . (int) $group_id : $db->sql_in_set('group_id', array_map('intval', $group_id))) : '';
- $sql_forum = ($forum_id !== false) ? ((!is_array($forum_id)) ? 'AND a.forum_id = ' . (int) $forum_id : 'AND ' . $db->sql_in_set('a.forum_id', array_map('intval', $forum_id))) : '';
-
- $sql_opts = '';
- $hold_ary = $sql_ary = array();
-
- if ($opts !== false)
- {
- $this->build_auth_option_statement('ao.auth_option', $opts, $sql_opts);
- }
-
- // Grab group settings - non-role specific...
- $sql_ary[] = 'SELECT a.group_id, a.forum_id, a.auth_setting, a.auth_option_id, ao.auth_option
- FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_OPTIONS_TABLE . ' ao
- WHERE a.auth_role_id = 0
- AND a.auth_option_id = ao.auth_option_id ' .
- (($sql_group) ? 'AND a.' . $sql_group : '') . "
- $sql_forum
- $sql_opts
- ORDER BY a.forum_id, ao.auth_option";
-
- // Now grab group settings - role specific...
- $sql_ary[] = 'SELECT a.group_id, a.forum_id, r.auth_setting, r.auth_option_id, ao.auth_option
- FROM ' . ACL_GROUPS_TABLE . ' a, ' . ACL_ROLES_DATA_TABLE . ' r, ' . ACL_OPTIONS_TABLE . ' ao
- WHERE a.auth_role_id = r.role_id
- AND r.auth_option_id = ao.auth_option_id ' .
- (($sql_group) ? 'AND a.' . $sql_group : '') . "
- $sql_forum
- $sql_opts
- ORDER BY a.forum_id, ao.auth_option";
-
- foreach ($sql_ary as $sql)
- {
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $hold_ary[$row['group_id']][$row['forum_id']][$row['auth_option']] = $row['auth_setting'];
- }
- $db->sql_freeresult($result);
- }
-
- return $hold_ary;
- }
-
- /**
- * Get raw acl data based on user for caching user_permissions
- * This function returns the same data as acl_raw_data(), but without the user id as the first key within the array.
- */
- function acl_raw_data_single_user($user_id)
- {
- global $db, $cache;
-
- // Check if the role-cache is there
- if (($this->role_cache = $cache->get('_role_cache')) === false)
- {
- $this->role_cache = array();
-
- // We pre-fetch roles
- $sql = 'SELECT *
- FROM ' . ACL_ROLES_DATA_TABLE . '
- ORDER BY role_id ASC';
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $this->role_cache[$row['role_id']][$row['auth_option_id']] = (int) $row['auth_setting'];
- }
- $db->sql_freeresult($result);
-
- foreach ($this->role_cache as $role_id => $role_options)
- {
- $this->role_cache[$role_id] = serialize($role_options);
- }
-
- $cache->put('_role_cache', $this->role_cache);
- }
-
- $hold_ary = array();
-
- // Grab user-specific permission settings
- $sql = 'SELECT forum_id, auth_option_id, auth_role_id, auth_setting
- FROM ' . ACL_USERS_TABLE . '
- WHERE user_id = ' . $user_id;
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- // If a role is assigned, assign all options included within this role. Else, only set this one option.
- if ($row['auth_role_id'])
- {
- $hold_ary[$row['forum_id']] = (empty($hold_ary[$row['forum_id']])) ? unserialize($this->role_cache[$row['auth_role_id']]) : $hold_ary[$row['forum_id']] + unserialize($this->role_cache[$row['auth_role_id']]);
- }
- else
- {
- $hold_ary[$row['forum_id']][$row['auth_option_id']] = $row['auth_setting'];
- }
- }
- $db->sql_freeresult($result);
-
- // 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, ' . 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);
-
- while ($row = $db->sql_fetchrow($result))
- {
- if (!$row['auth_role_id'])
- {
- $this->_set_group_hold_ary($hold_ary[$row['forum_id']], $row['auth_option_id'], $row['auth_setting']);
- }
- else if (!empty($this->role_cache[$row['auth_role_id']]))
- {
- foreach (unserialize($this->role_cache[$row['auth_role_id']]) as $option_id => $setting)
- {
- $this->_set_group_hold_ary($hold_ary[$row['forum_id']], $option_id, $setting);
- }
- }
- }
- $db->sql_freeresult($result);
-
- return $hold_ary;
- }
-
- /**
- * Private function snippet for setting a specific piece of the hold_ary
- */
- function _set_group_hold_ary(&$hold_ary, $option_id, $setting)
- {
- if (!isset($hold_ary[$option_id]) || (isset($hold_ary[$option_id]) && $hold_ary[$option_id] != ACL_NEVER))
- {
- $hold_ary[$option_id] = $setting;
-
- // If we detect ACL_NEVER, we will unset the flag option (within building the bitstring it is correctly set again)
- if ($setting == ACL_NEVER)
- {
- $flag = substr($this->acl_options['option'][$option_id], 0, strpos($this->acl_options['option'][$option_id], '_') + 1);
- $flag = (int) $this->acl_options['id'][$flag];
-
- if (isset($hold_ary[$flag]) && $hold_ary[$flag] == ACL_YES)
- {
- unset($hold_ary[$flag]);
-
-/* This is uncommented, because i suspect this being slightly wrong due to mixed permission classes being possible
- if (in_array(ACL_YES, $hold_ary))
- {
- $hold_ary[$flag] = ACL_YES;
- }*/
- }
- }
- }
- }
-
- /**
- * Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him.
- */
- function login($username, $password, $autologin = false, $viewonline = 1, $admin = 0)
- {
- global $config, $db, $user, $phpbb_root_path, $phpEx;
-
- $method = trim(basename($config['auth_method']));
- include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
-
- $method = 'login_' . $method;
- if (function_exists($method))
- {
- $login = $method($username, $password, $user->ip, $user->browser, $user->forwarded_for);
-
- // If the auth module wants us to create an empty profile do so and then treat the status as LOGIN_SUCCESS
- if ($login['status'] == LOGIN_SUCCESS_CREATE_PROFILE)
- {
- // we are going to use the user_add function so include functions_user.php if it wasn't defined yet
- if (!function_exists('user_add'))
- {
- include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
- }
-
- user_add($login['user_row'], (isset($login['cp_data'])) ? $login['cp_data'] : false);
-
- $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type
- FROM ' . USERS_TABLE . "
- WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if (!$row)
- {
- return array(
- 'status' => LOGIN_ERROR_EXTERNAL_AUTH,
- 'error_msg' => 'AUTH_NO_PROFILE_CREATED',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- $login = array(
- 'status' => LOGIN_SUCCESS,
- 'error_msg' => false,
- 'user_row' => $row,
- );
- }
-
- // If login succeeded, we will log the user in... else we pass the login array through...
- if ($login['status'] == LOGIN_SUCCESS)
- {
- $old_session_id = $user->session_id;
-
- if ($admin)
- {
- global $SID, $_SID;
-
- $cookie_expire = time() - 31536000;
- $user->set_cookie('u', '', $cookie_expire);
- $user->set_cookie('sid', '', $cookie_expire);
- unset($cookie_expire);
-
- $SID = '?sid=';
- $user->session_id = $_SID = '';
- }
-
- $result = $user->session_create($login['user_row']['user_id'], $admin, $autologin, $viewonline);
-
- // Successful session creation
- if ($result === true)
- {
- // If admin re-authentication we remove the old session entry because a new one has been created...
- if ($admin)
- {
- // the login array is used because the user ids do not differ for re-authentication
- $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
- WHERE session_id = '" . $db->sql_escape($old_session_id) . "'
- AND session_user_id = {$login['user_row']['user_id']}";
- $db->sql_query($sql);
- }
-
- return array(
- 'status' => LOGIN_SUCCESS,
- 'error_msg' => false,
- 'user_row' => $login['user_row'],
- );
- }
-
- return array(
- 'status' => LOGIN_BREAK,
- 'error_msg' => $result,
- 'user_row' => $login['user_row'],
- );
- }
-
- return $login;
- }
-
- trigger_error('Authentication method not found', E_USER_ERROR);
- }
-
- /**
- * Fill auth_option statement for later querying based on the supplied options
- */
- function build_auth_option_statement($key, $auth_options, &$sql_opts)
- {
- global $db;
-
- if (!is_array($auth_options))
- {
- if (strpos($auth_options, '%') !== false)
- {
- $sql_opts = "AND $key " . $db->sql_like_expression(str_replace('%', $db->any_char, $auth_options));
- }
- else
- {
- $sql_opts = "AND $key = '" . $db->sql_escape($auth_options) . "'";
- }
- }
- else
- {
- $is_like_expression = false;
-
- foreach ($auth_options as $option)
- {
- if (strpos($option, '%') !== false)
- {
- $is_like_expression = true;
- }
- }
-
- if (!$is_like_expression)
- {
- $sql_opts = 'AND ' . $db->sql_in_set($key, $auth_options);
- }
- else
- {
- $sql = array();
-
- foreach ($auth_options as $option)
- {
- if (strpos($option, '%') !== false)
- {
- $sql[] = $key . ' ' . $db->sql_like_expression(str_replace('%', $db->any_char, $option));
- }
- else
- {
- $sql[] = $key . " = '" . $db->sql_escape($option) . "'";
- }
- }
-
- $sql_opts = 'AND (' . implode(' OR ', $sql) . ')';
- }
- }
- }
-}
diff --git a/phpBB/includes/auth/auth_apache.php b/phpBB/includes/auth/auth_apache.php
deleted file mode 100644
index 10b288aa09..0000000000
--- a/phpBB/includes/auth/auth_apache.php
+++ /dev/null
@@ -1,247 +0,0 @@
-<?php
-/**
-* Apache auth plug-in for phpBB3
-*
-* Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him.
-*
-* @package login
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Checks whether the user is identified to apache
-* Only allow changing authentication to apache if the user is identified
-* Called in acp_board while setting authentication plugins
-*
-* @return boolean|string false if the user is identified and else an error message
-*/
-function init_apache()
-{
- global $user, $request;
-
- if (!$request->is_set('PHP_AUTH_USER', phpbb_request_interface::SERVER) || $user->data['username'] !== htmlspecialchars_decode($request->server('PHP_AUTH_USER')))
- {
- return $user->lang['APACHE_SETUP_BEFORE_USE'];
- }
- return false;
-}
-
-/**
-* Login function
-*/
-function login_apache(&$username, &$password)
-{
- global $db, $request;
-
- // do not allow empty password
- if (!$password)
- {
- return array(
- 'status' => LOGIN_ERROR_PASSWORD,
- 'error_msg' => 'NO_PASSWORD_SUPPLIED',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- if (!$username)
- {
- return array(
- 'status' => LOGIN_ERROR_USERNAME,
- 'error_msg' => 'LOGIN_ERROR_USERNAME',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- if (!$request->is_set('PHP_AUTH_USER', phpbb_request_interface::SERVER))
- {
- return array(
- 'status' => LOGIN_ERROR_EXTERNAL_AUTH,
- 'error_msg' => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- $php_auth_user = htmlspecialchars_decode($request->server('PHP_AUTH_USER'));
- $php_auth_pw = htmlspecialchars_decode($request->server('PHP_AUTH_PW'));
-
- if (!empty($php_auth_user) && !empty($php_auth_pw))
- {
- if ($php_auth_user !== $username)
- {
- return array(
- 'status' => LOGIN_ERROR_USERNAME,
- 'error_msg' => 'LOGIN_ERROR_USERNAME',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- $sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type
- FROM ' . USERS_TABLE . "
- WHERE username = '" . $db->sql_escape($php_auth_user) . "'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if ($row)
- {
- // User inactive...
- if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE)
- {
- return array(
- 'status' => LOGIN_ERROR_ACTIVE,
- 'error_msg' => 'ACTIVE_ERROR',
- 'user_row' => $row,
- );
- }
-
- // Successful login...
- return array(
- 'status' => LOGIN_SUCCESS,
- 'error_msg' => false,
- 'user_row' => $row,
- );
- }
-
- // this is the user's first login so create an empty profile
- return array(
- 'status' => LOGIN_SUCCESS_CREATE_PROFILE,
- 'error_msg' => false,
- 'user_row' => user_row_apache($php_auth_user, $php_auth_pw),
- );
- }
-
- // Not logged into apache
- return array(
- 'status' => LOGIN_ERROR_EXTERNAL_AUTH,
- 'error_msg' => 'LOGIN_ERROR_EXTERNAL_AUTH_APACHE',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
-}
-
-/**
-* Autologin function
-*
-* @return array containing the user row or empty if no auto login should take place
-*/
-function autologin_apache()
-{
- global $db, $request;
-
- if (!$request->is_set('PHP_AUTH_USER', phpbb_request_interface::SERVER))
- {
- return array();
- }
-
- $php_auth_user = htmlspecialchars_decode($request->server('PHP_AUTH_USER'));
- $php_auth_pw = htmlspecialchars_decode($request->server('PHP_AUTH_PW'));
-
- if (!empty($php_auth_user) && !empty($php_auth_pw))
- {
- set_var($php_auth_user, $php_auth_user, 'string', true);
- set_var($php_auth_pw, $php_auth_pw, 'string', true);
-
- $sql = 'SELECT *
- FROM ' . USERS_TABLE . "
- WHERE username = '" . $db->sql_escape($php_auth_user) . "'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if ($row)
- {
- return ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) ? array() : $row;
- }
-
- if (!function_exists('user_add'))
- {
- global $phpbb_root_path, $phpEx;
-
- include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
- }
-
- // create the user if he does not exist yet
- user_add(user_row_apache($php_auth_user, $php_auth_pw));
-
- $sql = 'SELECT *
- FROM ' . USERS_TABLE . "
- WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($php_auth_user)) . "'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if ($row)
- {
- return $row;
- }
- }
-
- return array();
-}
-
-/**
-* This function generates an array which can be passed to the user_add function in order to create a user
-*/
-function user_row_apache($username, $password)
-{
- global $db, $config, $user;
- // first retrieve default group id
- $sql = 'SELECT group_id
- FROM ' . GROUPS_TABLE . "
- WHERE group_name = '" . $db->sql_escape('REGISTERED') . "'
- AND group_type = " . GROUP_SPECIAL;
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if (!$row)
- {
- trigger_error('NO_GROUP');
- }
-
- // generate user account data
- return array(
- 'username' => $username,
- 'user_password' => phpbb_hash($password),
- 'user_email' => '',
- 'group_id' => (int) $row['group_id'],
- 'user_type' => USER_NORMAL,
- 'user_ip' => $user->ip,
- 'user_new' => ($config['new_member_post_limit']) ? 1 : 0,
- );
-}
-
-/**
-* The session validation function checks whether the user is still logged in
-*
-* @return boolean true if the given user is authenticated or false if the session should be closed
-*/
-function validate_session_apache(&$user)
-{
- global $request;
-
- // Check if PHP_AUTH_USER is set and handle this case
- if ($request->is_set('PHP_AUTH_USER', phpbb_request_interface::SERVER))
- {
- $php_auth_user = $request->server('PHP_AUTH_USER');
-
- return ($php_auth_user === $user['username']) ? true : false;
- }
-
- // PHP_AUTH_USER is not set. A valid session is now determined by the user type (anonymous/bot or not)
- if ($user['user_type'] == USER_IGNORE)
- {
- return true;
- }
-
- return false;
-}
diff --git a/phpBB/includes/auth/auth_db.php b/phpBB/includes/auth/auth_db.php
deleted file mode 100644
index ac944532a5..0000000000
--- a/phpBB/includes/auth/auth_db.php
+++ /dev/null
@@ -1,289 +0,0 @@
-<?php
-/**
-* Database auth plug-in for phpBB3
-*
-* Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him.
-*
-* This is for authentication via the integrated user table
-*
-* @package login
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Login function
-*
-* @param string $username
-* @param string $password
-* @param string $ip IP address the login is taking place from. Used to
-* limit the number of login attempts per IP address.
-* @param string $browser The user agent used to login
-* @param string $forwarded_for X_FORWARDED_FOR header sent with login request
-* @return array A associative array of the format
-* array(
-* 'status' => status constant
-* 'error_msg' => string
-* 'user_row' => array
-* )
-*/
-function login_db($username, $password, $ip = '', $browser = '', $forwarded_for = '')
-{
- global $db, $config;
- global $request;
-
- // Auth plugins get the password untrimmed.
- // For compatibility we trim() here.
- $password = trim($password);
-
- // do not allow empty password
- if (!$password)
- {
- return array(
- 'status' => LOGIN_ERROR_PASSWORD,
- 'error_msg' => 'NO_PASSWORD_SUPPLIED',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- if (!$username)
- {
- return array(
- 'status' => LOGIN_ERROR_USERNAME,
- 'error_msg' => 'LOGIN_ERROR_USERNAME',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- $username_clean = utf8_clean_string($username);
-
- $sql = 'SELECT user_id, username, user_password, user_passchg, user_pass_convert, user_email, user_type, user_login_attempts
- FROM ' . USERS_TABLE . "
- WHERE username_clean = '" . $db->sql_escape($username_clean) . "'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if (($ip && !$config['ip_login_limit_use_forwarded']) ||
- ($forwarded_for && $config['ip_login_limit_use_forwarded']))
- {
- $sql = 'SELECT COUNT(*) AS attempts
- FROM ' . LOGIN_ATTEMPT_TABLE . '
- WHERE attempt_time > ' . (time() - (int) $config['ip_login_limit_time']);
- if ($config['ip_login_limit_use_forwarded'])
- {
- $sql .= " AND attempt_forwarded_for = '" . $db->sql_escape($forwarded_for) . "'";
- }
- else
- {
- $sql .= " AND attempt_ip = '" . $db->sql_escape($ip) . "' ";
- }
-
- $result = $db->sql_query($sql);
- $attempts = (int) $db->sql_fetchfield('attempts');
- $db->sql_freeresult($result);
-
- $attempt_data = array(
- 'attempt_ip' => $ip,
- 'attempt_browser' => trim(substr($browser, 0, 149)),
- 'attempt_forwarded_for' => $forwarded_for,
- 'attempt_time' => time(),
- 'user_id' => ($row) ? (int) $row['user_id'] : 0,
- 'username' => $username,
- 'username_clean' => $username_clean,
- );
- $sql = 'INSERT INTO ' . LOGIN_ATTEMPT_TABLE . $db->sql_build_array('INSERT', $attempt_data);
- $result = $db->sql_query($sql);
- }
- else
- {
- $attempts = 0;
- }
-
- if (!$row)
- {
- if ($config['ip_login_limit_max'] && $attempts >= $config['ip_login_limit_max'])
- {
- return array(
- 'status' => LOGIN_ERROR_ATTEMPTS,
- 'error_msg' => 'LOGIN_ERROR_ATTEMPTS',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- return array(
- 'status' => LOGIN_ERROR_USERNAME,
- 'error_msg' => 'LOGIN_ERROR_USERNAME',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- $show_captcha = ($config['max_login_attempts'] && $row['user_login_attempts'] >= $config['max_login_attempts']) ||
- ($config['ip_login_limit_max'] && $attempts >= $config['ip_login_limit_max']);
-
- // If there are too much login attempts, we need to check for an confirm image
- // Every auth module is able to define what to do by itself...
- if ($show_captcha)
- {
- // Visual Confirmation handling
- if (!class_exists('phpbb_captcha_factory', false))
- {
- global $phpbb_root_path, $phpEx;
- include ($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx);
- }
-
- $captcha = phpbb_captcha_factory::get_instance($config['captcha_plugin']);
- $captcha->init(CONFIRM_LOGIN);
- $vc_response = $captcha->validate($row);
- if ($vc_response)
- {
- return array(
- 'status' => LOGIN_ERROR_ATTEMPTS,
- 'error_msg' => 'LOGIN_ERROR_ATTEMPTS',
- 'user_row' => $row,
- );
- }
- else
- {
- $captcha->reset();
- }
-
- }
-
- // If the password convert flag is set we need to convert it
- if ($row['user_pass_convert'])
- {
- // enable super globals to get literal value
- // this is needed to prevent unicode normalization
- $super_globals_disabled = $request->super_globals_disabled();
- if ($super_globals_disabled)
- {
- $request->enable_super_globals();
- }
-
- // in phpBB2 passwords were used exactly as they were sent, with addslashes applied
- $password_old_format = isset($_REQUEST['password']) ? (string) $_REQUEST['password'] : '';
- $password_old_format = (!STRIP) ? addslashes($password_old_format) : $password_old_format;
- $password_new_format = $request->variable('password', '', true);
-
- if ($super_globals_disabled)
- {
- $request->disable_super_globals();
- }
-
- if ($password == $password_new_format)
- {
- if (!function_exists('utf8_to_cp1252'))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx);
- }
-
- // cp1252 is phpBB2's default encoding, characters outside ASCII range might work when converted into that encoding
- // plain md5 support left in for conversions from other systems.
- if ((strlen($row['user_password']) == 34 && (phpbb_check_hash(md5($password_old_format), $row['user_password']) || phpbb_check_hash(md5(utf8_to_cp1252($password_old_format)), $row['user_password'])))
- || (strlen($row['user_password']) == 32 && (md5($password_old_format) == $row['user_password'] || md5(utf8_to_cp1252($password_old_format)) == $row['user_password'])))
- {
- $hash = phpbb_hash($password_new_format);
-
- // Update the password in the users table to the new format and remove user_pass_convert flag
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_password = \'' . $db->sql_escape($hash) . '\',
- user_pass_convert = 0
- WHERE user_id = ' . $row['user_id'];
- $db->sql_query($sql);
-
- $row['user_pass_convert'] = 0;
- $row['user_password'] = $hash;
- }
- else
- {
- // Although we weren't able to convert this password we have to
- // increase login attempt count to make sure this cannot be exploited
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_login_attempts = user_login_attempts + 1
- WHERE user_id = ' . (int) $row['user_id'] . '
- AND user_login_attempts < ' . LOGIN_ATTEMPTS_MAX;
- $db->sql_query($sql);
-
- return array(
- 'status' => LOGIN_ERROR_PASSWORD_CONVERT,
- 'error_msg' => 'LOGIN_ERROR_PASSWORD_CONVERT',
- 'user_row' => $row,
- );
- }
- }
- }
-
- // Check password ...
- if (!$row['user_pass_convert'] && phpbb_check_hash($password, $row['user_password']))
- {
- // Check for old password hash...
- if (strlen($row['user_password']) == 32)
- {
- $hash = phpbb_hash($password);
-
- // Update the password in the users table to the new format
- $sql = 'UPDATE ' . USERS_TABLE . "
- SET user_password = '" . $db->sql_escape($hash) . "',
- user_pass_convert = 0
- WHERE user_id = {$row['user_id']}";
- $db->sql_query($sql);
-
- $row['user_password'] = $hash;
- }
-
- $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . '
- WHERE user_id = ' . $row['user_id'];
- $db->sql_query($sql);
-
- if ($row['user_login_attempts'] != 0)
- {
- // Successful, reset login attempts (the user passed all stages)
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_login_attempts = 0
- WHERE user_id = ' . $row['user_id'];
- $db->sql_query($sql);
- }
-
- // User inactive...
- if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE)
- {
- return array(
- 'status' => LOGIN_ERROR_ACTIVE,
- 'error_msg' => 'ACTIVE_ERROR',
- 'user_row' => $row,
- );
- }
-
- // Successful login... set user_login_attempts to zero...
- return array(
- 'status' => LOGIN_SUCCESS,
- 'error_msg' => false,
- 'user_row' => $row,
- );
- }
-
- // Password incorrect - increase login attempts
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_login_attempts = user_login_attempts + 1
- WHERE user_id = ' . (int) $row['user_id'] . '
- AND user_login_attempts < ' . LOGIN_ATTEMPTS_MAX;
- $db->sql_query($sql);
-
- // Give status about wrong password...
- return array(
- 'status' => ($show_captcha) ? LOGIN_ERROR_ATTEMPTS : LOGIN_ERROR_PASSWORD,
- 'error_msg' => ($show_captcha) ? 'LOGIN_ERROR_ATTEMPTS' : 'LOGIN_ERROR_PASSWORD',
- 'user_row' => $row,
- );
-}
diff --git a/phpBB/includes/auth/auth_ldap.php b/phpBB/includes/auth/auth_ldap.php
deleted file mode 100644
index 24823f9ce7..0000000000
--- a/phpBB/includes/auth/auth_ldap.php
+++ /dev/null
@@ -1,350 +0,0 @@
-<?php
-/**
-*
-* LDAP auth plug-in for phpBB3
-*
-* Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him.
-*
-* @package login
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Connect to ldap server
-* Only allow changing authentication to ldap if we can connect to the ldap server
-* Called in acp_board while setting authentication plugins
-*/
-function init_ldap()
-{
- global $config, $user;
-
- if (!@extension_loaded('ldap'))
- {
- return $user->lang['LDAP_NO_LDAP_EXTENSION'];
- }
-
- $config['ldap_port'] = (int) $config['ldap_port'];
- if ($config['ldap_port'])
- {
- $ldap = @ldap_connect($config['ldap_server'], $config['ldap_port']);
- }
- else
- {
- $ldap = @ldap_connect($config['ldap_server']);
- }
-
- if (!$ldap)
- {
- return $user->lang['LDAP_NO_SERVER_CONNECTION'];
- }
-
- @ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
- @ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
-
- if ($config['ldap_user'] || $config['ldap_password'])
- {
- if (!@ldap_bind($ldap, htmlspecialchars_decode($config['ldap_user']), htmlspecialchars_decode($config['ldap_password'])))
- {
- return $user->lang['LDAP_INCORRECT_USER_PASSWORD'];
- }
- }
-
- // ldap_connect only checks whether the specified server is valid, so the connection might still fail
- $search = @ldap_search(
- $ldap,
- htmlspecialchars_decode($config['ldap_base_dn']),
- ldap_user_filter($user->data['username']),
- (empty($config['ldap_email'])) ?
- array(htmlspecialchars_decode($config['ldap_uid'])) :
- array(htmlspecialchars_decode($config['ldap_uid']), htmlspecialchars_decode($config['ldap_email'])),
- 0,
- 1
- );
-
- if ($search === false)
- {
- return $user->lang['LDAP_SEARCH_FAILED'];
- }
-
- $result = @ldap_get_entries($ldap, $search);
-
- @ldap_close($ldap);
-
-
- if (!is_array($result) || sizeof($result) < 2)
- {
- return sprintf($user->lang['LDAP_NO_IDENTITY'], $user->data['username']);
- }
-
- if (!empty($config['ldap_email']) && !isset($result[0][htmlspecialchars_decode($config['ldap_email'])]))
- {
- return $user->lang['LDAP_NO_EMAIL'];
- }
-
- return false;
-}
-
-/**
-* Login function
-*/
-function login_ldap(&$username, &$password)
-{
- global $db, $config, $user;
-
- // do not allow empty password
- if (!$password)
- {
- return array(
- 'status' => LOGIN_ERROR_PASSWORD,
- 'error_msg' => 'NO_PASSWORD_SUPPLIED',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- if (!$username)
- {
- return array(
- 'status' => LOGIN_ERROR_USERNAME,
- 'error_msg' => 'LOGIN_ERROR_USERNAME',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- if (!@extension_loaded('ldap'))
- {
- return array(
- 'status' => LOGIN_ERROR_EXTERNAL_AUTH,
- 'error_msg' => 'LDAP_NO_LDAP_EXTENSION',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- $config['ldap_port'] = (int) $config['ldap_port'];
- if ($config['ldap_port'])
- {
- $ldap = @ldap_connect($config['ldap_server'], $config['ldap_port']);
- }
- else
- {
- $ldap = @ldap_connect($config['ldap_server']);
- }
-
- if (!$ldap)
- {
- return array(
- 'status' => LOGIN_ERROR_EXTERNAL_AUTH,
- 'error_msg' => 'LDAP_NO_SERVER_CONNECTION',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
-
- @ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
- @ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
-
- if ($config['ldap_user'] || $config['ldap_password'])
- {
- if (!@ldap_bind($ldap, htmlspecialchars_decode($config['ldap_user']), htmlspecialchars_decode($config['ldap_password'])))
- {
- return array(
- 'status' => LOGIN_ERROR_EXTERNAL_AUTH,
- 'error_msg' => 'LDAP_NO_SERVER_CONNECTION',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
- }
-
- $search = @ldap_search(
- $ldap,
- htmlspecialchars_decode($config['ldap_base_dn']),
- ldap_user_filter($username),
- (empty($config['ldap_email'])) ?
- array(htmlspecialchars_decode($config['ldap_uid'])) :
- array(htmlspecialchars_decode($config['ldap_uid']), htmlspecialchars_decode($config['ldap_email'])),
- 0,
- 1
- );
-
- $ldap_result = @ldap_get_entries($ldap, $search);
-
- if (is_array($ldap_result) && sizeof($ldap_result) > 1)
- {
- if (@ldap_bind($ldap, $ldap_result[0]['dn'], htmlspecialchars_decode($password)))
- {
- @ldap_close($ldap);
-
- $sql ='SELECT user_id, username, user_password, user_passchg, user_email, user_type
- FROM ' . USERS_TABLE . "
- WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if ($row)
- {
- unset($ldap_result);
-
- // User inactive...
- if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE)
- {
- return array(
- 'status' => LOGIN_ERROR_ACTIVE,
- 'error_msg' => 'ACTIVE_ERROR',
- 'user_row' => $row,
- );
- }
-
- // Successful login... set user_login_attempts to zero...
- return array(
- 'status' => LOGIN_SUCCESS,
- 'error_msg' => false,
- 'user_row' => $row,
- );
- }
- else
- {
- // retrieve default group id
- $sql = 'SELECT group_id
- FROM ' . GROUPS_TABLE . "
- WHERE group_name = '" . $db->sql_escape('REGISTERED') . "'
- AND group_type = " . GROUP_SPECIAL;
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if (!$row)
- {
- trigger_error('NO_GROUP');
- }
-
- // generate user account data
- $ldap_user_row = array(
- 'username' => $username,
- 'user_password' => phpbb_hash($password),
- '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);
-
- // this is the user's first login so create an empty profile
- return array(
- 'status' => LOGIN_SUCCESS_CREATE_PROFILE,
- 'error_msg' => false,
- 'user_row' => $ldap_user_row,
- );
- }
- }
- else
- {
- unset($ldap_result);
- @ldap_close($ldap);
-
- // Give status about wrong password...
- return array(
- 'status' => LOGIN_ERROR_PASSWORD,
- 'error_msg' => 'LOGIN_ERROR_PASSWORD',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
- }
- }
-
- @ldap_close($ldap);
-
- return array(
- 'status' => LOGIN_ERROR_USERNAME,
- 'error_msg' => 'LOGIN_ERROR_USERNAME',
- 'user_row' => array('user_id' => ANONYMOUS),
- );
-}
-
-/**
-* Generates a filter string for ldap_search to find a user
-*
-* @param $username string Username identifying the searched user
-*
-* @return string A filter string for ldap_search
-*/
-function ldap_user_filter($username)
-{
- global $config;
-
- $filter = '(' . $config['ldap_uid'] . '=' . ldap_escape(htmlspecialchars_decode($username)) . ')';
- if ($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;
-}
-
-/**
-* Escapes an LDAP AttributeValue
-*/
-function ldap_escape($string)
-{
- return str_replace(array('*', '\\', '(', ')'), array('\\*', '\\\\', '\\(', '\\)'), $string);
-}
-
-/**
-* This function is used to output any required fields in the authentication
-* admin panel. It also defines any required configuration table fields.
-*/
-function acp_ldap(&$new)
-{
- global $user;
-
- $tpl = '
-
- <dl>
- <dt><label for="ldap_server">' . $user->lang['LDAP_SERVER'] . $user->lang['COLON'] . '</label><br /><span>' . $user->lang['LDAP_SERVER_EXPLAIN'] . '</span></dt>
- <dd><input type="text" id="ldap_server" size="40" name="config[ldap_server]" value="' . $new['ldap_server'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="ldap_port">' . $user->lang['LDAP_PORT'] . $user->lang['COLON'] . '</label><br /><span>' . $user->lang['LDAP_PORT_EXPLAIN'] . '</span></dt>
- <dd><input type="text" id="ldap_port" size="40" name="config[ldap_port]" value="' . $new['ldap_port'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="ldap_dn">' . $user->lang['LDAP_DN'] . $user->lang['COLON'] . '</label><br /><span>' . $user->lang['LDAP_DN_EXPLAIN'] . '</span></dt>
- <dd><input type="text" id="ldap_dn" size="40" name="config[ldap_base_dn]" value="' . $new['ldap_base_dn'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="ldap_uid">' . $user->lang['LDAP_UID'] . $user->lang['COLON'] . '</label><br /><span>' . $user->lang['LDAP_UID_EXPLAIN'] . '</span></dt>
- <dd><input type="text" id="ldap_uid" size="40" name="config[ldap_uid]" value="' . $new['ldap_uid'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="ldap_user_filter">' . $user->lang['LDAP_USER_FILTER'] . $user->lang['COLON'] . '</label><br /><span>' . $user->lang['LDAP_USER_FILTER_EXPLAIN'] . '</span></dt>
- <dd><input type="text" id="ldap_user_filter" size="40" name="config[ldap_user_filter]" value="' . $new['ldap_user_filter'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="ldap_email">' . $user->lang['LDAP_EMAIL'] . $user->lang['COLON'] . '</label><br /><span>' . $user->lang['LDAP_EMAIL_EXPLAIN'] . '</span></dt>
- <dd><input type="text" id="ldap_email" size="40" name="config[ldap_email]" value="' . $new['ldap_email'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="ldap_user">' . $user->lang['LDAP_USER'] . $user->lang['COLON'] . '</label><br /><span>' . $user->lang['LDAP_USER_EXPLAIN'] . '</span></dt>
- <dd><input type="text" id="ldap_user" size="40" name="config[ldap_user]" value="' . $new['ldap_user'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="ldap_password">' . $user->lang['LDAP_PASSWORD'] . $user->lang['COLON'] . '</label><br /><span>' . $user->lang['LDAP_PASSWORD_EXPLAIN'] . '</span></dt>
- <dd><input type="password" id="ldap_password" size="40" name="config[ldap_password]" value="' . $new['ldap_password'] . '" autocomplete="off" /></dd>
- </dl>
- ';
-
- // These are fields required in the config table
- return array(
- 'tpl' => $tpl,
- 'config' => array('ldap_server', 'ldap_port', 'ldap_base_dn', 'ldap_uid', 'ldap_user_filter', 'ldap_email', 'ldap_user', 'ldap_password')
- );
-}
diff --git a/phpBB/includes/auth/index.htm b/phpBB/includes/auth/index.htm
deleted file mode 100644
index ee1f723a7d..0000000000
--- a/phpBB/includes/auth/index.htm
+++ /dev/null
@@ -1,10 +0,0 @@
-<html>
-<head>
-<title></title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-</head>
-
-<body bgcolor="#FFFFFF" text="#000000">
-
-</body>
-</html>
diff --git a/phpBB/includes/bbcode.php b/phpBB/includes/bbcode.php
index b9ffa8091c..2fa6a8b099 100644
--- a/phpBB/includes/bbcode.php
+++ b/phpBB/includes/bbcode.php
@@ -132,13 +132,10 @@ class bbcode
{
$this->template_bitfield = new bitfield($user->style['bbcode_bitfield']);
- $style_resource_locator = new phpbb_style_resource_locator();
- $style_path_provider = new phpbb_style_extension_path_provider($phpbb_extension_manager, new phpbb_style_path_provider());
- $template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, new phpbb_template_context());
- $style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, $style_path_provider, $template);
- $style->set_style();
+ $template = new phpbb_template_twig($phpbb_root_path, $phpEx, $config, $user, new phpbb_template_context(), $phpbb_extension_manager);
+ $template->set_style();
$template->set_filenames(array('bbcode.html' => 'bbcode.html'));
- $this->template_filename = $style_resource_locator->get_source_file_for_handle('bbcode.html');
+ $this->template_filename = $template->get_source_file_for_handle('bbcode.html');
}
$bbcode_ids = $rowset = $sql = array();
diff --git a/phpBB/includes/cache/driver/apc.php b/phpBB/includes/cache/driver/apc.php
deleted file mode 100644
index 0516b669c8..0000000000
--- a/phpBB/includes/cache/driver/apc.php
+++ /dev/null
@@ -1,75 +0,0 @@
-<?php
-/**
-*
-* @package acm
-* @copyright (c) 2005, 2009 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* ACM for APC
-* @package acm
-*/
-class phpbb_cache_driver_apc extends phpbb_cache_driver_memory
-{
- var $extension = 'apc';
-
- /**
- * Purge cache data
- *
- * @return null
- */
- function purge()
- {
- apc_clear_cache('user');
-
- parent::purge();
- }
-
- /**
- * Fetch an item from the cache
- *
- * @access protected
- * @param string $var Cache key
- * @return mixed Cached data
- */
- function _read($var)
- {
- return apc_fetch($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 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);
- }
-}
diff --git a/phpBB/includes/cache/driver/base.php b/phpBB/includes/cache/driver/base.php
deleted file mode 100644
index 32e04f813a..0000000000
--- a/phpBB/includes/cache/driver/base.php
+++ /dev/null
@@ -1,23 +0,0 @@
-<?php
-/**
-*
-* @package acm
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* @package acm
-*/
-abstract class phpbb_cache_driver_base implements phpbb_cache_driver_interface
-{
-}
diff --git a/phpBB/includes/cache/driver/eaccelerator.php b/phpBB/includes/cache/driver/eaccelerator.php
deleted file mode 100644
index 257b90c76e..0000000000
--- a/phpBB/includes/cache/driver/eaccelerator.php
+++ /dev/null
@@ -1,112 +0,0 @@
-<?php
-/**
-*
-* @package acm
-* @copyright (c) 2005, 2009 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* ACM for eAccelerator
-* @package acm
-* @todo Missing locks from destroy() talk with David
-*/
-class phpbb_cache_driver_eaccelerator extends phpbb_cache_driver_memory
-{
- var $extension = 'eaccelerator';
- var $function = 'eaccelerator_get';
-
- var $serialize_header = '#phpbb-serialized#';
-
- /**
- * Purge cache data
- *
- * @return null
- */
- function purge()
- {
- foreach (eaccelerator_list_keys() as $var)
- {
- // @todo Check why the substr()
- // @todo Only unset vars matching $this->key_prefix
- eaccelerator_rm(substr($var['name'], 1));
- }
-
- parent::purge();
- }
-
- /**
- * Perform cache garbage collection
- *
- * @return null
- */
- 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);
- }
-}
diff --git a/phpBB/includes/cache/driver/file.php b/phpBB/includes/cache/driver/file.php
deleted file mode 100644
index 691abe0438..0000000000
--- a/phpBB/includes/cache/driver/file.php
+++ /dev/null
@@ -1,742 +0,0 @@
-<?php
-/**
-*
-* @package acm
-* @copyright (c) 2005, 2009 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* ACM File Based Caching
-* @package acm
-*/
-class phpbb_cache_driver_file extends phpbb_cache_driver_base
-{
- var $vars = array();
- var $var_expires = array();
- var $is_modified = false;
-
- var $sql_rowset = array();
- var $sql_row_pointer = array();
- var $cache_dir = '';
-
- /**
- * Set cache path
- */
- function __construct($cache_dir = null)
- {
- global $phpbb_root_path;
- $this->cache_dir = !is_null($cache_dir) ? $cache_dir : $phpbb_root_path . 'cache/';
- }
-
- /**
- * Load global cache
- */
- function load()
- {
- return $this->_read('data_global');
- }
-
- /**
- * Unload cache object
- */
- function unload()
- {
- $this->save();
- unset($this->vars);
- unset($this->var_expires);
- unset($this->sql_rowset);
- unset($this->sql_row_pointer);
-
- $this->vars = array();
- $this->var_expires = array();
- $this->sql_rowset = array();
- $this->sql_row_pointer = array();
- }
-
- /**
- * Save modified objects
- */
- function save()
- {
- if (!$this->is_modified)
- {
- return;
- }
-
- global $phpEx;
-
- if (!$this->_write('data_global'))
- {
- if (!function_exists('phpbb_is_writable'))
- {
- global $phpbb_root_path;
- include($phpbb_root_path . 'includes/functions.' . $phpEx);
- }
-
- // Now, this occurred how often? ... phew, just tell the user then...
- if (!phpbb_is_writable($this->cache_dir))
- {
- // We need to use die() here, because else we may encounter an infinite loop (the message handler calls $cache->unload())
- die('Fatal: ' . $this->cache_dir . ' is NOT writable.');
- exit;
- }
-
- die('Fatal: Not able to open ' . $this->cache_dir . 'data_global.' . $phpEx);
- exit;
- }
-
- $this->is_modified = false;
- }
-
- /**
- * Tidy cache
- */
- function tidy()
- {
- global $phpEx;
-
- $dir = @opendir($this->cache_dir);
-
- if (!$dir)
- {
- return;
- }
-
- $time = time();
-
- while (($entry = readdir($dir)) !== false)
- {
- if (!preg_match('/^(sql_|data_(?!global))/', $entry))
- {
- continue;
- }
-
- 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);
- }
- }
- closedir($dir);
-
- if (file_exists($this->cache_dir . 'data_global.' . $phpEx))
- {
- if (!sizeof($this->vars))
- {
- $this->load();
- }
-
- foreach ($this->var_expires as $var_name => $expires)
- {
- if ($time >= $expires)
- {
- $this->destroy($var_name);
- }
- }
- }
-
- set_config('cache_last_gc', time(), true);
- }
-
- /**
- * Get saved cache object
- */
- function get($var_name)
- {
- if ($var_name[0] == '_')
- {
- global $phpEx;
-
- if (!$this->_exists($var_name))
- {
- return false;
- }
-
- return $this->_read('data' . $var_name);
- }
- else
- {
- return ($this->_exists($var_name)) ? $this->vars[$var_name] : false;
- }
- }
-
- /**
- * Put data into cache
- */
- function put($var_name, $var, $ttl = 31536000)
- {
- if ($var_name[0] == '_')
- {
- $this->_write('data' . $var_name, $var, time() + $ttl);
- }
- else
- {
- $this->vars[$var_name] = $var;
- $this->var_expires[$var_name] = time() + $ttl;
- $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, 'container_') !== 0 &&
- strpos($entry, 'url_matcher') !== 0 &&
- 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->var_expires);
- unset($this->sql_rowset);
- unset($this->sql_row_pointer);
-
- $this->vars = array();
- $this->var_expires = array();
- $this->sql_rowset = array();
- $this->sql_row_pointer = array();
-
- $this->is_modified = false;
- }
-
- /**
- * Destroy cache data
- */
- function destroy($var_name, $table = '')
- {
- global $phpEx;
-
- if ($var_name == 'sql' && !empty($table))
- {
- if (!is_array($table))
- {
- $table = array($table);
- }
-
- $dir = @opendir($this->cache_dir);
-
- if (!$dir)
- {
- return;
- }
-
- while (($entry = readdir($dir)) !== false)
- {
- if (strpos($entry, 'sql_') !== 0)
- {
- continue;
- }
-
- if (!($handle = @fopen($this->cache_dir . $entry, 'rb')))
- {
- continue;
- }
-
- // Skip the PHP header
- fgets($handle);
-
- // Skip expiration
- fgets($handle);
-
- // Grab the query, remove the LF
- $query = substr(fgets($handle), 0, -1);
-
- fclose($handle);
-
- foreach ($table as $check_table)
- {
- // Better catch partial table names than no table names. ;)
- if (strpos($query, $check_table) !== false)
- {
- $this->remove_file($this->cache_dir . $entry);
- break;
- }
- }
- }
- closedir($dir);
-
- return;
- }
-
- if (!$this->_exists($var_name))
- {
- return;
- }
-
- if ($var_name[0] == '_')
- {
- $this->remove_file($this->cache_dir . 'data' . $var_name . ".$phpEx", true);
- }
- else if (isset($this->vars[$var_name]))
- {
- $this->is_modified = true;
- unset($this->vars[$var_name]);
- unset($this->var_expires[$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] == '_')
- {
- global $phpEx;
- return file_exists($this->cache_dir . 'data' . $var_name . ".$phpEx");
- }
- else
- {
- if (!sizeof($this->vars))
- {
- $this->load();
- }
-
- if (!isset($this->var_expires[$var_name]))
- {
- return false;
- }
-
- return (time() > $this->var_expires[$var_name]) ? false : 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);
-
- if (($rowset = $this->_read('sql_' . md5($query))) === false)
- {
- return false;
- }
-
- $query_id = sizeof($this->sql_rowset);
- $this->sql_rowset[$query_id] = $rowset;
- $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);
-
- $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);
-
- if ($this->_write('sql_' . md5($query), $this->sql_rowset[$query_id], $ttl + time(), $query))
- {
- return $query_id;
- }
-
- return $query_result;
- }
-
- /**
- * 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;
- }
-
- /**
- * 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:
- * <code>
- * <?php exit; ?>
- * (expiration)
- * (length of var and serialised data)
- * (var)
- * (serialised data)
- * ... (repeat)
- * </code>
- *
- * The other files have a similar format:
- * <code>
- * <?php exit; ?>
- * (expiration)
- * (query) [SQL files only]
- * (length of serialised data)
- * (serialised data)
- * </code>
- *
- * @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";
-
- $lock = new phpbb_lock_flock($file);
- $lock->acquire();
-
- if ($handle = @fopen($file, 'wb'))
- {
- // 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);
- }
-
- 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_value = true;
- }
- else
- {
- $return_value = false;
- }
-
- $lock->release();
-
- return $return_value;
- }
-
- /**
- * Removes/unlinks file
- */
- function remove_file($filename, $check = false)
- {
- if (!function_exists('phpbb_is_writable'))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/functions.' . $phpEx);
- }
-
- if ($check && !phpbb_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);
- }
-}
diff --git a/phpBB/includes/cache/driver/interface.php b/phpBB/includes/cache/driver/interface.php
deleted file mode 100644
index d403bbcd71..0000000000
--- a/phpBB/includes/cache/driver/interface.php
+++ /dev/null
@@ -1,143 +0,0 @@
-<?php
-/**
-*
-* @package acm
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* An interface that all cache drivers must implement
-*
-* @package acm
-*/
-interface phpbb_cache_driver_interface
-{
- /**
- * Load global cache
- */
- public function load();
-
- /**
- * Unload cache object
- */
- public function unload();
-
- /**
- * Save modified objects
- */
- public function save();
-
- /**
- * Tidy cache
- */
- public function tidy();
-
- /**
- * Get saved cache object
- */
- public function get($var_name);
-
- /**
- * Put data into cache
- */
- public function put($var_name, $var, $ttl = 0);
-
- /**
- * Purge cache data
- */
- public function purge();
-
- /**
- * Destroy cache data
- */
- public function destroy($var_name, $table = '');
-
- /**
- * Check if a given cache entry exists
- */
- public function _exists($var_name);
-
- /**
- * Load result of an SQL query from cache.
- *
- * @param string $query SQL query
- *
- * @return int|bool Query ID (integer) if cache contains a rowset
- * for the specified query.
- * False otherwise.
- */
- public function sql_load($query);
-
- /**
- * Save result of an SQL query in cache.
- *
- * In persistent cache stores, this function stores the query
- * result to persistent storage. In other words, there is no need
- * to call save() afterwards.
- *
- * @param string $query SQL query, should be used for generating storage key
- * @param mixed $query_result The result from dbal::sql_query, to be passed to
- * dbal::sql_fetchrow to get all rows and store them
- * in cache.
- * @param int $ttl Time to live, after this timeout the query should
- * expire from the cache.
- * @return int|mixed If storing in cache succeeded, an integer $query_id
- * representing the query should be returned. Otherwise
- * the original $query_result should be returned.
- */
- public function sql_save($query, $query_result, $ttl);
-
- /**
- * Check if result for a given SQL query exists in cache.
- *
- * @param int $query_id
- * @return bool
- */
- public function sql_exists($query_id);
-
- /**
- * Fetch row from cache (database)
- *
- * @param int $query_id
- * @return array|bool The query result if found in the cache, otherwise
- * false.
- */
- public function sql_fetchrow($query_id);
-
- /**
- * Fetch a field from the current row of a cached database result (database)
- *
- * @param int $query_id
- * @param $field The name of the column.
- * @return string|bool The field of the query result if found in the cache,
- * otherwise false.
- */
- public function sql_fetchfield($query_id, $field);
-
- /**
- * Seek a specific row in an a cached database result (database)
- *
- * @param int $rownum Row to seek to.
- * @param int $query_id
- * @return bool
- */
- public function sql_rowseek($rownum, $query_id);
-
- /**
- * Free memory used for a cached database result (database)
- *
- * @param int $query_id
- * @return bool
- */
- public function sql_freeresult($query_id);
-}
diff --git a/phpBB/includes/cache/driver/memcache.php b/phpBB/includes/cache/driver/memcache.php
deleted file mode 100644
index 3fd16b23b0..0000000000
--- a/phpBB/includes/cache/driver/memcache.php
+++ /dev/null
@@ -1,129 +0,0 @@
-<?php
-/**
-*
-* @package acm
-* @copyright (c) 2005, 2009 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-if (!defined('PHPBB_ACM_MEMCACHE_PORT'))
-{
- define('PHPBB_ACM_MEMCACHE_PORT', 11211);
-}
-
-if (!defined('PHPBB_ACM_MEMCACHE_COMPRESS'))
-{
- define('PHPBB_ACM_MEMCACHE_COMPRESS', false);
-}
-
-if (!defined('PHPBB_ACM_MEMCACHE_HOST'))
-{
- define('PHPBB_ACM_MEMCACHE_HOST', 'localhost');
-}
-
-if (!defined('PHPBB_ACM_MEMCACHE'))
-{
- //can define multiple servers with host1/port1,host2/port2 format
- define('PHPBB_ACM_MEMCACHE', PHPBB_ACM_MEMCACHE_HOST . '/' . PHPBB_ACM_MEMCACHE_PORT);
-}
-
-/**
-* ACM for Memcached
-* @package acm
-*/
-class phpbb_cache_driver_memcache extends phpbb_cache_driver_memory
-{
- var $extension = 'memcache';
-
- var $memcache;
- var $flags = 0;
-
- function __construct()
- {
- // Call the parent constructor
- parent::__construct();
-
- $this->memcache = new Memcache;
- foreach(explode(',', PHPBB_ACM_MEMCACHE) as $u)
- {
- $parts = explode('/', $u);
- $this->memcache->addServer(trim($parts[0]), trim($parts[1]));
- }
- $this->flags = (PHPBB_ACM_MEMCACHE_COMPRESS) ? MEMCACHE_COMPRESSED : 0;
- }
-
- /**
- * Unload the cache resources
- *
- * @return null
- */
- function unload()
- {
- parent::unload();
-
- $this->memcache->close();
- }
-
- /**
- * Purge cache data
- *
- * @return null
- */
- 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)
- {
- if (!$this->memcache->replace($this->key_prefix . $var, $data, $this->flags, $ttl))
- {
- return $this->memcache->set($this->key_prefix . $var, $data, $this->flags, $ttl);
- }
- return true;
- }
-
- /**
- * 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);
- }
-}
diff --git a/phpBB/includes/cache/driver/memory.php b/phpBB/includes/cache/driver/memory.php
deleted file mode 100644
index c39f9f7850..0000000000
--- a/phpBB/includes/cache/driver/memory.php
+++ /dev/null
@@ -1,441 +0,0 @@
-<?php
-/**
-*
-* @package acm
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* ACM Abstract Memory Class
-* @package acm
-*/
-abstract class phpbb_cache_driver_memory extends phpbb_cache_driver_base
-{
- var $key_prefix;
-
- var $vars = array();
- var $is_modified = false;
-
- var $sql_rowset = array();
- var $sql_row_pointer = array();
- var $cache_dir = '';
-
- /**
- * Set cache path
- */
- function __construct()
- {
- global $phpbb_root_path, $dbname, $table_prefix;
-
- $this->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);
- }
-
- if (isset($this->function) && !function_exists($this->function))
- {
- global $acm_type;
-
- trigger_error("The required function [{$this->function}] is not available for the ACM module $acm_type.", E_USER_ERROR);
- }
- }
-
- /**
- * 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, 'container_') !== 0 &&
- strpos($entry, 'url_matcher') !== 0 &&
- 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 $query_result;
- }
- $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);
-
- return $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 (!function_exists('phpbb_is_writable'))
- {
- global $phpbb_root_path, $phpEx;
- include($phpbb_root_path . 'includes/functions.' . $phpEx);
- }
-
- if ($check && !phpbb_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;
- }
-}
diff --git a/phpBB/includes/cache/driver/null.php b/phpBB/includes/cache/driver/null.php
deleted file mode 100644
index 687604d14f..0000000000
--- a/phpBB/includes/cache/driver/null.php
+++ /dev/null
@@ -1,154 +0,0 @@
-<?php
-/**
-*
-* @package acm
-* @copyright (c) 2005, 2009 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* ACM Null Caching
-* @package acm
-*/
-class phpbb_cache_driver_null extends phpbb_cache_driver_base
-{
- /**
- * Set cache path
- */
- function __construct()
- {
- }
-
- /**
- * Load global cache
- */
- function load()
- {
- return true;
- }
-
- /**
- * Unload cache object
- */
- function unload()
- {
- }
-
- /**
- * Save modified objects
- */
- function save()
- {
- }
-
- /**
- * Tidy cache
- */
- function tidy()
- {
- // This cache always has a tidy room.
- set_config('cache_last_gc', time(), true);
- }
-
- /**
- * Get saved cache object
- */
- function get($var_name)
- {
- return false;
- }
-
- /**
- * Put data into cache
- */
- function put($var_name, $var, $ttl = 0)
- {
- }
-
- /**
- * Purge cache data
- */
- function purge()
- {
- }
-
- /**
- * Destroy cache data
- */
- function destroy($var_name, $table = '')
- {
- }
-
- /**
- * Check if a given cache entry exist
- */
- function _exists($var_name)
- {
- return false;
- }
-
- /**
- * Load cached sql query
- */
- function sql_load($query)
- {
- return false;
- }
-
- /**
- * Save sql query
- */
- function sql_save($query, $query_result, $ttl)
- {
- return $query_result;
- }
-
- /**
- * Ceck if a given sql query exist in cache
- */
- function sql_exists($query_id)
- {
- return false;
- }
-
- /**
- * Fetch row from cache (database)
- */
- function sql_fetchrow($query_id)
- {
- return false;
- }
-
- /**
- * Fetch a field from the current row of a cached database result (database)
- */
- function sql_fetchfield($query_id, $field)
- {
- return false;
- }
-
- /**
- * Seek a specific row in an a cached database result (database)
- */
- function sql_rowseek($rownum, $query_id)
- {
- return false;
- }
-
- /**
- * Free memory used for a cached database result (database)
- */
- function sql_freeresult($query_id)
- {
- return false;
- }
-}
diff --git a/phpBB/includes/cache/driver/redis.php b/phpBB/includes/cache/driver/redis.php
deleted file mode 100644
index 960735b673..0000000000
--- a/phpBB/includes/cache/driver/redis.php
+++ /dev/null
@@ -1,166 +0,0 @@
-<?php
-/**
-*
-* @package acm
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-if (!defined('PHPBB_ACM_REDIS_PORT'))
-{
- define('PHPBB_ACM_REDIS_PORT', 6379);
-}
-
-if (!defined('PHPBB_ACM_REDIS_HOST'))
-{
- define('PHPBB_ACM_REDIS_HOST', 'localhost');
-}
-
-/**
-* ACM for Redis
-*
-* Compatible with the php extension phpredis available
-* at https://github.com/nicolasff/phpredis
-*
-* @package acm
-*/
-class phpbb_cache_driver_redis extends phpbb_cache_driver_memory
-{
- var $extension = 'redis';
-
- var $redis;
-
- /**
- * Creates a redis cache driver.
- *
- * The following global constants affect operation:
- *
- * PHPBB_ACM_REDIS_HOST
- * PHPBB_ACM_REDIS_PORT
- * PHPBB_ACM_REDIS_PASSWORD
- * PHPBB_ACM_REDIS_DB
- *
- * There are no publicly documented constructor parameters.
- */
- function __construct()
- {
- // Call the parent constructor
- parent::__construct();
-
- $this->redis = new Redis();
-
- $args = func_get_args();
- if (!empty($args))
- {
- $ok = call_user_func_array(array($this->redis, 'connect'), $args);
- }
- else
- {
- $ok = $this->redis->connect(PHPBB_ACM_REDIS_HOST, PHPBB_ACM_REDIS_PORT);
- }
-
- if (!$ok)
- {
- trigger_error('Could not connect to redis server');
- }
-
- if (defined('PHPBB_ACM_REDIS_PASSWORD'))
- {
- if (!$this->redis->auth(PHPBB_ACM_REDIS_PASSWORD))
- {
- global $acm_type;
-
- trigger_error("Incorrect password for the ACM module $acm_type.", E_USER_ERROR);
- }
- }
-
- $this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
- $this->redis->setOption(Redis::OPT_PREFIX, $this->key_prefix);
-
- if (defined('PHPBB_ACM_REDIS_DB'))
- {
- if (!$this->redis->select(PHPBB_ACM_REDIS_DB))
- {
- global $acm_type;
-
- trigger_error("Incorrect database for the ACM module $acm_type.", E_USER_ERROR);
- }
- }
- }
-
- /**
- * Unload the cache resources
- *
- * @return null
- */
- function unload()
- {
- parent::unload();
-
- $this->redis->close();
- }
-
- /**
- * Purge cache data
- *
- * @return null
- */
- function purge()
- {
- $this->redis->flushDB();
-
- parent::purge();
- }
-
- /**
- * Fetch an item from the cache
- *
- * @access protected
- * @param string $var Cache key
- * @return mixed Cached data
- */
- function _read($var)
- {
- return $this->redis->get($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->redis->setex($var, $ttl, $data);
- }
-
- /**
- * Remove an item from the cache
- *
- * @access protected
- * @param string $var Cache key
- * @return bool True if the operation succeeded
- */
- function _delete($var)
- {
- if ($this->redis->delete($var) > 0)
- {
- return true;
- }
- return false;
- }
-}
-
diff --git a/phpBB/includes/cache/driver/wincache.php b/phpBB/includes/cache/driver/wincache.php
deleted file mode 100644
index 58f3b4a581..0000000000
--- a/phpBB/includes/cache/driver/wincache.php
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-/**
-*
-* @package acm
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* ACM for WinCache
-* @package acm
-*/
-class phpbb_cache_driver_wincache extends phpbb_cache_driver_memory
-{
- var $extension = 'wincache';
-
- /**
- * Purge cache data
- *
- * @return null
- */
- function purge()
- {
- wincache_ucache_clear();
-
- parent::purge();
- }
-
- /**
- * Fetch an item from the cache
- *
- * @access protected
- * @param string $var Cache key
- * @return mixed Cached data
- */
- function _read($var)
- {
- $success = false;
- $result = wincache_ucache_get($this->key_prefix . $var, $success);
-
- return ($success) ? $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 wincache_ucache_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 wincache_ucache_delete($this->key_prefix . $var);
- }
-}
diff --git a/phpBB/includes/cache/driver/xcache.php b/phpBB/includes/cache/driver/xcache.php
deleted file mode 100644
index 06c5fafd97..0000000000
--- a/phpBB/includes/cache/driver/xcache.php
+++ /dev/null
@@ -1,112 +0,0 @@
-<?php
-/**
-*
-* @package acm
-* @copyright (c) 2005, 2009 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* ACM for XCache
-* @package acm
-*
-* To use this module you need ini_get() enabled and the following INI settings configured as follows:
-* - xcache.var_size > 0
-* - xcache.admin.enable_auth = off (or xcache.admin.user and xcache.admin.password set)
-*
-*/
-class phpbb_cache_driver_xcache extends phpbb_cache_driver_memory
-{
- var $extension = 'XCache';
-
- function __construct()
- {
- parent::__construct();
-
- 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 null
- */
- 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);
- }
-}
diff --git a/phpBB/includes/cache/service.php b/phpBB/includes/cache/service.php
deleted file mode 100644
index e63ec6e33a..0000000000
--- a/phpBB/includes/cache/service.php
+++ /dev/null
@@ -1,411 +0,0 @@
-<?php
-/**
-*
-* @package acm
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Class for grabbing/handling cached entries
-* @package acm
-*/
-class phpbb_cache_service
-{
- private $driver;
-
- /**
- * Creates a cache service around a cache driver
- *
- * @param phpbb_cache_driver_interface $driver The cache driver
- */
- public function __construct(phpbb_cache_driver_interface $driver = null)
- {
- $this->set_driver($driver);
- }
-
- /**
- * Returns the cache driver used by this cache service.
- *
- * @return phpbb_cache_driver_interface The cache driver
- */
- public function get_driver()
- {
- return $this->driver;
- }
-
- /**
- * Replaces the cache driver used by this cache service.
- *
- * @param phpbb_cache_driver_interface $driver The cache driver
- */
- public function set_driver(phpbb_cache_driver_interface $driver)
- {
- $this->driver = $driver;
- }
-
- public function __call($method, $arguments)
- {
- return call_user_func_array(array($this->driver, $method), $arguments);
- }
-
- /**
- * Obtain list of naughty words and build preg style replacement arrays for use by the
- * calling script
- */
- function obtain_word_list()
- {
- global $db;
-
- if (($censors = $this->driver->get('_word_censors')) === false)
- {
- $sql = 'SELECT word, replacement
- FROM ' . WORDS_TABLE;
- $result = $db->sql_query($sql);
-
- $censors = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $censors['match'][] = get_censor_preg_expression($row['word']);
- $censors['replace'][] = $row['replacement'];
- }
- $db->sql_freeresult($result);
-
- $this->driver->put('_word_censors', $censors);
- }
-
- return $censors;
- }
-
- /**
- * Obtain currently listed icons
- */
- function obtain_icons()
- {
- if (($icons = $this->driver->get('_icons')) === false)
- {
- global $db;
-
- // Topic icons
- $sql = 'SELECT *
- FROM ' . ICONS_TABLE . '
- ORDER BY icons_order';
- $result = $db->sql_query($sql);
-
- $icons = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $icons[$row['icons_id']]['img'] = $row['icons_url'];
- $icons[$row['icons_id']]['width'] = (int) $row['icons_width'];
- $icons[$row['icons_id']]['height'] = (int) $row['icons_height'];
- $icons[$row['icons_id']]['display'] = (bool) $row['display_on_posting'];
- }
- $db->sql_freeresult($result);
-
- $this->driver->put('_icons', $icons);
- }
-
- return $icons;
- }
-
- /**
- * Obtain ranks
- */
- function obtain_ranks()
- {
- if (($ranks = $this->driver->get('_ranks')) === false)
- {
- global $db;
-
- $sql = 'SELECT *
- FROM ' . RANKS_TABLE . '
- ORDER BY rank_min DESC';
- $result = $db->sql_query($sql);
-
- $ranks = array();
- while ($row = $db->sql_fetchrow($result))
- {
- if ($row['rank_special'])
- {
- $ranks['special'][$row['rank_id']] = array(
- 'rank_title' => $row['rank_title'],
- 'rank_image' => $row['rank_image']
- );
- }
- else
- {
- $ranks['normal'][] = array(
- 'rank_title' => $row['rank_title'],
- 'rank_min' => $row['rank_min'],
- 'rank_image' => $row['rank_image']
- );
- }
- }
- $db->sql_freeresult($result);
-
- $this->driver->put('_ranks', $ranks);
- }
-
- return $ranks;
- }
-
- /**
- * Obtain allowed extensions
- *
- * @param mixed $forum_id If false then check for private messaging, if int then check for forum id. If true, then only return extension informations.
- *
- * @return array allowed extensions array.
- */
- function obtain_attach_extensions($forum_id)
- {
- if (($extensions = $this->driver->get('_extensions')) === false)
- {
- global $db;
-
- $extensions = array(
- '_allowed_post' => array(),
- '_allowed_pm' => array(),
- );
-
- // The rule is to only allow those extensions defined. ;)
- $sql = 'SELECT e.extension, g.*
- FROM ' . EXTENSIONS_TABLE . ' e, ' . EXTENSION_GROUPS_TABLE . ' g
- WHERE e.group_id = g.group_id
- AND (g.allow_group = 1 OR g.allow_in_pm = 1)';
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $extension = strtolower(trim($row['extension']));
-
- $extensions[$extension] = array(
- 'display_cat' => (int) $row['cat_id'],
- 'download_mode' => (int) $row['download_mode'],
- 'upload_icon' => trim($row['upload_icon']),
- 'max_filesize' => (int) $row['max_filesize'],
- 'allow_group' => $row['allow_group'],
- 'allow_in_pm' => $row['allow_in_pm'],
- 'group_name' => $row['group_name'],
- );
-
- $allowed_forums = ($row['allowed_forums']) ? unserialize(trim($row['allowed_forums'])) : array();
-
- // Store allowed extensions forum wise
- if ($row['allow_group'])
- {
- $extensions['_allowed_post'][$extension] = (!sizeof($allowed_forums)) ? 0 : $allowed_forums;
- }
-
- if ($row['allow_in_pm'])
- {
- $extensions['_allowed_pm'][$extension] = 0;
- }
- }
- $db->sql_freeresult($result);
-
- $this->driver->put('_extensions', $extensions);
- }
-
- // Forum post
- if ($forum_id === false)
- {
- // We are checking for private messages, therefore we only need to get the pm extensions...
- $return = array('_allowed_' => array());
-
- foreach ($extensions['_allowed_pm'] as $extension => $check)
- {
- $return['_allowed_'][$extension] = 0;
- $return[$extension] = $extensions[$extension];
- }
-
- $extensions = $return;
- }
- else if ($forum_id === true)
- {
- return $extensions;
- }
- else
- {
- $forum_id = (int) $forum_id;
- $return = array('_allowed_' => array());
-
- foreach ($extensions['_allowed_post'] as $extension => $check)
- {
- // Check for allowed forums
- if (is_array($check))
- {
- $allowed = (!in_array($forum_id, $check)) ? false : true;
- }
- else
- {
- $allowed = true;
- }
-
- if ($allowed)
- {
- $return['_allowed_'][$extension] = 0;
- $return[$extension] = $extensions[$extension];
- }
- }
-
- $extensions = $return;
- }
-
- if (!isset($extensions['_allowed_']))
- {
- $extensions['_allowed_'] = array();
- }
-
- return $extensions;
- }
-
- /**
- * Obtain active bots
- */
- function obtain_bots()
- {
- if (($bots = $this->driver->get('_bots')) === false)
- {
- global $db;
-
- switch ($db->sql_layer)
- {
- case 'mssql':
- case 'mssql_odbc':
- case 'mssqlnative':
- $sql = 'SELECT user_id, bot_agent, bot_ip
- FROM ' . BOTS_TABLE . '
- WHERE bot_active = 1
- ORDER BY LEN(bot_agent) DESC';
- break;
-
- case 'firebird':
- $sql = 'SELECT user_id, bot_agent, bot_ip
- FROM ' . BOTS_TABLE . '
- WHERE bot_active = 1
- ORDER BY CHAR_LENGTH(bot_agent) DESC';
- break;
-
- // LENGTH supported by MySQL, IBM DB2 and Oracle for sure...
- default:
- $sql = 'SELECT user_id, bot_agent, bot_ip
- FROM ' . BOTS_TABLE . '
- WHERE bot_active = 1
- ORDER BY LENGTH(bot_agent) DESC';
- break;
- }
- $result = $db->sql_query($sql);
-
- $bots = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $bots[] = $row;
- }
- $db->sql_freeresult($result);
-
- $this->driver->put('_bots', $bots);
- }
-
- return $bots;
- }
-
- /**
- * Obtain cfg file data
- */
- function obtain_cfg_items($style)
- {
- global $config, $phpbb_root_path;
-
- $parsed_array = $this->driver->get('_cfg_' . $style['style_path']);
-
- if ($parsed_array === false)
- {
- $parsed_array = array();
- }
-
- $filename = $phpbb_root_path . 'styles/' . $style['style_path'] . '/style.cfg';
-
- if (!file_exists($filename))
- {
- return $parsed_array;
- }
-
- if (!isset($parsed_array['filetime']) || (($config['load_tplcompile'] && @filemtime($filename) > $parsed_array['filetime'])))
- {
- // Re-parse cfg file
- $parsed_array = parse_cfg_file($filename);
- $parsed_array['filetime'] = @filemtime($filename);
-
- $this->driver->put('_cfg_' . $style['style_path'], $parsed_array);
- }
-
- return $parsed_array;
- }
-
- /**
- * Obtain disallowed usernames
- */
- function obtain_disallowed_usernames()
- {
- if (($usernames = $this->driver->get('_disallowed_usernames')) === false)
- {
- global $db;
-
- $sql = 'SELECT disallow_username
- FROM ' . DISALLOW_TABLE;
- $result = $db->sql_query($sql);
-
- $usernames = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $usernames[] = str_replace('%', '.*?', preg_quote(utf8_clean_string($row['disallow_username']), '#'));
- }
- $db->sql_freeresult($result);
-
- $this->driver->put('_disallowed_usernames', $usernames);
- }
-
- return $usernames;
- }
-
- /**
- * Obtain hooks...
- */
- function obtain_hooks()
- {
- global $phpbb_root_path, $phpEx;
-
- if (($hook_files = $this->driver->get('_hooks')) === false)
- {
- $hook_files = array();
-
- // Now search for hooks...
- $dh = @opendir($phpbb_root_path . 'includes/hooks/');
-
- if ($dh)
- {
- while (($file = readdir($dh)) !== false)
- {
- if (strpos($file, 'hook_') === 0 && substr($file, -(strlen($phpEx) + 1)) === '.' . $phpEx)
- {
- $hook_files[] = substr($file, 0, -(strlen($phpEx) + 1));
- }
- }
- closedir($dh);
- }
-
- $this->driver->put('_hooks', $hook_files);
- }
-
- return $hook_files;
- }
-}
diff --git a/phpBB/includes/captcha/captcha_factory.php b/phpBB/includes/captcha/captcha_factory.php
index 1ed8e119b5..fac45087e3 100644
--- a/phpBB/includes/captcha/captcha_factory.php
+++ b/phpBB/includes/captcha/captcha_factory.php
@@ -50,7 +50,8 @@ class phpbb_captcha_factory
{
include($phpbb_root_path . "includes/captcha/plugins/{$name}_plugin." . $phpEx);
}
- call_user_func(array($name, 'garbage_collect'), 0);
+ $captcha = self::get_instance($name);
+ $captcha->garbage_collect(0);
}
/**
diff --git a/phpBB/includes/captcha/captcha_non_gd.php b/phpBB/includes/captcha/captcha_non_gd.php
index c2b97423e6..bb5067cafa 100644
--- a/phpBB/includes/captcha/captcha_non_gd.php
+++ b/phpBB/includes/captcha/captcha_non_gd.php
@@ -118,7 +118,7 @@ class captcha
$new_line = '';
$end = strlen($scanline) - ceil($width/2);
- for ($i = floor($width/2); $i < $end; $i++)
+ for ($i = (int) floor($width / 2); $i < $end; $i++)
{
$pixel = ord($scanline{$i});
diff --git a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php
index ec7636f511..6843f25d72 100644
--- a/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php
+++ b/phpBB/includes/captcha/plugins/phpbb_captcha_qa_plugin.php
@@ -110,12 +110,8 @@ class phpbb_captcha_qa
*/
static public function is_installed()
{
- global $db, $phpbb_root_path, $phpEx;
+ global $db;
- if (!class_exists('phpbb_db_tools', false))
- {
- 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);
@@ -297,12 +293,8 @@ class phpbb_captcha_qa
*/
function install()
{
- global $db, $phpbb_root_path, $phpEx;
+ global $db;
- 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);
diff --git a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php
index 83d40bbba7..cb21b04ec5 100644
--- a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php
+++ b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php
@@ -270,7 +270,7 @@ class phpbb_recaptcha extends phpbb_default_captcha
$response = '';
if (false == ($fs = @fsockopen($host, $port, $errno, $errstr, 10)))
{
- trigger_error('Could not open socket', E_USER_ERROR);
+ trigger_error('RECAPTCHA_SOCKET_ERROR', E_USER_ERROR);
}
fwrite($fs, $http_request);
diff --git a/phpBB/includes/class_loader.php b/phpBB/includes/class_loader.php
deleted file mode 100644
index 6082800908..0000000000
--- a/phpBB/includes/class_loader.php
+++ /dev/null
@@ -1,170 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* The class loader resolves class names to file system paths and loads them if
-* necessary.
-*
-* Classes have to be of the form phpbb_(dir_)*(classpart_)*, so directory names
-* must never contain underscores. Example: phpbb_dir_subdir_class_name is a
-* valid class name, while phpbb_dir_sub_dir_class_name is not.
-*
-* If every part of the class name is a directory, the last directory name is
-* also used as the filename, e.g. phpbb_dir would resolve to dir/dir.php.
-*
-* @package phpBB3
-*/
-class phpbb_class_loader
-{
- private $prefix;
- private $path;
- private $php_ext;
- private $cache;
-
- /**
- * A map of looked up class names to paths relative to $this->path.
- * This map is stored in cache and looked up if the cache is available.
- *
- * @var array
- */
- private $cached_paths = array();
-
- /**
- * Creates a new phpbb_class_loader, which loads files with the given
- * file extension from the given path.
- *
- * @param string $prefix Required class name prefix for files to be loaded
- * @param string $path Directory to load files from
- * @param string $php_ext The file extension for PHP files
- * @param phpbb_cache_driver_interface $cache An implementation of the phpBB cache interface.
- */
- public function __construct($prefix, $path, $php_ext = '.php', phpbb_cache_driver_interface $cache = null)
- {
- $this->prefix = $prefix;
- $this->path = $path;
- $this->php_ext = $php_ext;
-
- $this->set_cache($cache);
- }
-
- /**
- * Provide the class loader with a cache to store paths. If set to null, the
- * the class loader will resolve paths by checking for the existance of every
- * directory in the class name every time.
- *
- * @param phpbb_cache_driver_interface $cache An implementation of the phpBB cache interface.
- */
- public function set_cache(phpbb_cache_driver_interface $cache = null)
- {
- if ($cache)
- {
- $this->cached_paths = $cache->get('class_loader_' . $this->prefix);
-
- if ($this->cached_paths === false)
- {
- $this->cached_paths = array();
- }
- }
-
- $this->cache = $cache;
- }
-
- /**
- * Registers the class loader as an autoloader using SPL.
- */
- public function register()
- {
- spl_autoload_register(array($this, 'load_class'));
- }
-
- /**
- * Removes the class loader from the SPL autoloader stack.
- */
- public function unregister()
- {
- spl_autoload_unregister(array($this, 'load_class'));
- }
-
- /**
- * Resolves a phpBB class name to a relative path which can be included.
- *
- * @param string $class The class name to resolve, must have a phpbb_
- * prefix
- * @return string|bool A relative path to the file containing the
- * class or false if looking it up failed.
- */
- public function resolve_path($class)
- {
- if (isset($this->cached_paths[$class]))
- {
- return $this->path . $this->cached_paths[$class] . $this->php_ext;
- }
-
- if (!preg_match('/^' . $this->prefix . '[a-zA-Z0-9_]+$/', $class))
- {
- return false;
- }
-
- $parts = explode('_', substr($class, strlen($this->prefix)));
-
- $dirs = '';
-
- for ($i = 0, $n = sizeof($parts); $i < $n && is_dir($this->path . $dirs . $parts[$i]); $i++)
- {
- $dirs .= $parts[$i] . '/';
- }
-
- // no file name left => use last dir name as file name
- if ($i == sizeof($parts))
- {
- $parts[] = $parts[$i - 1];
- }
-
- $relative_path = $dirs . implode(array_slice($parts, $i, sizeof($parts) - $i), '_');
-
- if (!file_exists($this->path . $relative_path . $this->php_ext))
- {
- return false;
- }
-
- if ($this->cache)
- {
- $this->cached_paths[$class] = $relative_path;
- $this->cache->put('class_loader_' . $this->prefix, $this->cached_paths);
- }
-
- return $this->path . $relative_path . $this->php_ext;
- }
-
- /**
- * Resolves a class name to a path and then includes it.
- *
- * @param string $class The class name which is being loaded.
- */
- public function load_class($class)
- {
- if (substr($class, 0, strlen($this->prefix)) === $this->prefix)
- {
- $path = $this->resolve_path($class);
-
- if ($path)
- {
- require $path;
- }
- }
- }
-}
diff --git a/phpBB/includes/config/config.php b/phpBB/includes/config/config.php
deleted file mode 100644
index 4b533dd55c..0000000000
--- a/phpBB/includes/config/config.php
+++ /dev/null
@@ -1,170 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Configuration container class
-* @package phpBB3
-*/
-class phpbb_config implements ArrayAccess, IteratorAggregate, Countable
-{
- /**
- * The configuration data
- * @var array(string => string)
- */
- protected $config;
-
- /**
- * Creates a configuration container with a default set of values
- *
- * @param array(string => string) $config The configuration data.
- */
- public function __construct(array $config)
- {
- $this->config = $config;
- }
-
- /**
- * Retrieves an ArrayIterator over the configuration values.
- *
- * @return ArrayIterator An iterator over all config data
- */
- public function getIterator()
- {
- return new ArrayIterator($this->config);
- }
-
- /**
- * Checks if the specified config value exists.
- *
- * @param string $key The configuration option's name.
- * @return bool Whether the configuration option exists.
- */
- public function offsetExists($key)
- {
- return isset($this->config[$key]);
- }
-
- /**
- * Retrieves a configuration value.
- *
- * @param string $key The configuration option's name.
- * @return string The configuration value
- */
- public function offsetGet($key)
- {
- return (isset($this->config[$key])) ? $this->config[$key] : '';
- }
-
- /**
- * Temporarily overwrites the value of a configuration variable.
- *
- * The configuration change will not persist. It will be lost
- * after the request.
- *
- * @param string $key The configuration option's name.
- * @param string $value The temporary value.
- */
- public function offsetSet($key, $value)
- {
- $this->config[$key] = $value;
- }
-
- /**
- * Called when deleting a configuration value directly, triggers an error.
- *
- * @param string $key The configuration option's name.
- */
- public function offsetUnset($key)
- {
- trigger_error('Config values have to be deleted explicitly with the phpbb_config::delete($key) method.', E_USER_ERROR);
- }
-
- /**
- * Retrieves the number of configuration options currently set.
- *
- * @return int Number of config options
- */
- public function count()
- {
- return count($this->config);
- }
-
- /**
- * Removes a configuration option
- *
- * @param String $key The configuration option's name
- * @param bool $use_cache Whether this variable should be cached or if it
- * changes too frequently to be efficiently cached
- * @return null
- */
- public function delete($key, $use_cache = true)
- {
- unset($this->config[$key]);
- }
-
- /**
- * Sets a configuration option's value
- *
- * @param string $key The configuration option's name
- * @param string $value New configuration value
- * @param bool $use_cache Whether this variable should be cached or if it
- * changes too frequently to be efficiently cached.
- */
- public function set($key, $value, $use_cache = true)
- {
- $this->config[$key] = $value;
- }
-
- /**
- * Sets a configuration option's value only if the old_value matches the
- * current configuration value or the configuration value does not exist yet.
- *
- * @param string $key The configuration option's name
- * @param string $old_value Current configuration value
- * @param string $new_value New configuration value
- * @param bool $use_cache Whether this variable should be cached or if it
- * changes too frequently to be efficiently cached.
- * @return bool True if the value was changed, false otherwise.
- */
- public function set_atomic($key, $old_value, $new_value, $use_cache = true)
- {
- if (!isset($this->config[$key]) || $this->config[$key] == $old_value)
- {
- $this->config[$key] = $new_value;
- return true;
- }
- return false;
- }
-
- /**
- * Increments an integer configuration value.
- *
- * @param string $key The configuration option's name
- * @param int $increment Amount to increment by
- * @param bool $use_cache Whether this variable should be cached or if it
- * changes too frequently to be efficiently cached.
- */
- function increment($key, $increment, $use_cache = true)
- {
- if (!isset($this->config[$key]))
- {
- $this->config[$key] = 0;
- }
-
- $this->config[$key] += $increment;
- }
-}
diff --git a/phpBB/includes/config/db.php b/phpBB/includes/config/db.php
deleted file mode 100644
index 45f9f1cb21..0000000000
--- a/phpBB/includes/config/db.php
+++ /dev/null
@@ -1,207 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Configuration container class
-* @package phpBB3
-*/
-class phpbb_config_db extends phpbb_config
-{
- /**
- * Cache instance
- * @var phpbb_cache_driver_interface
- */
- protected $cache;
-
- /**
- * Database connection
- * @var dbal
- */
- protected $db;
-
- /**
- * Name of the database table used for configuration.
- * @var string
- */
- protected $table;
-
- /**
- * Creates a configuration container with a default set of values
- *
- * @param dbal $db Database connection
- * @param phpbb_cache_driver_interface $cache Cache instance
- * @param string $table Configuration table name
- */
- public function __construct(dbal $db, phpbb_cache_driver_interface $cache, $table)
- {
- $this->db = $db;
- $this->cache = $cache;
- $this->table = $table;
-
- if (($config = $cache->get('config')) !== false)
- {
- $sql = 'SELECT config_name, config_value
- FROM ' . $this->table . '
- WHERE is_dynamic = 1';
- $result = $this->db->sql_query($sql);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $config[$row['config_name']] = $row['config_value'];
- }
- $this->db->sql_freeresult($result);
- }
- else
- {
- $config = $cached_config = array();
-
- $sql = 'SELECT config_name, config_value, is_dynamic
- FROM ' . $this->table;
- $result = $this->db->sql_query($sql);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- if (!$row['is_dynamic'])
- {
- $cached_config[$row['config_name']] = $row['config_value'];
- }
-
- $config[$row['config_name']] = $row['config_value'];
- }
- $this->db->sql_freeresult($result);
-
- $cache->put('config', $cached_config);
- }
-
- parent::__construct($config);
- }
-
- /**
- * Removes a configuration option
- *
- * @param String $key The configuration option's name
- * @param bool $use_cache Whether this variable should be cached or if it
- * changes too frequently to be efficiently cached
- * @return null
- */
- public function delete($key, $use_cache = true)
- {
- $sql = 'DELETE FROM ' . $this->table . "
- WHERE config_name = '" . $this->db->sql_escape($key) . "'";
- $this->db->sql_query($sql);
-
- unset($this->config[$key]);
-
- if ($use_cache)
- {
- $this->cache->destroy('config');
- }
- }
-
- /**
- * Sets a configuration option's value
- *
- * @param string $key The configuration option's name
- * @param string $value New configuration value
- * @param bool $use_cache Whether this variable should be cached or if it
- * changes too frequently to be efficiently cached.
- */
- public function set($key, $value, $use_cache = true)
- {
- $this->set_atomic($key, false, $value, $use_cache);
- }
-
- /**
- * Sets a configuration option's value only if the old_value matches the
- * current configuration value or the configuration value does not exist yet.
- *
- * @param string $key The configuration option's name
- * @param mixed $old_value Current configuration value or false to ignore
- * the old value
- * @param string $new_value New configuration value
- * @param bool $use_cache Whether this variable should be cached or if it
- * changes too frequently to be efficiently cached
- * @return bool True if the value was changed, false otherwise
- */
- public function set_atomic($key, $old_value, $new_value, $use_cache = true)
- {
- $sql = 'UPDATE ' . $this->table . "
- SET config_value = '" . $this->db->sql_escape($new_value) . "'
- WHERE config_name = '" . $this->db->sql_escape($key) . "'";
-
- if ($old_value !== false)
- {
- $sql .= " AND config_value = '" . $this->db->sql_escape($old_value) . "'";
- }
-
- $result = $this->db->sql_query($sql);
-
- if (!$this->db->sql_affectedrows($result) && isset($this->config[$key]))
- {
- return false;
- }
-
- if (!isset($this->config[$key]))
- {
- $sql = 'INSERT INTO ' . $this->table . ' ' . $this->db->sql_build_array('INSERT', array(
- 'config_name' => $key,
- 'config_value' => $new_value,
- 'is_dynamic' => ($use_cache) ? 0 : 1));
- $this->db->sql_query($sql);
- }
-
- if ($use_cache)
- {
- $this->cache->destroy('config');
- }
-
- $this->config[$key] = $new_value;
- return true;
- }
-
- /**
- * Increments an integer config value directly in the database.
- *
- * Using this method instead of setting the new value directly avoids race
- * conditions and unlike set_atomic it cannot fail.
- *
- * @param string $key The configuration option's name
- * @param int $increment Amount to increment by
- * @param bool $use_cache Whether this variable should be cached or if it
- * changes too frequently to be efficiently cached.
- */
- function increment($key, $increment, $use_cache = true)
- {
- if (!isset($this->config[$key]))
- {
- $this->set($key, '0', $use_cache);
- }
-
- $sql_update = $this->db->cast_expr_to_string($this->db->cast_expr_to_bigint('config_value') . ' + ' . (int) $increment);
-
- $this->db->sql_query('UPDATE ' . $this->table . '
- SET config_value = ' . $sql_update . "
- WHERE config_name = '" . $this->db->sql_escape($key) . "'");
-
- if ($use_cache)
- {
- $this->cache->destroy('config');
- }
-
- $this->config[$key] += $increment;
- }
-}
diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php
index 78c4051708..ec78b488cd 100644
--- a/phpBB/includes/constants.php
+++ b/phpBB/includes/constants.php
@@ -87,6 +87,10 @@ define('ITEM_UNLOCKED', 0);
define('ITEM_LOCKED', 1);
define('ITEM_MOVED', 2);
+define('ITEM_UNAPPROVED', 0); // => has not yet been approved
+define('ITEM_APPROVED', 1); // => has been approved, and has not been soft deleted
+define('ITEM_DELETED', 2); // => has been soft deleted
+
// Forum Flags
define('FORUM_FLAG_LINK_TRACK', 1);
define('FORUM_FLAG_PRUNE_POLL', 2);
@@ -156,6 +160,7 @@ define('PHYSICAL_LINK', 2);
define('CONFIRM_REG', 1);
define('CONFIRM_LOGIN', 2);
define('CONFIRM_POST', 3);
+define('CONFIRM_REPORT', 4);
// Categories - Attachments
define('ATTACHMENT_CATEGORY_NONE', 0);
@@ -237,8 +242,11 @@ define('ICONS_TABLE', $table_prefix . 'icons');
define('LANG_TABLE', $table_prefix . 'lang');
define('LOG_TABLE', $table_prefix . 'log');
define('LOGIN_ATTEMPT_TABLE', $table_prefix . 'login_attempts');
+define('MIGRATIONS_TABLE', $table_prefix . 'migrations');
define('MODERATOR_CACHE_TABLE', $table_prefix . 'moderator_cache');
define('MODULES_TABLE', $table_prefix . 'modules');
+define('NOTIFICATION_TYPES_TABLE', $table_prefix . 'notification_types');
+define('NOTIFICATIONS_TABLE', $table_prefix . 'notifications');
define('POLL_OPTIONS_TABLE', $table_prefix . 'poll_options');
define('POLL_VOTES_TABLE', $table_prefix . 'poll_votes');
define('POSTS_TABLE', $table_prefix . 'posts');
@@ -267,11 +275,13 @@ define('STYLES_TEMPLATE_DATA_TABLE',$table_prefix . 'styles_template_data');
define('STYLES_THEME_TABLE', $table_prefix . 'styles_theme');
define('STYLES_IMAGESET_TABLE', $table_prefix . 'styles_imageset');
define('STYLES_IMAGESET_DATA_TABLE',$table_prefix . 'styles_imageset_data');
+define('TEAMPAGE_TABLE', $table_prefix . 'teampage');
define('TOPICS_TABLE', $table_prefix . 'topics');
define('TOPICS_POSTED_TABLE', $table_prefix . 'topics_posted');
define('TOPICS_TRACK_TABLE', $table_prefix . 'topics_track');
define('TOPICS_WATCH_TABLE', $table_prefix . 'topics_watch');
define('USER_GROUP_TABLE', $table_prefix . 'user_group');
+define('USER_NOTIFICATIONS_TABLE', $table_prefix . 'user_notifications');
define('USERS_TABLE', $table_prefix . 'users');
define('WARNINGS_TABLE', $table_prefix . 'warnings');
define('WORDS_TABLE', $table_prefix . 'words');
diff --git a/phpBB/includes/controller/exception.php b/phpBB/includes/controller/exception.php
deleted file mode 100644
index faa8b6b584..0000000000
--- a/phpBB/includes/controller/exception.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-/**
-*
-* @package controller
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Controller exception class
-* @package phpBB3
-*/
-class phpbb_controller_exception extends RuntimeException
-{
-}
diff --git a/phpBB/includes/controller/helper.php b/phpBB/includes/controller/helper.php
deleted file mode 100644
index 6cacc8fefa..0000000000
--- a/phpBB/includes/controller/helper.php
+++ /dev/null
@@ -1,117 +0,0 @@
-<?php
-/**
-*
-* @package controller
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\HttpFoundation\Response;
-
-/**
-* Controller helper class, contains methods that do things for controllers
-* @package phpBB3
-*/
-class phpbb_controller_helper
-{
- /**
- * Template object
- * @var phpbb_template
- */
- protected $template;
-
- /**
- * User object
- * @var phpbb_user
- */
- protected $user;
-
- /**
- * phpBB root path
- * @var string
- */
- protected $phpbb_root_path;
-
- /**
- * PHP extension
- * @var string
- */
- protected $php_ext;
-
- /**
- * Constructor
- *
- * @param phpbb_template $template Template object
- * @param phpbb_user $user User object
- * @param string $phpbb_root_path phpBB root path
- * @param string $php_ext PHP extension
- */
- public function __construct(phpbb_template $template, phpbb_user $user, $phpbb_root_path, $php_ext)
- {
- $this->template = $template;
- $this->user = $user;
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
- }
-
- /**
- * Automate setting up the page and creating the response object.
- *
- * @param string $handle The template handle to render
- * @param string $page_title The title of the page to output
- * @param int $status_code The status code to be sent to the page header
- * @return Response object containing rendered page
- */
- public function render($template_file, $page_title = '', $status_code = 200)
- {
- page_header($page_title);
-
- $this->template->set_filenames(array(
- 'body' => $template_file,
- ));
-
- page_footer(true, false, false);
-
- return new Response($this->template->assign_display('body'), $status_code);
- }
-
- /**
- * Easily generate a URL
- *
- * @param array $url_parts Each array element is a 'folder'
- * i.e. array('my', 'ext') maps to ./app.php/my/ext
- * @param mixed $query The Query string, passed directly into the second
- * argument of append_sid()
- * @return string A URL that has already been run through append_sid()
- */
- public function url(array $url_parts, $query = '')
- {
- return append_sid($this->phpbb_root_path . implode('/', $url_parts), $query);
- }
-
- /**
- * Output an error, effectively the same thing as trigger_error
- *
- * @param string $message The error message
- * @param string $code The error code (e.g. 404, 500, 503, etc.)
- * @return Response A Reponse instance
- */
- public function error($message, $code = 500)
- {
- $this->template->assign_vars(array(
- 'MESSAGE_TEXT' => $message,
- 'MESSAGE_TITLE' => $this->user->lang('INFORMATION'),
- ));
-
- return $this->render('message_body.html', $this->user->lang('INFORMATION'), $code);
- }
-}
diff --git a/phpBB/includes/controller/provider.php b/phpBB/includes/controller/provider.php
deleted file mode 100644
index b2a5b9f6b2..0000000000
--- a/phpBB/includes/controller/provider.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-/**
-*
-* @package controller
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\Routing\RouteCollection;
-use Symfony\Component\Routing\Loader\YamlFileLoader;
-use Symfony\Component\Config\FileLocator;
-
-/**
-* Controller interface
-* @package phpBB3
-*/
-class phpbb_controller_provider
-{
- /**
- * YAML file(s) containing route information
- * @var array
- */
- protected $routing_paths;
-
- /**
- * Construct method
- *
- * @param array() $routing_paths Array of strings containing paths
- * to YAML files holding route information
- */
- public function __construct($routing_paths = array())
- {
- $this->routing_paths = $routing_paths;
- }
-
- /**
- * Locate paths containing routing files
- * This sets an internal property but does not return the paths.
- *
- * @return The current instance of this object for method chaining
- */
- public function import_paths_from_finder(phpbb_extension_finder $finder)
- {
- // We hardcode the path to the core config directory
- // because the finder cannot find it
- $this->routing_paths = array_merge(array('config'), array_map('dirname', array_keys($finder
- ->directory('config')
- ->prefix('routing')
- ->suffix('yml')
- ->find()
- )));
-
- return $this;
- }
-
- /**
- * Get a list of controllers and return it
- *
- * @param string $base_path Base path to prepend to file paths
- * @return array Array of controllers and their route information
- */
- public function find($base_path = '')
- {
- $routes = new RouteCollection;
- foreach ($this->routing_paths as $path)
- {
- $loader = new YamlFileLoader(new FileLocator($base_path . $path));
- $routes->addCollection($loader->load('routing.yml'));
- }
-
- return $routes;
- }
-}
diff --git a/phpBB/includes/controller/resolver.php b/phpBB/includes/controller/resolver.php
deleted file mode 100644
index ee469aa9c8..0000000000
--- a/phpBB/includes/controller/resolver.php
+++ /dev/null
@@ -1,128 +0,0 @@
-<?php
-/**
-*
-* @package controller
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
-* Controller manager class
-* @package phpBB3
-*/
-class phpbb_controller_resolver implements ControllerResolverInterface
-{
- /**
- * User object
- * @var phpbb_user
- */
- protected $user;
-
- /**
- * ContainerInterface object
- * @var ContainerInterface
- */
- protected $container;
-
- /**
- * Construct method
- *
- * @param phpbb_user $user User Object
- * @param ContainerInterface $container ContainerInterface object
- */
- public function __construct(phpbb_user $user, ContainerInterface $container)
- {
- $this->user = $user;
- $this->container = $container;
- }
-
- /**
- * Load a controller callable
- *
- * @param Symfony\Component\HttpFoundation\Request $request Symfony Request object
- * @return bool|Callable Callable or false
- * @throws phpbb_controller_exception
- */
- public function getController(Request $request)
- {
- $controller = $request->attributes->get('_controller');
-
- if (!$controller)
- {
- throw new phpbb_controller_exception($this->user->lang['CONTROLLER_NOT_SPECIFIED']);
- }
-
- // Require a method name along with the service name
- if (stripos($controller, ':') === false)
- {
- throw new phpbb_controller_exception($this->user->lang['CONTROLLER_METHOD_NOT_SPECIFIED']);
- }
-
- list($service, $method) = explode(':', $controller);
-
- if (!$this->container->has($service))
- {
- throw new phpbb_controller_exception($this->user->lang('CONTROLLER_SERVICE_UNDEFINED', $service));
- }
-
- $controller_object = $this->container->get($service);
-
- return array($controller_object, $method);
- }
-
- /**
- * Dependencies should be specified in the service definition and can be
- * then accessed in __construct(). Arguments are sent through the URL path
- * and should match the parameters of the method you are using as your
- * controller.
- *
- * @param Symfony\Component\HttpFoundation\Request $request Symfony Request object
- * @param mixed $controller A callable (controller class, method)
- * @return bool False
- * @throws phpbb_controller_exception
- */
- public function getArguments(Request $request, $controller)
- {
- // At this point, $controller contains the object and method name
- list($object, $method) = $controller;
- $mirror = new ReflectionMethod($object, $method);
-
- $arguments = array();
- $parameters = $mirror->getParameters();
- $attributes = $request->attributes->all();
- foreach ($parameters as $param)
- {
- if (array_key_exists($param->name, $attributes))
- {
- $arguments[] = $attributes[$param->name];
- }
- else if ($param->getClass() && $param->getClass()->isInstance($request))
- {
- $arguments[] = $request;
- }
- else if ($param->isDefaultValueAvailable())
- {
- $arguments[] = $param->getDefaultValue();
- }
- else
- {
- throw new phpbb_controller_exception($this->user->lang('CONTROLLER_ARGUMENT_VALUE_MISSING', $param->getPosition() + 1, get_class($object) . ':' . $method, $param->name));
- }
- }
-
- return $arguments;
- }
-}
diff --git a/phpBB/includes/cron/manager.php b/phpBB/includes/cron/manager.php
deleted file mode 100644
index 84c9650830..0000000000
--- a/phpBB/includes/cron/manager.php
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Cron manager class.
-*
-* Finds installed cron tasks, stores task objects, provides task selection.
-*
-* @package phpBB3
-*/
-class phpbb_cron_manager
-{
- /**
- * Set of phpbb_cron_task_wrapper objects.
- * Array holding all tasks that have been found.
- *
- * @var array
- */
- protected $tasks = array();
-
- protected $phpbb_root_path;
- protected $php_ext;
-
- /**
- * Constructor. Loads all available tasks.
- *
- * @param array|Traversable $tasks Provides an iterable set of task names
- */
- public function __construct($tasks, $phpbb_root_path, $php_ext)
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
-
- $this->load_tasks($tasks);
- }
-
- /**
- * Loads tasks given by name, wraps them
- * and puts them into $this->tasks.
- *
- * @param array|Traversable $tasks Array of instances of phpbb_cron_task
- *
- * @return null
- */
- public function load_tasks($tasks)
- {
- foreach ($tasks as $task)
- {
- $this->tasks[] = $this->wrap_task($task);
- }
- }
-
- /**
- * Finds a task that is ready to run.
- *
- * If several tasks are ready, any one of them could be returned.
- *
- * If no tasks are ready, null is returned.
- *
- * @return phpbb_cron_task_wrapper|null
- */
- public function find_one_ready_task()
- {
- foreach ($this->tasks as $task)
- {
- if ($task->is_ready())
- {
- return $task;
- }
- }
- return null;
- }
-
- /**
- * Finds all tasks that are ready to run.
- *
- * @return array List of tasks which are ready to run (wrapped in phpbb_cron_task_wrapper).
- */
- public function find_all_ready_tasks()
- {
- $tasks = array();
- foreach ($this->tasks as $task)
- {
- if ($task->is_ready())
- {
- $tasks[] = $task;
- }
- }
- return $tasks;
- }
-
- /**
- * Finds a task by name.
- *
- * If there is no task with the specified name, null is returned.
- *
- * Web runner uses this method to resolve names to tasks.
- *
- * @param string $name Name of the task to look up.
- * @return phpbb_cron_task A task corresponding to the given name, or null.
- */
- public function find_task($name)
- {
- foreach ($this->tasks as $task)
- {
- if ($task->get_name() == $name)
- {
- return $task;
- }
- }
- return null;
- }
-
- /**
- * Wraps a task inside an instance of phpbb_cron_task_wrapper.
- *
- * @param phpbb_cron_task $task The task.
- * @return phpbb_cron_task_wrapper The wrapped task.
- */
- public function wrap_task(phpbb_cron_task $task)
- {
- return new phpbb_cron_task_wrapper($task, $this->phpbb_root_path, $this->php_ext);
- }
-}
diff --git a/phpBB/includes/cron/task/base.php b/phpBB/includes/cron/task/base.php
deleted file mode 100644
index 94a2f267b4..0000000000
--- a/phpBB/includes/cron/task/base.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Cron task base class. Provides sensible defaults for cron tasks
-* and partially implements cron task interface, making writing cron tasks easier.
-*
-* At a minimum, subclasses must override the run() method.
-*
-* Cron tasks need not inherit from this base class. If desired,
-* they may implement cron task interface directly.
-*
-* @package phpBB3
-*/
-abstract class phpbb_cron_task_base implements phpbb_cron_task
-{
- private $name;
-
- /**
- * Returns the name of the task.
- *
- * @return string Name of wrapped task.
- */
- public function get_name()
- {
- return $this->name;
- }
-
- /**
- * Sets the name of the task.
- *
- * @param string $name The task name
- */
- public function set_name($name)
- {
- $this->name = $name;
- }
-
- /**
- * Returns whether this cron task can run, given current board configuration.
- *
- * For example, a cron task that prunes forums can only run when
- * forum pruning is enabled.
- *
- * @return bool
- */
- public function is_runnable()
- {
- return true;
- }
-
- /**
- * Returns whether this cron task should run now, because enough time
- * has passed since it was last run.
- *
- * @return bool
- */
- public function should_run()
- {
- return true;
- }
-}
diff --git a/phpBB/includes/cron/task/core/prune_all_forums.php b/phpBB/includes/cron/task/core/prune_all_forums.php
deleted file mode 100644
index ee0b5f7626..0000000000
--- a/phpBB/includes/cron/task/core/prune_all_forums.php
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Prune all forums cron task.
-*
-* It is intended to be invoked from system cron.
-* This task will find all forums for which pruning is enabled, and will
-* prune all forums as necessary.
-*
-* @package phpBB3
-*/
-class phpbb_cron_task_core_prune_all_forums extends phpbb_cron_task_base
-{
- protected $phpbb_root_path;
- protected $php_ext;
- protected $config;
- protected $db;
-
- /**
- * Constructor.
- *
- * @param string $phpbb_root_path The root path
- * @param string $php_ext The PHP extension
- * @param phpbb_config $config The config
- * @param dbal $db The db connection
- */
- public function __construct($phpbb_root_path, $php_ext, phpbb_config $config, dbal $db)
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
- $this->config = $config;
- $this->db = $db;
- }
-
- /**
- * Runs this cron task.
- *
- * @return null
- */
- public function run()
- {
- if (!function_exists('auto_prune'))
- {
- include($this->phpbb_root_path . 'includes/functions_admin.' . $this->php_ext);
- }
-
- $sql = 'SELECT forum_id, prune_next, enable_prune, prune_days, prune_viewed, forum_flags, prune_freq
- FROM ' . FORUMS_TABLE . "
- WHERE enable_prune = 1
- AND prune_next < " . time();
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- if ($row['prune_days'])
- {
- auto_prune($row['forum_id'], 'posted', $row['forum_flags'], $row['prune_days'], $row['prune_freq']);
- }
-
- if ($row['prune_viewed'])
- {
- auto_prune($row['forum_id'], 'viewed', $row['forum_flags'], $row['prune_viewed'], $row['prune_freq']);
- }
- }
- $this->db->sql_freeresult($result);
- }
-
- /**
- * Returns whether this cron task can run, given current board configuration.
- *
- * This cron task will only run when system cron is utilised.
- *
- * @return bool
- */
- public function is_runnable()
- {
- return (bool) $this->config['use_system_cron'];
- }
-}
diff --git a/phpBB/includes/cron/task/core/prune_forum.php b/phpBB/includes/cron/task/core/prune_forum.php
deleted file mode 100644
index fa7a761d88..0000000000
--- a/phpBB/includes/cron/task/core/prune_forum.php
+++ /dev/null
@@ -1,163 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Prune one forum cron task.
-*
-* It is intended to be used when cron is invoked via web.
-* This task can decide whether it should be run using data obtained by viewforum
-* code, without making additional database queries.
-*
-* @package phpBB3
-*/
-class phpbb_cron_task_core_prune_forum extends phpbb_cron_task_base implements phpbb_cron_task_parametrized
-{
- protected $phpbb_root_path;
- protected $php_ext;
- protected $config;
- protected $db;
-
- /**
- * If $forum_data is given, it is assumed to contain necessary information
- * about a single forum that is to be pruned.
- *
- * If $forum_data is not given, forum id will be retrieved via request_var
- * and a database query will be performed to load the necessary information
- * about the forum.
- */
- protected $forum_data;
-
- /**
- * Constructor.
- *
- * @param string $phpbb_root_path The root path
- * @param string $php_ext The PHP extension
- * @param phpbb_config $config The config
- * @param dbal $db The db connection
- */
- public function __construct($phpbb_root_path, $php_ext, phpbb_config $config, dbal $db)
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
- $this->config = $config;
- $this->db = $db;
- }
-
- /**
- * Manually set forum data.
- *
- * @param array $forum_data Information about a forum to be pruned.
- */
- public function set_forum_data($forum_data)
- {
- $this->forum_data = $forum_data;
- }
-
- /**
- * Runs this cron task.
- *
- * @return null
- */
- public function run()
- {
- if (!function_exists('auto_prune'))
- {
- include($this->phpbb_root_path . 'includes/functions_admin.' . $this->php_ext);
- }
-
- if ($this->forum_data['prune_days'])
- {
- auto_prune($this->forum_data['forum_id'], 'posted', $this->forum_data['forum_flags'], $this->forum_data['prune_days'], $this->forum_data['prune_freq']);
- }
-
- if ($this->forum_data['prune_viewed'])
- {
- auto_prune($this->forum_data['forum_id'], 'viewed', $this->forum_data['forum_flags'], $this->forum_data['prune_viewed'], $this->forum_data['prune_freq']);
- }
- }
-
- /**
- * Returns whether this cron task can run, given current board configuration.
- *
- * This cron task will not run when system cron is utilised, as in
- * such cases prune_all_forums task would run instead.
- *
- * Additionally, this task must be given the forum data, either via
- * the constructor or parse_parameters method.
- *
- * @return bool
- */
- public function is_runnable()
- {
- return !$this->config['use_system_cron'] && $this->forum_data;
- }
-
- /**
- * Returns whether this cron task should run now, because enough time
- * has passed since it was last run.
- *
- * Forum pruning interval is specified in the forum data.
- *
- * @return bool
- */
- public function should_run()
- {
- return $this->forum_data['enable_prune'] && $this->forum_data['prune_next'] < time();
- }
-
- /**
- * Returns parameters of this cron task as an array.
- * The array has one key, f, whose value is id of the forum to be pruned.
- *
- * @return array
- */
- public function get_parameters()
- {
- return array('f' => $this->forum_data['forum_id']);
- }
-
- /**
- * Parses parameters found in $request, which is an instance of
- * phpbb_request_interface.
- *
- * It is expected to have a key f whose value is id of the forum to be pruned.
- *
- * @param phpbb_request_interface $request Request object.
- *
- * @return null
- */
- public function parse_parameters(phpbb_request_interface $request)
- {
- $this->forum_data = null;
- if ($request->is_set('f'))
- {
- $forum_id = $request->variable('f', 0);
-
- $sql = 'SELECT forum_id, prune_next, enable_prune, prune_days, prune_viewed, forum_flags, prune_freq
- FROM ' . FORUMS_TABLE . "
- WHERE forum_id = $forum_id";
- $result = $this->db->sql_query($sql);
- $row = $this->db->sql_fetchrow($result);
- $this->db->sql_freeresult($result);
-
- if ($row)
- {
- $this->forum_data = $row;
- }
- }
- }
-}
diff --git a/phpBB/includes/cron/task/core/queue.php b/phpBB/includes/cron/task/core/queue.php
deleted file mode 100644
index 732f9c6bea..0000000000
--- a/phpBB/includes/cron/task/core/queue.php
+++ /dev/null
@@ -1,82 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Queue cron task. Sends email and jabber messages queued by other scripts.
-*
-* @package phpBB3
-*/
-class phpbb_cron_task_core_queue extends phpbb_cron_task_base
-{
- protected $phpbb_root_path;
- protected $php_ext;
- protected $config;
-
- /**
- * Constructor.
- *
- * @param string $phpbb_root_path The root path
- * @param string $php_ext The PHP extension
- * @param phpbb_config $config The config
- */
- public function __construct($phpbb_root_path, $php_ext, phpbb_config $config)
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
- $this->config = $config;
- }
-
- /**
- * Runs this cron task.
- *
- * @return null
- */
- public function run()
- {
- if (!class_exists('queue'))
- {
- include($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext);
- }
- $queue = new queue();
- $queue->process();
- }
-
- /**
- * Returns whether this cron task can run, given current board configuration.
- *
- * Queue task is only run if the email queue (file) exists.
- *
- * @return bool
- */
- public function is_runnable()
- {
- return file_exists($this->phpbb_root_path . 'cache/queue.' . $this->php_ext);
- }
-
- /**
- * Returns whether this cron task should run now, because enough time
- * has passed since it was last run.
- *
- * The interval between queue runs is specified in board configuration.
- *
- * @return bool
- */
- public function should_run()
- {
- return $this->config['last_queue_run'] < time() - $this->config['queue_interval_config'];
- }
-}
diff --git a/phpBB/includes/cron/task/core/tidy_cache.php b/phpBB/includes/cron/task/core/tidy_cache.php
deleted file mode 100644
index 16a45dae7c..0000000000
--- a/phpBB/includes/cron/task/core/tidy_cache.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Tidy cache cron task.
-*
-* @package phpBB3
-*/
-class phpbb_cron_task_core_tidy_cache extends phpbb_cron_task_base
-{
- protected $config;
- protected $cache;
-
- /**
- * Constructor.
- *
- * @param phpbb_config $config The config
- * @param phpbb_cache_driver_interface $cache The cache driver
- */
- public function __construct(phpbb_config $config, phpbb_cache_driver_interface $cache)
- {
- $this->config = $config;
- $this->cache = $cache;
- }
-
- /**
- * Runs this cron task.
- *
- * @return null
- */
- public function run()
- {
- $this->cache->tidy();
- }
-
- /**
- * Returns whether this cron task can run, given current board configuration.
- *
- * Tidy cache cron task runs if the cache implementation in use
- * supports tidying.
- *
- * @return bool
- */
- public function is_runnable()
- {
- return true;
- }
-
- /**
- * Returns whether this cron task should run now, because enough time
- * has passed since it was last run.
- *
- * The interval between cache tidying is specified in board
- * configuration.
- *
- * @return bool
- */
- public function should_run()
- {
- return $this->config['cache_last_gc'] < time() - $this->config['cache_gc'];
- }
-}
diff --git a/phpBB/includes/cron/task/core/tidy_database.php b/phpBB/includes/cron/task/core/tidy_database.php
deleted file mode 100644
index b882e7b500..0000000000
--- a/phpBB/includes/cron/task/core/tidy_database.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Tidy database cron task.
-*
-* @package phpBB3
-*/
-class phpbb_cron_task_core_tidy_database extends phpbb_cron_task_base
-{
- protected $phpbb_root_path;
- protected $php_ext;
- protected $config;
-
- /**
- * Constructor.
- *
- * @param string $phpbb_root_path The root path
- * @param string $php_ext The PHP extension
- * @param phpbb_config $config The config
- */
- public function __construct($phpbb_root_path, $php_ext, phpbb_config $config)
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
- $this->config = $config;
- }
-
- /**
- * Runs this cron task.
- *
- * @return null
- */
- public function run()
- {
- if (!function_exists('tidy_database'))
- {
- include($this->phpbb_root_path . 'includes/functions_admin.' . $this->php_ext);
- }
- tidy_database();
- }
-
- /**
- * Returns whether this cron task should run now, because enough time
- * has passed since it was last run.
- *
- * The interval between database tidying is specified in board
- * configuration.
- *
- * @return bool
- */
- public function should_run()
- {
- return $this->config['database_last_gc'] < time() - $this->config['database_gc'];
- }
-}
diff --git a/phpBB/includes/cron/task/core/tidy_search.php b/phpBB/includes/cron/task/core/tidy_search.php
deleted file mode 100644
index fdbe31346e..0000000000
--- a/phpBB/includes/cron/task/core/tidy_search.php
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Tidy search cron task.
-*
-* Will only run when the currently selected search backend supports tidying.
-*
-* @package phpBB3
-*/
-class phpbb_cron_task_core_tidy_search extends phpbb_cron_task_base
-{
- protected $phpbb_root_path;
- protected $php_ext;
- protected $auth;
- protected $config;
- protected $db;
- protected $user;
-
- /**
- * Constructor.
- *
- * @param string $phpbb_root_path The root path
- * @param string $php_ext The PHP extension
- * @param phpbb_auth $auth The auth
- * @param phpbb_config $config The config
- * @param dbal $db The db connection
- * @param phpbb_user $user The user
- */
- public function __construct($phpbb_root_path, $php_ext, phpbb_auth $auth, phpbb_config $config, dbal $db, phpbb_user $user)
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
- $this->auth = $auth;
- $this->config = $config;
- $this->db = $db;
- $this->user = $user;
- }
-
- /**
- * Runs this cron task.
- *
- * @return null
- */
- public function run()
- {
- // Select the search method
- $search_type = basename($this->config['search_type']);
-
- if (!class_exists($search_type))
- {
- include($this->phpbb_root_path . "includes/search/$search_type." . $this->php_ext);
- }
-
- // We do some additional checks in the module to ensure it can actually be utilised
- $error = false;
- $search = new $search_type($error, $this->phpbb_root_path, $this->php_ext, $this->auth, $this->config, $this->db, $this->user);
-
- if (!$error)
- {
- $search->tidy();
- }
- }
-
- /**
- * Returns whether this cron task can run, given current board configuration.
- *
- * Search cron task is runnable in all normal use. It may not be
- * runnable if the search backend implementation selected in board
- * configuration does not exist.
- *
- * @return bool
- */
- public function is_runnable()
- {
- // Select the search method
- $search_type = basename($this->config['search_type']);
-
- return file_exists($this->phpbb_root_path . 'includes/search/' . $search_type . '.' . $this->php_ext);
- }
-
- /**
- * Returns whether this cron task should run now, because enough time
- * has passed since it was last run.
- *
- * The interval between search tidying is specified in board
- * configuration.
- *
- * @return bool
- */
- public function should_run()
- {
- return $this->config['search_last_gc'] < time() - $this->config['search_gc'];
- }
-}
diff --git a/phpBB/includes/cron/task/core/tidy_sessions.php b/phpBB/includes/cron/task/core/tidy_sessions.php
deleted file mode 100644
index 95f55235c9..0000000000
--- a/phpBB/includes/cron/task/core/tidy_sessions.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Tidy sessions cron task.
-*
-* @package phpBB3
-*/
-class phpbb_cron_task_core_tidy_sessions extends phpbb_cron_task_base
-{
- protected $config;
- protected $user;
-
- /**
- * Constructor.
- *
- * @param phpbb_config $config The config
- * @param phpbb_user $user The user
- */
- public function __construct(phpbb_config $config, phpbb_user $user)
- {
- $this->config = $config;
- $this->user = $user;
- }
-
- /**
- * Runs this cron task.
- *
- * @return null
- */
- public function run()
- {
- $this->user->session_gc();
- }
-
- /**
- * Returns whether this cron task should run now, because enough time
- * has passed since it was last run.
- *
- * The interval between session tidying is specified in board
- * configuration.
- *
- * @return bool
- */
- public function should_run()
- {
- return $this->config['session_last_gc'] < time() - $this->config['session_gc'];
- }
-}
diff --git a/phpBB/includes/cron/task/core/tidy_warnings.php b/phpBB/includes/cron/task/core/tidy_warnings.php
deleted file mode 100644
index 2a7798e56e..0000000000
--- a/phpBB/includes/cron/task/core/tidy_warnings.php
+++ /dev/null
@@ -1,84 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Tidy warnings cron task.
-*
-* Will only run when warnings are configured to expire.
-*
-* @package phpBB3
-*/
-class phpbb_cron_task_core_tidy_warnings extends phpbb_cron_task_base
-{
- protected $phpbb_root_path;
- protected $php_ext;
- protected $config;
-
- /**
- * Constructor.
- *
- * @param string $phpbb_root_path The root path
- * @param string $php_ext The PHP extension
- * @param phpbb_config $config The config
- */
- public function __construct($phpbb_root_path, $php_ext, phpbb_config $config)
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
- $this->config = $config;
- }
-
- /**
- * Runs this cron task.
- *
- * @return null
- */
- public function run()
- {
- if (!function_exists('tidy_warnings'))
- {
- include($this->phpbb_root_path . 'includes/functions_admin.' . $this->php_ext);
- }
- tidy_warnings();
- }
-
- /**
- * Returns whether this cron task can run, given current board configuration.
- *
- * If warnings are set to never expire, this cron task will not run.
- *
- * @return bool
- */
- public function is_runnable()
- {
- return (bool) $this->config['warnings_expire_days'];
- }
-
- /**
- * Returns whether this cron task should run now, because enough time
- * has passed since it was last run.
- *
- * The interval between warnings tidying is specified in board
- * configuration.
- *
- * @return bool
- */
- public function should_run()
- {
- return $this->config['warnings_last_gc'] < time() - $this->config['warnings_gc'];
- }
-}
diff --git a/phpBB/includes/cron/task/parametrized.php b/phpBB/includes/cron/task/parametrized.php
deleted file mode 100644
index 5f0e46eafc..0000000000
--- a/phpBB/includes/cron/task/parametrized.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Parametrized cron task interface.
-*
-* Parametrized cron tasks are somewhat of a cross between regular cron tasks and
-* delayed jobs. Whereas regular cron tasks perform some action globally,
-* parametrized cron tasks perform actions on a particular object (or objects).
-* Parametrized cron tasks do not make sense and are not usable without
-* specifying these objects.
-*
-* @package phpBB3
-*/
-interface phpbb_cron_task_parametrized extends phpbb_cron_task
-{
- /**
- * Returns parameters of this cron task as an array.
- *
- * The array must map string keys to string values.
- *
- * @return array
- */
- public function get_parameters();
-
- /**
- * Parses parameters found in $request, which is an instance of
- * phpbb_request_interface.
- *
- * $request contains user input and must not be trusted.
- * Cron task must validate all data before using it.
- *
- * @param phpbb_request_interface $request Request object.
- *
- * @return null
- */
- public function parse_parameters(phpbb_request_interface $request);
-}
diff --git a/phpBB/includes/cron/task/task.php b/phpBB/includes/cron/task/task.php
deleted file mode 100644
index 2d585df96d..0000000000
--- a/phpBB/includes/cron/task/task.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Cron task interface
-* @package phpBB3
-*/
-interface phpbb_cron_task
-{
- /**
- * Returns the name of the task.
- *
- * @return string Name of wrapped task.
- */
- public function get_name();
-
- /**
- * Runs this cron task.
- *
- * @return null
- */
- public function run();
-
- /**
- * Returns whether this cron task can run, given current board configuration.
- *
- * For example, a cron task that prunes forums can only run when
- * forum pruning is enabled.
- *
- * @return bool
- */
- public function is_runnable();
-
- /**
- * Returns whether this cron task should run now, because enough time
- * has passed since it was last run.
- *
- * @return bool
- */
- public function should_run();
-}
diff --git a/phpBB/includes/cron/task/wrapper.php b/phpBB/includes/cron/task/wrapper.php
deleted file mode 100644
index 386fb5b383..0000000000
--- a/phpBB/includes/cron/task/wrapper.php
+++ /dev/null
@@ -1,108 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Cron task wrapper class.
-* Enhances cron tasks with convenience methods that work identically for all tasks.
-*
-* @package phpBB3
-*/
-class phpbb_cron_task_wrapper
-{
- protected $task;
- protected $phpbb_root_path;
- protected $php_ext;
-
- /**
- * Constructor.
- *
- * Wraps a task $task, which must implement cron_task interface.
- *
- * @param phpbb_cron_task $task The cron task to wrap.
- */
- public function __construct(phpbb_cron_task $task, $phpbb_root_path, $php_ext)
- {
- $this->task = $task;
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
- }
-
- /**
- * Returns whether the wrapped task is parametrised.
- *
- * Parametrized tasks accept parameters during initialization and must
- * normally be scheduled with parameters.
- *
- * @return bool Whether or not this task is parametrized.
- */
- public function is_parametrized()
- {
- return $this->task instanceof phpbb_cron_task_parametrized;
- }
-
- /**
- * Returns whether the wrapped task is ready to run.
- *
- * A task is ready to run when it is runnable according to current configuration
- * and enough time has passed since it was last run.
- *
- * @return bool Whether the wrapped task is ready to run.
- */
- public function is_ready()
- {
- return $this->task->is_runnable() && $this->task->should_run();
- }
-
- /**
- * Returns a url through which this task may be invoked via web.
- *
- * When system cron is not in use, running a cron task is accomplished
- * by outputting an image with the url returned by this function as
- * source.
- *
- * @return string URL through which this task may be invoked.
- */
- public function get_url()
- {
- $name = $this->get_name();
- if ($this->is_parametrized())
- {
- $params = $this->task->get_parameters();
- $extra = '';
- foreach ($params as $key => $value)
- {
- $extra .= '&amp;' . $key . '=' . urlencode($value);
- }
- }
- else
- {
- $extra = '';
- }
- $url = append_sid($this->phpbb_root_path . 'cron.' . $this->php_ext, 'cron_type=' . $name . $extra);
- return $url;
- }
-
- /**
- * Forwards all other method calls to the wrapped task implementation.
- *
- * @return mixed
- */
- public function __call($name, $args)
- {
- return call_user_func_array(array($this->task, $name), $args);
- }
-}
diff --git a/phpBB/includes/datetime.php b/phpBB/includes/datetime.php
deleted file mode 100644
index b3462ddf67..0000000000
--- a/phpBB/includes/datetime.php
+++ /dev/null
@@ -1,158 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*/
-
-/**
-* phpBB custom extensions to the PHP DateTime class
-* This handles the relative formats phpBB employs
-*/
-class phpbb_datetime extends DateTime
-{
- /**
- * String used to wrap the date segment which should be replaced by today/tomorrow/yesterday
- */
- const RELATIVE_WRAPPER = '|';
-
- /**
- * @var user User who is the context for this DateTime instance
- */
- protected $user;
-
- /**
- * @var array Date formats are preprocessed by phpBB, to save constant recalculation they are cached.
- */
- static protected $format_cache = array();
-
- /**
- * Constructs a new instance of phpbb_datetime, expanded to include an argument to inject
- * the user context and modify the timezone to the users selected timezone if one is not set.
- *
- * @param string $time String in a format accepted by strtotime().
- * @param DateTimeZone $timezone Time zone of the time.
- * @param user User object for context.
- */
- public function __construct($user, $time = 'now', DateTimeZone $timezone = null)
- {
- $this->user = $user;
- $timezone = $timezone ?: $this->user->timezone;
-
- parent::__construct($time, $timezone);
- }
-
- /**
- * Formats the current date time into the specified format
- *
- * @param string $format Optional format to use for output, defaults to users chosen format
- * @param boolean $force_absolute Force output of a non relative date
- * @return string Formatted date time
- */
- public function format($format = '', $force_absolute = false)
- {
- $format = $format ? $format : $this->user->date_format;
- $format = self::format_cache($format, $this->user);
- $relative = ($format['is_short'] && !$force_absolute);
- $now = new self($this->user, 'now', $this->user->timezone);
-
- $timestamp = $this->getTimestamp();
- $now_ts = $now->getTimeStamp();
-
- $delta = $now_ts - $timestamp;
-
- if ($relative)
- {
- /*
- * Check the delta is less than or equal to 1 hour
- * and the delta not more than a minute in the past
- * and the delta is either greater than -5 seconds or timestamp
- * and current time are of the same minute (they must be in the same hour already)
- * finally check that relative dates are supported by the language pack
- */
- if ($delta <= 3600 && $delta > -60 &&
- ($delta >= -5 || (($now_ts / 60) % 60) == (($timestamp / 60) % 60))
- && isset($this->user->lang['datetime']['AGO']))
- {
- return $this->user->lang(array('datetime', 'AGO'), max(0, (int) floor($delta / 60)));
- }
- else
- {
- $midnight = clone $now;
- $midnight->setTime(0, 0, 0);
-
- $midnight = $midnight->getTimestamp();
-
- $day = false;
-
- if ($timestamp > $midnight + 86400)
- {
- $day = 'TOMORROW';
- }
- else if ($timestamp > $midnight)
- {
- $day = 'TODAY';
- }
- else if ($timestamp > $midnight - 86400)
- {
- $day = 'YESTERDAY';
- }
-
- if ($day !== false)
- {
- // Format using the short formatting and finally swap out the relative token placeholder with the correct value
- return str_replace(self::RELATIVE_WRAPPER . self::RELATIVE_WRAPPER, $this->user->lang['datetime'][$day], strtr(parent::format($format['format_short']), $format['lang']));
- }
- }
- }
-
- return strtr(parent::format($format['format_long']), $format['lang']);
- }
-
- /**
- * Magic method to convert DateTime object to string
- *
- * @return Formatted date time, according to the users default settings.
- */
- public function __toString()
- {
- return $this->format();
- }
-
- /**
- * Pre-processes the specified date format
- *
- * @param string $format Output format
- * @param user $user User object to use for localisation
- * @return array Processed date format
- */
- static protected function format_cache($format, $user)
- {
- $lang = $user->lang_name;
-
- if (!isset(self::$format_cache[$lang]))
- {
- self::$format_cache[$lang] = array();
- }
-
- if (!isset(self::$format_cache[$lang][$format]))
- {
- // Is the user requesting a friendly date format (i.e. 'Today 12:42')?
- self::$format_cache[$lang][$format] = array(
- 'is_short' => strpos($format, self::RELATIVE_WRAPPER) !== false,
- 'format_short' => substr($format, 0, strpos($format, self::RELATIVE_WRAPPER)) . self::RELATIVE_WRAPPER . self::RELATIVE_WRAPPER . substr(strrchr($format, self::RELATIVE_WRAPPER), 1),
- 'format_long' => str_replace(self::RELATIVE_WRAPPER, '', $format),
- 'lang' => $user->lang['datetime'],
- );
-
- // Short representation of month in format? Some languages use different terms for the long and short format of May
- if ((strpos($format, '\M') === false && strpos($format, 'M') !== false) || (strpos($format, '\r') === false && strpos($format, 'r') !== false))
- {
- self::$format_cache[$lang][$format]['lang']['May'] = $user->lang['datetime']['May_short'];
- }
- }
-
- return self::$format_cache[$lang][$format];
- }
-}
diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php
deleted file mode 100644
index 6df3aac9ce..0000000000
--- a/phpBB/includes/db/db_tools.php
+++ /dev/null
@@ -1,2457 +0,0 @@
-<?php
-/**
-*
-* @package dbal
-* @copyright (c) 2007 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Database Tools for handling cross-db actions such as altering columns, etc.
-* Currently not supported is returning SQL for creating tables.
-*
-* @package dbal
-*/
-class phpbb_db_tools
-{
- /**
- * Current sql layer
- */
- var $sql_layer = '';
-
- /**
- * @var object DB object
- */
- var $db = NULL;
-
- /**
- * The Column types for every database we support
- * @var array
- */
- var $dbms_type_map = array(
- 'mysql_41' => array(
- 'INT:' => 'int(%d)',
- 'BINT' => 'bigint(20)',
- 'UINT' => 'mediumint(8) UNSIGNED',
- 'UINT:' => 'int(%d) UNSIGNED',
- 'TINT:' => 'tinyint(%d)',
- 'USINT' => 'smallint(4) UNSIGNED',
- 'BOOL' => 'tinyint(1) UNSIGNED',
- 'VCHAR' => 'varchar(255)',
- 'VCHAR:' => 'varchar(%d)',
- 'CHAR:' => 'char(%d)',
- 'XSTEXT' => 'text',
- 'XSTEXT_UNI'=> 'varchar(100)',
- 'STEXT' => 'text',
- 'STEXT_UNI' => 'varchar(255)',
- 'TEXT' => 'text',
- 'TEXT_UNI' => 'text',
- 'MTEXT' => 'mediumtext',
- 'MTEXT_UNI' => 'mediumtext',
- 'TIMESTAMP' => 'int(11) UNSIGNED',
- 'DECIMAL' => 'decimal(5,2)',
- 'DECIMAL:' => 'decimal(%d,2)',
- 'PDECIMAL' => 'decimal(6,3)',
- 'PDECIMAL:' => 'decimal(%d,3)',
- 'VCHAR_UNI' => 'varchar(255)',
- 'VCHAR_UNI:'=> 'varchar(%d)',
- 'VCHAR_CI' => 'varchar(255)',
- 'VARBINARY' => 'varbinary(255)',
- ),
-
- 'mysql_40' => array(
- 'INT:' => 'int(%d)',
- 'BINT' => 'bigint(20)',
- 'UINT' => 'mediumint(8) UNSIGNED',
- 'UINT:' => 'int(%d) UNSIGNED',
- 'TINT:' => 'tinyint(%d)',
- 'USINT' => 'smallint(4) UNSIGNED',
- 'BOOL' => 'tinyint(1) UNSIGNED',
- 'VCHAR' => 'varbinary(255)',
- 'VCHAR:' => 'varbinary(%d)',
- 'CHAR:' => 'binary(%d)',
- 'XSTEXT' => 'blob',
- 'XSTEXT_UNI'=> 'blob',
- 'STEXT' => 'blob',
- 'STEXT_UNI' => 'blob',
- 'TEXT' => 'blob',
- 'TEXT_UNI' => 'blob',
- 'MTEXT' => 'mediumblob',
- 'MTEXT_UNI' => 'mediumblob',
- 'TIMESTAMP' => 'int(11) UNSIGNED',
- 'DECIMAL' => 'decimal(5,2)',
- 'DECIMAL:' => 'decimal(%d,2)',
- 'PDECIMAL' => 'decimal(6,3)',
- 'PDECIMAL:' => 'decimal(%d,3)',
- 'VCHAR_UNI' => 'blob',
- 'VCHAR_UNI:'=> array('varbinary(%d)', 'limit' => array('mult', 3, 255, 'blob')),
- 'VCHAR_CI' => 'blob',
- 'VARBINARY' => 'varbinary(255)',
- ),
-
- 'firebird' => array(
- 'INT:' => 'INTEGER',
- 'BINT' => 'DOUBLE PRECISION',
- 'UINT' => 'INTEGER',
- 'UINT:' => 'INTEGER',
- 'TINT:' => 'INTEGER',
- 'USINT' => 'INTEGER',
- 'BOOL' => 'INTEGER',
- 'VCHAR' => 'VARCHAR(255) CHARACTER SET NONE',
- 'VCHAR:' => 'VARCHAR(%d) CHARACTER SET NONE',
- 'CHAR:' => 'CHAR(%d) CHARACTER SET NONE',
- 'XSTEXT' => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE',
- 'STEXT' => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE',
- 'TEXT' => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE',
- 'MTEXT' => 'BLOB SUB_TYPE TEXT CHARACTER SET NONE',
- 'XSTEXT_UNI'=> 'VARCHAR(100) CHARACTER SET UTF8',
- 'STEXT_UNI' => 'VARCHAR(255) CHARACTER SET UTF8',
- 'TEXT_UNI' => 'BLOB SUB_TYPE TEXT CHARACTER SET UTF8',
- 'MTEXT_UNI' => 'BLOB SUB_TYPE TEXT CHARACTER SET UTF8',
- 'TIMESTAMP' => 'INTEGER',
- 'DECIMAL' => 'DOUBLE PRECISION',
- 'DECIMAL:' => 'DOUBLE PRECISION',
- 'PDECIMAL' => 'DOUBLE PRECISION',
- 'PDECIMAL:' => 'DOUBLE PRECISION',
- 'VCHAR_UNI' => 'VARCHAR(255) CHARACTER SET UTF8',
- 'VCHAR_UNI:'=> 'VARCHAR(%d) CHARACTER SET UTF8',
- 'VCHAR_CI' => 'VARCHAR(255) CHARACTER SET UTF8',
- 'VARBINARY' => 'CHAR(255) CHARACTER SET NONE',
- ),
-
- 'mssql' => array(
- 'INT:' => '[int]',
- 'BINT' => '[float]',
- 'UINT' => '[int]',
- 'UINT:' => '[int]',
- 'TINT:' => '[int]',
- 'USINT' => '[int]',
- 'BOOL' => '[int]',
- 'VCHAR' => '[varchar] (255)',
- 'VCHAR:' => '[varchar] (%d)',
- 'CHAR:' => '[char] (%d)',
- 'XSTEXT' => '[varchar] (1000)',
- 'STEXT' => '[varchar] (3000)',
- 'TEXT' => '[varchar] (8000)',
- 'MTEXT' => '[text]',
- 'XSTEXT_UNI'=> '[varchar] (100)',
- 'STEXT_UNI' => '[varchar] (255)',
- 'TEXT_UNI' => '[varchar] (4000)',
- 'MTEXT_UNI' => '[text]',
- 'TIMESTAMP' => '[int]',
- 'DECIMAL' => '[float]',
- 'DECIMAL:' => '[float]',
- 'PDECIMAL' => '[float]',
- 'PDECIMAL:' => '[float]',
- 'VCHAR_UNI' => '[varchar] (255)',
- 'VCHAR_UNI:'=> '[varchar] (%d)',
- 'VCHAR_CI' => '[varchar] (255)',
- 'VARBINARY' => '[varchar] (255)',
- ),
-
- 'mssqlnative' => array(
- 'INT:' => '[int]',
- 'BINT' => '[float]',
- 'UINT' => '[int]',
- 'UINT:' => '[int]',
- 'TINT:' => '[int]',
- 'USINT' => '[int]',
- 'BOOL' => '[int]',
- 'VCHAR' => '[varchar] (255)',
- 'VCHAR:' => '[varchar] (%d)',
- 'CHAR:' => '[char] (%d)',
- 'XSTEXT' => '[varchar] (1000)',
- 'STEXT' => '[varchar] (3000)',
- 'TEXT' => '[varchar] (8000)',
- 'MTEXT' => '[text]',
- 'XSTEXT_UNI'=> '[varchar] (100)',
- 'STEXT_UNI' => '[varchar] (255)',
- 'TEXT_UNI' => '[varchar] (4000)',
- 'MTEXT_UNI' => '[text]',
- 'TIMESTAMP' => '[int]',
- 'DECIMAL' => '[float]',
- 'DECIMAL:' => '[float]',
- 'PDECIMAL' => '[float]',
- 'PDECIMAL:' => '[float]',
- 'VCHAR_UNI' => '[varchar] (255)',
- 'VCHAR_UNI:'=> '[varchar] (%d)',
- 'VCHAR_CI' => '[varchar] (255)',
- 'VARBINARY' => '[varchar] (255)',
- ),
-
- 'oracle' => array(
- 'INT:' => 'number(%d)',
- 'BINT' => 'number(20)',
- 'UINT' => 'number(8)',
- 'UINT:' => 'number(%d)',
- 'TINT:' => 'number(%d)',
- 'USINT' => 'number(4)',
- 'BOOL' => 'number(1)',
- 'VCHAR' => 'varchar2(255)',
- 'VCHAR:' => 'varchar2(%d)',
- 'CHAR:' => 'char(%d)',
- 'XSTEXT' => 'varchar2(1000)',
- 'STEXT' => 'varchar2(3000)',
- 'TEXT' => 'clob',
- 'MTEXT' => 'clob',
- 'XSTEXT_UNI'=> 'varchar2(300)',
- 'STEXT_UNI' => 'varchar2(765)',
- 'TEXT_UNI' => 'clob',
- 'MTEXT_UNI' => 'clob',
- 'TIMESTAMP' => 'number(11)',
- 'DECIMAL' => 'number(5, 2)',
- 'DECIMAL:' => 'number(%d, 2)',
- 'PDECIMAL' => 'number(6, 3)',
- 'PDECIMAL:' => 'number(%d, 3)',
- 'VCHAR_UNI' => 'varchar2(765)',
- 'VCHAR_UNI:'=> array('varchar2(%d)', 'limit' => array('mult', 3, 765, 'clob')),
- 'VCHAR_CI' => 'varchar2(255)',
- 'VARBINARY' => 'raw(255)',
- ),
-
- 'sqlite' => array(
- 'INT:' => 'int(%d)',
- 'BINT' => 'bigint(20)',
- 'UINT' => 'INTEGER UNSIGNED', //'mediumint(8) UNSIGNED',
- 'UINT:' => 'INTEGER UNSIGNED', // 'int(%d) UNSIGNED',
- 'TINT:' => 'tinyint(%d)',
- 'USINT' => 'INTEGER UNSIGNED', //'mediumint(4) UNSIGNED',
- 'BOOL' => 'INTEGER UNSIGNED', //'tinyint(1) UNSIGNED',
- 'VCHAR' => 'varchar(255)',
- 'VCHAR:' => 'varchar(%d)',
- 'CHAR:' => 'char(%d)',
- 'XSTEXT' => 'text(65535)',
- 'STEXT' => 'text(65535)',
- 'TEXT' => 'text(65535)',
- 'MTEXT' => 'mediumtext(16777215)',
- 'XSTEXT_UNI'=> 'text(65535)',
- 'STEXT_UNI' => 'text(65535)',
- 'TEXT_UNI' => 'text(65535)',
- 'MTEXT_UNI' => 'mediumtext(16777215)',
- 'TIMESTAMP' => 'INTEGER UNSIGNED', //'int(11) UNSIGNED',
- 'DECIMAL' => 'decimal(5,2)',
- 'DECIMAL:' => 'decimal(%d,2)',
- 'PDECIMAL' => 'decimal(6,3)',
- 'PDECIMAL:' => 'decimal(%d,3)',
- 'VCHAR_UNI' => 'varchar(255)',
- 'VCHAR_UNI:'=> 'varchar(%d)',
- 'VCHAR_CI' => 'varchar(255)',
- 'VARBINARY' => 'blob',
- ),
-
- 'postgres' => array(
- 'INT:' => 'INT4',
- 'BINT' => 'INT8',
- 'UINT' => 'INT4', // unsigned
- 'UINT:' => 'INT4', // unsigned
- 'USINT' => 'INT2', // unsigned
- 'BOOL' => 'INT2', // unsigned
- 'TINT:' => 'INT2',
- 'VCHAR' => 'varchar(255)',
- 'VCHAR:' => 'varchar(%d)',
- 'CHAR:' => 'char(%d)',
- 'XSTEXT' => 'varchar(1000)',
- 'STEXT' => 'varchar(3000)',
- 'TEXT' => 'varchar(8000)',
- 'MTEXT' => 'TEXT',
- 'XSTEXT_UNI'=> 'varchar(100)',
- 'STEXT_UNI' => 'varchar(255)',
- 'TEXT_UNI' => 'varchar(4000)',
- 'MTEXT_UNI' => 'TEXT',
- 'TIMESTAMP' => 'INT4', // unsigned
- 'DECIMAL' => 'decimal(5,2)',
- 'DECIMAL:' => 'decimal(%d,2)',
- 'PDECIMAL' => 'decimal(6,3)',
- 'PDECIMAL:' => 'decimal(%d,3)',
- 'VCHAR_UNI' => 'varchar(255)',
- 'VCHAR_UNI:'=> 'varchar(%d)',
- 'VCHAR_CI' => 'varchar_ci',
- 'VARBINARY' => 'bytea',
- ),
- );
-
- /**
- * A list of types being unsigned for better reference in some db's
- * @var array
- */
- var $unsigned_types = array('UINT', 'UINT:', 'USINT', 'BOOL', 'TIMESTAMP');
-
- /**
- * A list of supported DBMS. We change this class to support more DBMS, the DBMS itself only need to follow some rules.
- * @var array
- */
- var $supported_dbms = array('firebird', 'mssql', 'mssqlnative', 'mysql_40', 'mysql_41', 'oracle', 'postgres', 'sqlite');
-
- /**
- * This is set to true if user only wants to return the 'to-be-executed' SQL statement(s) (as an array).
- * This mode has no effect on some methods (inserting of data for example). This is expressed within the methods command.
- */
- var $return_statements = false;
-
- /**
- * Constructor. Set DB Object and set {@link $return_statements return_statements}.
- *
- * @param phpbb_dbal $db DBAL object
- * @param bool $return_statements True if only statements should be returned and no SQL being executed
- */
- function phpbb_db_tools(&$db, $return_statements = false)
- {
- $this->db = $db;
- $this->return_statements = $return_statements;
-
- // Determine mapping database type
- switch ($this->db->sql_layer)
- {
- case 'mysql':
- $this->sql_layer = 'mysql_40';
- break;
-
- case 'mysql4':
- if (version_compare($this->db->sql_server_info(true), '4.1.3', '>='))
- {
- $this->sql_layer = 'mysql_41';
- }
- else
- {
- $this->sql_layer = 'mysql_40';
- }
- break;
-
- case 'mysqli':
- $this->sql_layer = 'mysql_41';
- break;
-
- case 'mssql':
- case 'mssql_odbc':
- $this->sql_layer = 'mssql';
- break;
-
- case 'mssqlnative':
- $this->sql_layer = 'mssqlnative';
- break;
-
- default:
- $this->sql_layer = $this->db->sql_layer;
- break;
- }
- }
-
- /**
- * Gets a list of tables in the database.
- *
- * @return array Array of table names (all lower case)
- */
- function sql_list_tables()
- {
- switch ($this->db->sql_layer)
- {
- case 'mysql':
- case 'mysql4':
- case 'mysqli':
- $sql = 'SHOW TABLES';
- break;
-
- case 'sqlite':
- $sql = 'SELECT name
- FROM sqlite_master
- WHERE type = "table"';
- break;
-
- case 'mssql':
- case 'mssql_odbc':
- case 'mssqlnative':
- $sql = "SELECT name
- FROM sysobjects
- WHERE type='U'";
- break;
-
- case 'postgres':
- $sql = 'SELECT relname
- FROM pg_stat_user_tables';
- break;
-
- case 'firebird':
- $sql = 'SELECT rdb$relation_name
- FROM rdb$relations
- WHERE rdb$view_source is null
- AND rdb$system_flag = 0';
- break;
-
- case 'oracle':
- $sql = 'SELECT table_name
- FROM USER_TABLES';
- break;
- }
-
- $result = $this->db->sql_query($sql);
-
- $tables = array();
- while ($row = $this->db->sql_fetchrow($result))
- {
- $name = current($row);
- $tables[$name] = $name;
- }
- $this->db->sql_freeresult($result);
-
- return $tables;
- }
-
- /**
- * Check if table exists
- *
- *
- * @param string $table_name The table name to check for
- * @return bool true if table exists, else false
- */
- function sql_table_exists($table_name)
- {
- $this->db->sql_return_on_error(true);
- $result = $this->db->sql_query_limit('SELECT * FROM ' . $table_name, 1);
- $this->db->sql_return_on_error(false);
-
- if ($result)
- {
- $this->db->sql_freeresult($result);
- return true;
- }
-
- return false;
- }
-
- /**
- * Create SQL Table
- *
- * @param string $table_name The table name to create
- * @param array $table_data Array containing table data.
- * @return array Statements if $return_statements is true.
- */
- function sql_create_table($table_name, $table_data)
- {
- // 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';
-
- // Determine if we have created a PRIMARY KEY in the earliest
- $primary_key_gen = false;
-
- // Determine if the table must be created with TEXTIMAGE
- $create_textimage = false;
-
- // Determine if the table requires a sequence
- $create_sequence = false;
-
- // Begin table sql statement
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- $table_sql = 'CREATE TABLE [' . $table_name . '] (' . "\n";
- break;
-
- default:
- $table_sql = 'CREATE TABLE ' . $table_name . ' (' . "\n";
- break;
- }
-
- // Iterate through the columns to create a table
- foreach ($table_data['COLUMNS'] as $column_name => $column_data)
- {
- // here lies an array, filled with information compiled on the column's data
- $prepared_column = $this->sql_prepare_column_data($table_name, $column_name, $column_data);
-
- if (isset($prepared_column['auto_increment']) && strlen($column_name) > 26) // "${column_name}_gen"
- {
- trigger_error("Index name '${column_name}_gen' on table '$table_name' is too long. The maximum auto increment column length is 26 characters.", E_USER_ERROR);
- }
-
- // here we add the definition of the new column to the list of columns
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- $columns[] = "\t [{$column_name}] " . $prepared_column['column_type_sql_default'];
- break;
-
- default:
- $columns[] = "\t {$column_name} " . $prepared_column['column_type_sql'];
- break;
- }
-
- // see if we have found a primary key set due to a column definition if we have found it, we can stop looking
- if (!$primary_key_gen)
- {
- $primary_key_gen = isset($prepared_column['primary_key_set']) && $prepared_column['primary_key_set'];
- }
-
- // create textimage DDL based off of the existance of certain column types
- if (!$create_textimage)
- {
- $create_textimage = isset($prepared_column['textimage']) && $prepared_column['textimage'];
- }
-
- // create sequence DDL based off of the existance of auto incrementing columns
- if (!$create_sequence && isset($prepared_column['auto_increment']) && $prepared_column['auto_increment'])
- {
- $create_sequence = $column_name;
- }
- }
-
- // this makes up all the columns in the create table statement
- $table_sql .= implode(",\n", $columns);
-
- // Close the table for two DBMS and add to the statements
- switch ($this->sql_layer)
- {
- case 'firebird':
- $table_sql .= "\n);";
- $statements[] = $table_sql;
- break;
-
- case 'mssql':
- case 'mssqlnative':
- $table_sql .= "\n) ON [PRIMARY]" . (($create_textimage) ? ' TEXTIMAGE_ON [PRIMARY]' : '');
- $statements[] = $table_sql;
- break;
- }
-
- // we have yet to create a primary key for this table,
- // this means that we can add the one we really wanted instead
- if (!$primary_key_gen)
- {
- // Write primary key
- if (isset($table_data['PRIMARY_KEY']))
- {
- if (!is_array($table_data['PRIMARY_KEY']))
- {
- $table_data['PRIMARY_KEY'] = array($table_data['PRIMARY_KEY']);
- }
-
- switch ($this->sql_layer)
- {
- case 'mysql_40':
- case 'mysql_41':
- case 'postgres':
- case 'sqlite':
- $table_sql .= ",\n\t PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')';
- break;
-
- case 'firebird':
- case 'mssql':
- case 'mssqlnative':
- // We need the data here
- $old_return_statements = $this->return_statements;
- $this->return_statements = true;
-
- $primary_key_stmts = $this->sql_create_primary_key($table_name, $table_data['PRIMARY_KEY']);
- foreach ($primary_key_stmts as $pk_stmt)
- {
- $statements[] = $pk_stmt;
- }
-
- $this->return_statements = $old_return_statements;
- break;
-
- case 'oracle':
- $table_sql .= ",\n\t CONSTRAINT pk_{$table_name} PRIMARY KEY (" . implode(', ', $table_data['PRIMARY_KEY']) . ')';
- break;
- }
- }
- }
-
- // close the table
- switch ($this->sql_layer)
- {
- case 'mysql_41':
- // make sure the table is in UTF-8 mode
- $table_sql .= "\n) CHARACTER SET `utf8` COLLATE `utf8_bin`;";
- $statements[] = $table_sql;
- break;
-
- case 'mysql_40':
- case 'sqlite':
- $table_sql .= "\n);";
- $statements[] = $table_sql;
- break;
-
- case 'postgres':
- // do we need to add a sequence for auto incrementing columns?
- if ($create_sequence)
- {
- $statements[] = "CREATE SEQUENCE {$table_name}_seq;";
- }
-
- $table_sql .= "\n);";
- $statements[] = $table_sql;
- break;
-
- case 'oracle':
- $table_sql .= "\n)";
- $statements[] = $table_sql;
-
- // do we need to add a sequence and a tigger for auto incrementing columns?
- if ($create_sequence)
- {
- // create the actual sequence
- $statements[] = "CREATE SEQUENCE {$table_name}_seq";
-
- // the trigger is the mechanism by which we increment the counter
- $trigger = "CREATE OR REPLACE TRIGGER t_{$table_name}\n";
- $trigger .= "BEFORE INSERT ON {$table_name}\n";
- $trigger .= "FOR EACH ROW WHEN (\n";
- $trigger .= "\tnew.{$create_sequence} IS NULL OR new.{$create_sequence} = 0\n";
- $trigger .= ")\n";
- $trigger .= "BEGIN\n";
- $trigger .= "\tSELECT {$table_name}_seq.nextval\n";
- $trigger .= "\tINTO :new.{$create_sequence}\n";
- $trigger .= "\tFROM dual;\n";
- $trigger .= "END;";
-
- $statements[] = $trigger;
- }
- break;
-
- case 'firebird':
- if ($create_sequence)
- {
- $statements[] = "CREATE GENERATOR {$table_name}_gen;";
- $statements[] = "SET GENERATOR {$table_name}_gen TO 0;";
-
- $trigger = "CREATE TRIGGER t_$table_name FOR $table_name\n";
- $trigger .= "BEFORE INSERT\nAS\nBEGIN\n";
- $trigger .= "\tNEW.{$create_sequence} = GEN_ID({$table_name}_gen, 1);\nEND;";
- $statements[] = $trigger;
- }
- break;
- }
-
- // Write Keys
- if (isset($table_data['KEYS']))
- {
- foreach ($table_data['KEYS'] as $key_name => $key_data)
- {
- if (!is_array($key_data[1]))
- {
- $key_data[1] = array($key_data[1]);
- }
-
- $old_return_statements = $this->return_statements;
- $this->return_statements = true;
-
- $key_stmts = ($key_data[0] == 'UNIQUE') ? $this->sql_create_unique_index($table_name, $key_name, $key_data[1]) : $this->sql_create_index($table_name, $key_name, $key_data[1]);
-
- foreach ($key_stmts as $key_stmt)
- {
- $statements[] = $key_stmt;
- }
-
- $this->return_statements = $old_return_statements;
- }
- }
-
- // Commit Transaction
- $statements[] = 'commit';
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Handle passed database update array.
- * Expected structure...
- * Key being one of the following
- * change_columns: Column changes (only type, not name)
- * add_columns: Add columns to a table
- * drop_keys: Dropping keys
- * drop_columns: Removing/Dropping columns
- * add_primary_keys: adding primary keys
- * add_unique_index: adding an unique index
- * add_index: adding an index (can be column:index_size if you need to provide size)
- *
- * The values are in this format:
- * {TABLE NAME} => array(
- * {COLUMN NAME} => array({COLUMN TYPE}, {DEFAULT VALUE}, {OPTIONAL VARIABLES}),
- * {KEY/INDEX NAME} => array({COLUMN NAMES}),
- * )
- *
- * For more information have a look at /develop/create_schema_files.php (only available through SVN)
- */
- function perform_schema_changes($schema_changes)
- {
- if (empty($schema_changes))
- {
- return;
- }
-
- $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;
- }
-
- // Drop tables?
- if (!empty($schema_changes['drop_tables']))
- {
- foreach ($schema_changes['drop_tables'] as $table)
- {
- // only drop table if it exists
- if ($this->sql_table_exists($table))
- {
- $result = $this->sql_table_drop($table);
- if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
-
- // Add tables?
- if (!empty($schema_changes['add_tables']))
- {
- foreach ($schema_changes['add_tables'] as $table => $table_data)
- {
- $result = $this->sql_create_table($table, $table_data);
- if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
-
- // Change columns?
- if (!empty($schema_changes['change_columns']))
- {
- foreach ($schema_changes['change_columns'] as $table => $columns)
- {
- foreach ($columns as $column_name => $column_data)
- {
- // If the column exists we change it, else we add it ;)
- if ($column_exists = $this->sql_column_exists($table, $column_name))
- {
- $result = $this->sql_column_change($table, $column_name, $column_data, true);
- }
- else
- {
- $result = $this->sql_column_add($table, $column_name, $column_data, true);
- }
-
- 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);
- }
- }
- }
- }
-
- // Add columns?
- if (!empty($schema_changes['add_columns']))
- {
- foreach ($schema_changes['add_columns'] as $table => $columns)
- {
- foreach ($columns as $column_name => $column_data)
- {
- // Only add the column if it does not exist yet
- if ($column_exists = $this->sql_column_exists($table, $column_name))
- {
- 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, true);
- }
-
- if ($sqlite)
- {
- if ($column_exists)
- {
- continue;
-// $sqlite_data[$table]['change_columns'][] = $result;
- }
- else
- {
- $sqlite_data[$table]['add_columns'][] = $result;
- }
- }
- else if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
-
- // Remove keys?
- if (!empty($schema_changes['drop_keys']))
- {
- foreach ($schema_changes['drop_keys'] as $table => $indexes)
- {
- foreach ($indexes as $index_name)
- {
- if (!$this->sql_index_exists($table, $index_name))
- {
- continue;
- }
-
- $result = $this->sql_index_drop($table, $index_name);
-
- if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
-
- // Drop columns?
- if (!empty($schema_changes['drop_columns']))
- {
- foreach ($schema_changes['drop_columns'] as $table => $columns)
- {
- foreach ($columns as $column)
- {
- // Only remove the column if it exists...
- if ($this->sql_column_exists($table, $column))
- {
- $result = $this->sql_column_remove($table, $column, true);
-
- if ($sqlite)
- {
- $sqlite_data[$table]['drop_columns'][] = $result;
- }
- else if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
- }
-
- // Add primary keys?
- if (!empty($schema_changes['add_primary_keys']))
- {
- foreach ($schema_changes['add_primary_keys'] as $table => $columns)
- {
- $result = $this->sql_create_primary_key($table, $columns, true);
-
- if ($sqlite)
- {
- $sqlite_data[$table]['primary_key'] = $result;
- }
- else if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
-
- // Add unqiue indexes?
- if (!empty($schema_changes['add_unique_index']))
- {
- foreach ($schema_changes['add_unique_index'] as $table => $index_array)
- {
- foreach ($index_array as $index_name => $column)
- {
- if ($this->sql_unique_index_exists($table, $index_name))
- {
- continue;
- }
-
- $result = $this->sql_create_unique_index($table, $index_name, $column);
-
- if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
-
- // Add indexes?
- if (!empty($schema_changes['add_index']))
- {
- foreach ($schema_changes['add_index'] as $table => $index_array)
- {
- foreach ($index_array as $index_name => $column)
- {
- if ($this->sql_index_exists($table, $index_name))
- {
- continue;
- }
-
- $result = $this->sql_create_index($table, $index_name, $column);
-
- if ($this->return_statements)
- {
- $statements = array_merge($statements, $result);
- }
- }
- }
- }
-
- 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;
- }
- }
-
- /**
- * Gets a list of columns of a table.
- *
- * @param string $table Table name
- *
- * @return array Array of column names (all lower case)
- */
- function sql_list_columns($table)
- {
- $columns = array();
-
- switch ($this->sql_layer)
- {
- case 'mysql_40':
- case 'mysql_41':
- $sql = "SHOW COLUMNS FROM $table";
- break;
-
- // PostgreSQL has a way of doing this in a much simpler way but would
- // not allow us to support all versions of PostgreSQL
- case 'postgres':
- $sql = "SELECT a.attname
- FROM pg_class c, pg_attribute a
- WHERE c.relname = '{$table}'
- AND a.attnum > 0
- AND a.attrelid = c.oid";
- break;
-
- // same deal with PostgreSQL, we must perform more complex operations than
- // we technically could
- case 'mssql':
- case 'mssqlnative':
- $sql = "SELECT c.name
- FROM syscolumns c
- LEFT JOIN sysobjects o ON c.id = o.id
- WHERE o.name = '{$table}'";
- break;
-
- case 'oracle':
- $sql = "SELECT column_name
- FROM user_tab_columns
- WHERE LOWER(table_name) = '" . strtolower($table) . "'";
- break;
-
- case 'firebird':
- $sql = "SELECT RDB\$FIELD_NAME as FNAME
- FROM RDB\$RELATION_FIELDS
- WHERE RDB\$RELATION_NAME = '" . strtoupper($table) . "'";
- break;
-
- case 'sqlite':
- $sql = "SELECT sql
- FROM sqlite_master
- WHERE type = 'table'
- AND name = '{$table}'";
-
- $result = $this->db->sql_query($sql);
-
- if (!$result)
- {
- return false;
- }
-
- $row = $this->db->sql_fetchrow($result);
- $this->db->sql_freeresult($result);
-
- preg_match('#\((.*)\)#s', $row['sql'], $matches);
-
- $cols = trim($matches[1]);
- $col_array = preg_split('/,(?![\s\w]+\))/m', $cols);
-
- foreach ($col_array as $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- if ($entities[0] == 'PRIMARY')
- {
- continue;
- }
-
- $column = strtolower($entities[0]);
- $columns[$column] = $column;
- }
-
- return $columns;
- break;
- }
-
- $result = $this->db->sql_query($sql);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $column = strtolower(current($row));
- $columns[$column] = $column;
- }
- $this->db->sql_freeresult($result);
-
- return $columns;
- }
-
- /**
- * Check whether a specified column exist in a table
- *
- * @param string $table Table to check
- * @param string $column_name Column to check
- *
- * @return bool True if column exists, false otherwise
- */
- function sql_column_exists($table, $column_name)
- {
- $columns = $this->sql_list_columns($table);
-
- return isset($columns[$column_name]);
- }
-
- /**
- * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes.
- *
- * @param string $table_name Table to check the index at
- * @param string $index_name The index name to check
- *
- * @return bool True if index exists, else false
- */
- function sql_index_exists($table_name, $index_name)
- {
- if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative')
- {
- $sql = "EXEC sp_statistics '$table_name'";
- $result = $this->db->sql_query($sql);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- if ($row['TYPE'] == 3)
- {
- if (strtolower($row['INDEX_NAME']) == strtolower($index_name))
- {
- $this->db->sql_freeresult($result);
- return true;
- }
- }
- }
- $this->db->sql_freeresult($result);
-
- return false;
- }
-
- switch ($this->sql_layer)
- {
- case 'firebird':
- $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name
- FROM RDB\$INDICES
- WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "'
- AND RDB\$UNIQUE_FLAG IS NULL
- AND RDB\$FOREIGN_KEY IS NULL";
- $col = 'index_name';
- break;
-
- case 'postgres':
- $sql = "SELECT ic.relname as index_name
- FROM pg_class bc, pg_class ic, pg_index i
- WHERE (bc.oid = i.indrelid)
- AND (ic.oid = i.indexrelid)
- AND (bc.relname = '" . $table_name . "')
- AND (i.indisunique != 't')
- AND (i.indisprimary != 't')";
- $col = 'index_name';
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $sql = 'SHOW KEYS
- FROM ' . $table_name;
- $col = 'Key_name';
- break;
-
- case 'oracle':
- $sql = "SELECT index_name
- FROM user_indexes
- WHERE table_name = '" . strtoupper($table_name) . "'
- AND generated = 'N'
- AND uniqueness = 'NONUNIQUE'";
- $col = 'index_name';
- break;
-
- case 'sqlite':
- $sql = "PRAGMA index_list('" . $table_name . "');";
- $col = 'name';
- break;
- }
-
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique'])
- {
- continue;
- }
-
- // These DBMS prefix index name with the table name
- switch ($this->sql_layer)
- {
- case 'firebird':
- case 'oracle':
- case 'postgres':
- case 'sqlite':
- $row[$col] = substr($row[$col], strlen($table_name) + 1);
- break;
- }
-
- if (strtolower($row[$col]) == strtolower($index_name))
- {
- $this->db->sql_freeresult($result);
- return true;
- }
- }
- $this->db->sql_freeresult($result);
-
- return false;
- }
-
- /**
- * Check if a specified index exists in table. Does not return PRIMARY KEY and UNIQUE indexes.
- *
- * @param string $table_name Table to check the index at
- * @param string $index_name The index name to check
- *
- * @return bool True if index exists, else false
- */
- function sql_unique_index_exists($table_name, $index_name)
- {
- if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative')
- {
- $sql = "EXEC sp_statistics '$table_name'";
- $result = $this->db->sql_query($sql);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- // Usually NON_UNIQUE is the column we want to check, but we allow for both
- if ($row['TYPE'] == 3)
- {
- if (strtolower($row['INDEX_NAME']) == strtolower($index_name))
- {
- $this->db->sql_freeresult($result);
- return true;
- }
- }
- }
- $this->db->sql_freeresult($result);
- return false;
- }
-
- switch ($this->sql_layer)
- {
- case 'firebird':
- $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name
- FROM RDB\$INDICES
- WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "'
- AND RDB\$UNIQUE_FLAG IS NOT NULL
- AND RDB\$FOREIGN_KEY IS NULL";
- $col = 'index_name';
- break;
-
- case 'postgres':
- $sql = "SELECT ic.relname as index_name, i.indisunique
- FROM pg_class bc, pg_class ic, pg_index i
- WHERE (bc.oid = i.indrelid)
- AND (ic.oid = i.indexrelid)
- AND (bc.relname = '" . $table_name . "')
- AND (i.indisprimary != 't')";
- $col = 'index_name';
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $sql = 'SHOW KEYS
- FROM ' . $table_name;
- $col = 'Key_name';
- break;
-
- case 'oracle':
- $sql = "SELECT index_name, table_owner
- FROM user_indexes
- WHERE table_name = '" . strtoupper($table_name) . "'
- AND generated = 'N'
- AND uniqueness = 'UNIQUE'";
- $col = 'index_name';
- break;
-
- case 'sqlite':
- $sql = "PRAGMA index_list('" . $table_name . "');";
- $col = 'name';
- break;
- }
-
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && ($row['Non_unique'] || $row[$col] == 'PRIMARY'))
- {
- continue;
- }
-
- if ($this->sql_layer == 'sqlite' && !$row['unique'])
- {
- continue;
- }
-
- if ($this->sql_layer == 'postgres' && $row['indisunique'] != 't')
- {
- continue;
- }
-
- // These DBMS prefix index name with the table name
- switch ($this->sql_layer)
- {
- case 'oracle':
- // Two cases here... prefixed with U_[table_owner] and not prefixed with table_name
- if (strpos($row[$col], 'U_') === 0)
- {
- $row[$col] = substr($row[$col], strlen('U_' . $row['table_owner']) + 1);
- }
- else if (strpos($row[$col], strtoupper($table_name)) === 0)
- {
- $row[$col] = substr($row[$col], strlen($table_name) + 1);
- }
- break;
-
- case 'firebird':
- case 'postgres':
- case 'sqlite':
- $row[$col] = substr($row[$col], strlen($table_name) + 1);
- break;
- }
-
- if (strtolower($row[$col]) == strtolower($index_name))
- {
- $this->db->sql_freeresult($result);
- return true;
- }
- }
- $this->db->sql_freeresult($result);
-
- return false;
- }
-
- /**
- * Private method for performing sql statements (either execute them or return them)
- * @access private
- */
- function _sql_run_sql($statements)
- {
- if ($this->return_statements)
- {
- return $statements;
- }
-
- // We could add error handling here...
- foreach ($statements as $sql)
- {
- if ($sql === 'begin')
- {
- $this->db->sql_transaction('begin');
- }
- else if ($sql === 'commit')
- {
- $this->db->sql_transaction('commit');
- }
- else
- {
- $this->db->sql_query($sql);
- }
- }
-
- return true;
- }
-
- /**
- * Function to prepare some column information for better usage
- * @access private
- */
- function sql_prepare_column_data($table_name, $column_name, $column_data)
- {
- if (strlen($column_name) > 30)
- {
- trigger_error("Column name '$column_name' on table '$table_name' is too long. The maximum is 30 characters.", E_USER_ERROR);
- }
-
- // Get type
- if (strpos($column_data[0], ':') !== false)
- {
- list($orig_column_type, $column_length) = explode(':', $column_data[0]);
- if (!is_array($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']))
- {
- $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'], $column_length);
- }
- else
- {
- if (isset($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule']))
- {
- switch ($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'][0])
- {
- case 'div':
- $column_length /= $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['rule'][1];
- $column_length = ceil($column_length);
- $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'][0], $column_length);
- break;
- }
- }
-
- if (isset($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit']))
- {
- switch ($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][0])
- {
- case 'mult':
- $column_length *= $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][1];
- if ($column_length > $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][2])
- {
- $column_type = $this->dbms_type_map[$this->sql_layer][$orig_column_type . ':']['limit'][3];
- }
- else
- {
- $column_type = sprintf($this->dbms_type_map[$this->sql_layer][$orig_column_type . ':'][0], $column_length);
- }
- break;
- }
- }
- }
- $orig_column_type .= ':';
- }
- else
- {
- $orig_column_type = $column_data[0];
- $column_type = $this->dbms_type_map[$this->sql_layer][$column_data[0]];
- }
-
- // Adjust default value if db-dependent specified
- if (is_array($column_data[1]))
- {
- $column_data[1] = (isset($column_data[1][$this->sql_layer])) ? $column_data[1][$this->sql_layer] : $column_data[1]['default'];
- }
-
- $sql = '';
-
- $return_array = array();
-
- switch ($this->sql_layer)
- {
- 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';
-
- // This is a UNICODE column and thus should be given it's fair share
- if (preg_match('/^X?STEXT_UNI|VCHAR_(CI|UNI:?)/', $column_data[0]))
- {
- $sql .= ' COLLATE UNICODE';
- }
-
- $return_array['auto_increment'] = false;
- if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
- {
- $return_array['auto_increment'] = true;
- }
-
- break;
-
- case 'mssql':
- case 'mssqlnative':
- $sql .= " {$column_type} ";
- $sql_default = " {$column_type} ";
-
- // For adding columns we need the default definition
- if (!is_null($column_data[1]))
- {
- // For hexadecimal values do not use single quotes
- if (strpos($column_data[1], '0x') === 0)
- {
- $return_array['default'] = 'DEFAULT (' . $column_data[1] . ') ';
- $sql_default .= $return_array['default'];
- }
- else
- {
- $return_array['default'] = 'DEFAULT (' . ((is_numeric($column_data[1])) ? $column_data[1] : "'{$column_data[1]}'") . ') ';
- $sql_default .= $return_array['default'];
- }
- }
-
- if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
- {
-// $sql .= 'IDENTITY (1, 1) ';
- $sql_default .= 'IDENTITY (1, 1) ';
- }
-
- $return_array['textimage'] = $column_type === '[text]';
-
- $sql .= 'NOT NULL';
- $sql_default .= 'NOT NULL';
-
- $return_array['column_type_sql_default'] = $sql_default;
-
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $sql .= " {$column_type} ";
-
- // For hexadecimal values do not use single quotes
- if (!is_null($column_data[1]) && substr($column_type, -4) !== 'text' && substr($column_type, -4) !== 'blob')
- {
- $sql .= (strpos($column_data[1], '0x') === 0) ? "DEFAULT {$column_data[1]} " : "DEFAULT '{$column_data[1]}' ";
- }
- $sql .= 'NOT NULL';
-
- if (isset($column_data[2]))
- {
- if ($column_data[2] == 'auto_increment')
- {
- $sql .= ' auto_increment';
- }
- else if ($this->sql_layer === 'mysql_41' && $column_data[2] == 'true_sort')
- {
- $sql .= ' COLLATE utf8_unicode_ci';
- }
- }
-
- break;
-
- case 'oracle':
- $sql .= " {$column_type} ";
- $sql .= (!is_null($column_data[1])) ? "DEFAULT '{$column_data[1]}' " : '';
-
- // In Oracle empty strings ('') are treated as NULL.
- // Therefore in oracle we allow NULL's for all DEFAULT '' entries
- // Oracle does not like setting NOT NULL on a column that is already NOT NULL (this happens only on number fields)
- if (!preg_match('/number/i', $column_type))
- {
- $sql .= ($column_data[1] === '') ? '' : 'NOT NULL';
- }
-
- $return_array['auto_increment'] = false;
- if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
- {
- $return_array['auto_increment'] = true;
- }
-
- break;
-
- case 'postgres':
- $return_array['column_type'] = $column_type;
-
- $sql .= " {$column_type} ";
-
- $return_array['auto_increment'] = false;
- if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
- {
- $default_val = "nextval('{$table_name}_seq')";
- $return_array['auto_increment'] = true;
- }
- else if (!is_null($column_data[1]))
- {
- $default_val = "'" . $column_data[1] . "'";
- $return_array['null'] = 'NOT NULL';
- $sql .= 'NOT NULL ';
- }
-
- $return_array['default'] = $default_val;
-
- $sql .= "DEFAULT {$default_val}";
-
- // Unsigned? Then add a CHECK contraint
- if (in_array($orig_column_type, $this->unsigned_types))
- {
- $return_array['constraint'] = "CHECK ({$column_name} >= 0)";
- $sql .= " CHECK ({$column_name} >= 0)";
- }
-
- break;
-
- case 'sqlite':
- $return_array['primary_key_set'] = false;
- if (isset($column_data[2]) && $column_data[2] == 'auto_increment')
- {
- $sql .= ' INTEGER PRIMARY KEY';
- $return_array['primary_key_set'] = true;
- }
- else
- {
- $sql .= ' ' . $column_type;
- }
-
- $sql .= ' NOT NULL ';
- $sql .= (!is_null($column_data[1])) ? "DEFAULT '{$column_data[1]}'" : '';
-
- break;
- }
-
- $return_array['column_type_sql'] = $sql;
-
- return $return_array;
- }
-
- /**
- * Add new column
- */
- 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();
-
- 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':
- case 'mssqlnative':
- // 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':
- $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
- if (version_compare($this->db->sql_server_info(true), '8.0', '>='))
- {
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type_sql'];
- }
- else
- {
- // old versions cannot add columns with default and null information
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD COLUMN "' . $column_name . '" ' . $column_data['column_type'] . ' ' . $column_data['constraint'];
-
- if (isset($column_data['null']))
- {
- if ($column_data['null'] == 'NOT NULL')
- {
- $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET NOT NULL';
- }
- }
-
- if (isset($column_data['default']))
- {
- $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default'];
- }
- }
-
- break;
-
- case 'sqlite':
-
- if ($inline && $this->return_statements)
- {
- return $column_name . ' ' . $column_data['column_type_sql'];
- }
-
- if (version_compare(sqlite_libversion(), '3.0') == -1)
- {
- $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)
- {
- break;
- }
-
- $row = $this->db->sql_fetchrow($result);
- $this->db->sql_freeresult($result);
-
- $statements[] = 'begin';
-
- // 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;
-
- preg_match('#\((.*)\)#s', $row['sql'], $matches);
-
- $new_table_cols = trim($matches[1]);
- $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
- $column_list = array();
-
- foreach ($old_table_cols as $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- if ($entities[0] == 'PRIMARY')
- {
- continue;
- }
- $column_list[] = $entities[0];
- }
-
- $columns = implode(',', $column_list);
-
- $new_table_cols = $column_name . ' ' . $column_data['column_type_sql'] . ',' . $new_table_cols;
-
- // create a new table and fill it up. destroy the temp one
- $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ');';
- $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
- $statements[] = 'DROP TABLE ' . $table_name . '_temp';
-
- $statements[] = 'commit';
- }
- else
- {
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD ' . $column_name . ' [' . $column_data['column_type_sql'] . ']';
- }
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Drop column
- */
- function sql_column_remove($table_name, $column_name, $inline = false)
- {
- $statements = array();
-
- switch ($this->sql_layer)
- {
- case 'firebird':
- $statements[] = 'ALTER TABLE ' . $table_name . ' DROP "' . strtoupper($column_name) . '"';
- break;
-
- case 'mssql':
- case 'mssqlnative':
- $statements[] = 'ALTER TABLE [' . $table_name . '] DROP COLUMN [' . $column_name . ']';
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $statements[] = 'ALTER TABLE `' . $table_name . '` DROP COLUMN `' . $column_name . '`';
- break;
-
- case 'oracle':
- $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN ' . $column_name;
- break;
-
- case 'postgres':
- $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN "' . $column_name . '"';
- break;
-
- case 'sqlite':
-
- if ($inline && $this->return_statements)
- {
- return $column_name;
- }
-
- if (version_compare(sqlite_libversion(), '3.0') == -1)
- {
- $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)
- {
- break;
- }
-
- $row = $this->db->sql_fetchrow($result);
- $this->db->sql_freeresult($result);
-
- $statements[] = 'begin';
-
- // 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;
-
- preg_match('#\((.*)\)#s', $row['sql'], $matches);
-
- $new_table_cols = trim($matches[1]);
- $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
- $column_list = array();
-
- foreach ($old_table_cols as $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- if ($entities[0] == 'PRIMARY' || $entities[0] === $column_name)
- {
- continue;
- }
- $column_list[] = $entities[0];
- }
-
- $columns = implode(',', $column_list);
-
- $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 . ');';
- $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
- $statements[] = 'DROP TABLE ' . $table_name . '_temp';
-
- $statements[] = 'commit';
- }
- else
- {
- $statements[] = 'ALTER TABLE ' . $table_name . ' DROP COLUMN ' . $column_name;
- }
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Drop Index
- */
- function sql_index_drop($table_name, $index_name)
- {
- $statements = array();
-
- switch ($this->sql_layer)
- {
- case 'mssql':
- case 'mssqlnative':
- $statements[] = 'DROP INDEX ' . $table_name . '.' . $index_name;
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $statements[] = 'DROP INDEX ' . $index_name . ' ON ' . $table_name;
- break;
-
- case 'firebird':
- case 'oracle':
- case 'postgres':
- case 'sqlite':
- $statements[] = 'DROP INDEX ' . $table_name . '_' . $index_name;
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Drop Table
- */
- function sql_table_drop($table_name)
- {
- $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;
-
- switch ($this->sql_layer)
- {
- case 'firebird':
- $sql = 'SELECT RDB$GENERATOR_NAME as gen
- FROM RDB$GENERATORS
- WHERE RDB$SYSTEM_FLAG = 0
- AND RDB$GENERATOR_NAME = \'' . strtoupper($table_name) . "_GEN'";
- $result = $this->db->sql_query($sql);
-
- // does a generator exist?
- if ($row = $this->db->sql_fetchrow($result))
- {
- $statements[] = "DROP GENERATOR {$row['gen']};";
- }
- $this->db->sql_freeresult($result);
- break;
-
- case 'oracle':
- $sql = 'SELECT A.REFERENCED_NAME
- FROM USER_DEPENDENCIES A, USER_TRIGGERS B
- WHERE A.REFERENCED_TYPE = \'SEQUENCE\'
- AND A.NAME = B.TRIGGER_NAME
- AND B.TABLE_NAME = \'' . strtoupper($table_name) . "'";
- $result = $this->db->sql_query($sql);
-
- // any sequences ref'd to this table's triggers?
- while ($row = $this->db->sql_fetchrow($result))
- {
- $statements[] = "DROP SEQUENCE {$row['referenced_name']}";
- }
- $this->db->sql_freeresult($result);
- break;
-
- case 'postgres':
- // PGSQL does not "tightly" bind sequences and tables, we must guess...
- $sql = "SELECT relname
- FROM pg_class
- WHERE relkind = 'S'
- AND relname = '{$table_name}_seq'";
- $result = $this->db->sql_query($sql);
-
- // We don't even care about storing the results. We already know the answer if we get rows back.
- if ($this->db->sql_fetchrow($result))
- {
- $statements[] = "DROP SEQUENCE {$table_name}_seq;\n";
- }
- $this->db->sql_freeresult($result);
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Add primary key
- */
- function sql_create_primary_key($table_name, $column, $inline = false)
- {
- $statements = array();
-
- switch ($this->sql_layer)
- {
- case 'firebird':
- case 'postgres':
- case 'mysql_40':
- case 'mysql_41':
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD PRIMARY KEY (' . implode(', ', $column) . ')';
- break;
-
- case 'mssql':
- case 'mssqlnative':
- $sql = "ALTER TABLE [{$table_name}] WITH NOCHECK ADD ";
- $sql .= "CONSTRAINT [PK_{$table_name}] PRIMARY KEY CLUSTERED (";
- $sql .= '[' . implode("],\n\t\t[", $column) . ']';
- $sql .= ') ON [PRIMARY]';
-
- $statements[] = $sql;
- break;
-
- case 'oracle':
- $statements[] = 'ALTER TABLE ' . $table_name . 'add CONSTRAINT pk_' . $table_name . ' PRIMARY KEY (' . implode(', ', $column) . ')';
- break;
-
- case 'sqlite':
-
- if ($inline && $this->return_statements)
- {
- return $column;
- }
-
- $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)
- {
- break;
- }
-
- $row = $this->db->sql_fetchrow($result);
- $this->db->sql_freeresult($result);
-
- $statements[] = 'begin';
-
- // 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;
-
- preg_match('#\((.*)\)#s', $row['sql'], $matches);
-
- $new_table_cols = trim($matches[1]);
- $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
- $column_list = array();
-
- foreach ($old_table_cols as $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- if ($entities[0] == 'PRIMARY')
- {
- continue;
- }
- $column_list[] = $entities[0];
- }
-
- $columns = implode(',', $column_list);
-
- // create a new table and fill it up. destroy the temp one
- $statements[] = 'CREATE TABLE ' . $table_name . ' (' . $new_table_cols . ', PRIMARY KEY (' . implode(', ', $column) . '));';
- $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
- $statements[] = 'DROP TABLE ' . $table_name . '_temp';
-
- $statements[] = 'commit';
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Add unique index
- */
- function sql_create_unique_index($table_name, $index_name, $column)
- {
- $statements = array();
-
- $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config)
- if (strlen($table_name . $index_name) - strlen($table_prefix) > 24)
- {
- $max_length = strlen($table_prefix) + 24;
- trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR);
- }
-
- switch ($this->sql_layer)
- {
- case 'firebird':
- case 'postgres':
- case 'oracle':
- case 'sqlite':
- $statements[] = 'CREATE UNIQUE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD UNIQUE INDEX ' . $index_name . '(' . implode(', ', $column) . ')';
- break;
-
- case 'mssql':
- case 'mssqlnative':
- $statements[] = 'CREATE UNIQUE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ') ON [PRIMARY]';
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * Add index
- */
- function sql_create_index($table_name, $index_name, $column)
- {
- $statements = array();
-
- $table_prefix = substr(CONFIG_TABLE, 0, -6); // strlen(config)
- if (strlen($table_name . $index_name) - strlen($table_prefix) > 24)
- {
- $max_length = strlen($table_prefix) + 24;
- trigger_error("Index name '{$table_name}_$index_name' on table '$table_name' is too long. The maximum is $max_length characters.", E_USER_ERROR);
- }
-
- // remove index length unless MySQL4
- if ('mysql_40' != $this->sql_layer)
- {
- $column = preg_replace('#:.*$#', '', $column);
- }
-
- switch ($this->sql_layer)
- {
- case 'firebird':
- case 'postgres':
- case 'oracle':
- case 'sqlite':
- $statements[] = 'CREATE INDEX ' . $table_name . '_' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ')';
- break;
-
- case 'mysql_40':
- // add index size to definition as required by MySQL4
- foreach ($column as $i => $col)
- {
- if (false !== strpos($col, ':'))
- {
- list($col, $index_size) = explode(':', $col);
- $column[$i] = "$col($index_size)";
- }
- }
- // no break
- case 'mysql_41':
- $statements[] = 'ALTER TABLE ' . $table_name . ' ADD INDEX ' . $index_name . '(' . implode(', ', $column) . ')';
- break;
-
- case 'mssql':
- case 'mssqlnative':
- $statements[] = 'CREATE INDEX ' . $index_name . ' ON ' . $table_name . '(' . implode(', ', $column) . ') ON [PRIMARY]';
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-
- /**
- * List all of the indices that belong to a table,
- * does not count:
- * * UNIQUE indices
- * * PRIMARY keys
- */
- function sql_list_index($table_name)
- {
- $index_array = array();
-
- if ($this->sql_layer == 'mssql' || $this->sql_layer == 'mssqlnative')
- {
- $sql = "EXEC sp_statistics '$table_name'";
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- if ($row['TYPE'] == 3)
- {
- $index_array[] = $row['INDEX_NAME'];
- }
- }
- $this->db->sql_freeresult($result);
- }
- else
- {
- switch ($this->sql_layer)
- {
- case 'firebird':
- $sql = "SELECT LOWER(RDB\$INDEX_NAME) as index_name
- FROM RDB\$INDICES
- WHERE RDB\$RELATION_NAME = '" . strtoupper($table_name) . "'
- AND RDB\$UNIQUE_FLAG IS NULL
- AND RDB\$FOREIGN_KEY IS NULL";
- $col = 'index_name';
- break;
-
- case 'postgres':
- $sql = "SELECT ic.relname as index_name
- FROM pg_class bc, pg_class ic, pg_index i
- WHERE (bc.oid = i.indrelid)
- AND (ic.oid = i.indexrelid)
- AND (bc.relname = '" . $table_name . "')
- AND (i.indisunique != 't')
- AND (i.indisprimary != 't')";
- $col = 'index_name';
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $sql = 'SHOW KEYS
- FROM ' . $table_name;
- $col = 'Key_name';
- break;
-
- case 'oracle':
- $sql = "SELECT index_name
- FROM user_indexes
- WHERE table_name = '" . strtoupper($table_name) . "'
- AND generated = 'N'
- AND uniqueness = 'NONUNIQUE'";
- $col = 'index_name';
- break;
-
- case 'sqlite':
- $sql = "PRAGMA index_info('" . $table_name . "');";
- $col = 'name';
- break;
- }
-
- $result = $this->db->sql_query($sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- if (($this->sql_layer == 'mysql_40' || $this->sql_layer == 'mysql_41') && !$row['Non_unique'])
- {
- continue;
- }
-
- switch ($this->sql_layer)
- {
- case 'firebird':
- case 'oracle':
- case 'postgres':
- case 'sqlite':
- $row[$col] = substr($row[$col], strlen($table_name) + 1);
- break;
- }
-
- $index_array[] = $row[$col];
- }
- $this->db->sql_freeresult($result);
- }
-
- return array_map('strtolower', $index_array);
- }
-
- /**
- * Change column type (not name!)
- */
- 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();
-
- switch ($this->sql_layer)
- {
- case 'firebird':
- // Change type...
- 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
- {
- // TODO: try to change pkey without removing trigger, generator or constraints. ATM this query may fail.
- $statements[] = 'ALTER TABLE ' . $table_name . ' ALTER COLUMN "' . strtoupper($column_name) . '" TYPE ' . ' ' . $column_data['column_type_sql_type'];
- }
- break;
-
- case 'mssql':
- case 'mssqlnative':
- $statements[] = 'ALTER TABLE [' . $table_name . '] ALTER COLUMN [' . $column_name . '] ' . $column_data['column_type_sql'];
-
- if (!empty($column_data['default']))
- {
- // Using TRANSACT-SQL for this statement because we do not want to have colliding data if statements are executed at a later stage
- $statements[] = "DECLARE @drop_default_name VARCHAR(100), @cmd VARCHAR(1000)
- SET @drop_default_name =
- (SELECT so.name FROM sysobjects so
- JOIN sysconstraints sc ON so.id = sc.constid
- WHERE object_name(so.parent_obj) = '{$table_name}'
- AND so.xtype = 'D'
- AND sc.colid = (SELECT colid FROM syscolumns
- WHERE id = object_id('{$table_name}')
- AND name = '{$column_name}'))
- IF @drop_default_name <> ''
- BEGIN
- SET @cmd = 'ALTER TABLE [{$table_name}] DROP CONSTRAINT [' + @drop_default_name + ']'
- EXEC(@cmd)
- END
- SET @cmd = 'ALTER TABLE [{$table_name}] ADD CONSTRAINT [DF_{$table_name}_{$column_name}_1] {$column_data['default']} FOR [{$column_name}]'
- EXEC(@cmd)";
- }
- break;
-
- case 'mysql_40':
- case 'mysql_41':
- $statements[] = 'ALTER TABLE `' . $table_name . '` CHANGE `' . $column_name . '` `' . $column_name . '` ' . $column_data['column_type_sql'];
- break;
-
- case 'oracle':
- $statements[] = 'ALTER TABLE ' . $table_name . ' MODIFY ' . $column_name . ' ' . $column_data['column_type_sql'];
- break;
-
- case 'postgres':
- $sql = 'ALTER TABLE ' . $table_name . ' ';
-
- $sql_array = array();
- $sql_array[] = 'ALTER COLUMN ' . $column_name . ' TYPE ' . $column_data['column_type'];
-
- if (isset($column_data['null']))
- {
- if ($column_data['null'] == 'NOT NULL')
- {
- $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET NOT NULL';
- }
- else if ($column_data['null'] == 'NULL')
- {
- $sql_array[] = 'ALTER COLUMN ' . $column_name . ' DROP NOT NULL';
- }
- }
-
- if (isset($column_data['default']))
- {
- $sql_array[] = 'ALTER COLUMN ' . $column_name . ' SET DEFAULT ' . $column_data['default'];
- }
-
- // we don't want to double up on constraints if we change different number data types
- if (isset($column_data['constraint']))
- {
- $constraint_sql = "SELECT consrc as constraint_data
- FROM pg_constraint, pg_class bc
- WHERE conrelid = bc.oid
- AND bc.relname = '{$table_name}'
- AND NOT EXISTS (
- SELECT *
- FROM pg_constraint as c, pg_inherits as i
- WHERE i.inhrelid = pg_constraint.conrelid
- AND c.conname = pg_constraint.conname
- AND c.consrc = pg_constraint.consrc
- AND c.conrelid = i.inhparent
- )";
-
- $constraint_exists = false;
-
- $result = $this->db->sql_query($constraint_sql);
- while ($row = $this->db->sql_fetchrow($result))
- {
- if (trim($row['constraint_data']) == trim($column_data['constraint']))
- {
- $constraint_exists = true;
- break;
- }
- }
- $this->db->sql_freeresult($result);
-
- if (!$constraint_exists)
- {
- $sql_array[] = 'ADD ' . $column_data['constraint'];
- }
- }
-
- $sql .= implode(', ', $sql_array);
-
- $statements[] = $sql;
- break;
-
- case 'sqlite':
-
- if ($inline && $this->return_statements)
- {
- return $column_name . ' ' . $column_data['column_type_sql'];
- }
-
- $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)
- {
- break;
- }
-
- $row = $this->db->sql_fetchrow($result);
- $this->db->sql_freeresult($result);
-
- $statements[] = 'begin';
-
- // Create a temp 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;
-
- preg_match('#\((.*)\)#s', $row['sql'], $matches);
-
- $new_table_cols = trim($matches[1]);
- $old_table_cols = preg_split('/,(?![\s\w]+\))/m', $new_table_cols);
- $column_list = array();
-
- foreach ($old_table_cols as $key => $declaration)
- {
- $entities = preg_split('#\s+#', trim($declaration));
- $column_list[] = $entities[0];
- if ($entities[0] == $column_name)
- {
- $old_table_cols[$key] = $column_name . ' ' . $column_data['column_type_sql'];
- }
- }
-
- $columns = implode(',', $column_list);
-
- // create a new table and fill it up. destroy the temp one
- $statements[] = 'CREATE TABLE ' . $table_name . ' (' . implode(',', $old_table_cols) . ');';
- $statements[] = 'INSERT INTO ' . $table_name . ' (' . $columns . ') SELECT ' . $columns . ' FROM ' . $table_name . '_temp;';
- $statements[] = 'DROP TABLE ' . $table_name . '_temp';
-
- $statements[] = 'commit';
-
- break;
- }
-
- return $this->_sql_run_sql($statements);
- }
-}
diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/dbal.php
deleted file mode 100644
index ef1dd7d14d..0000000000
--- a/phpBB/includes/db/dbal.php
+++ /dev/null
@@ -1,1049 +0,0 @@
-<?php
-/**
-*
-* @package dbal
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Database Abstraction Layer
-* @package dbal
-*/
-class dbal
-{
- var $db_connect_id;
- var $query_result;
- var $return_on_error = false;
- var $transaction = false;
- var $sql_time = 0;
- var $num_queries = array();
- var $open_queries = array();
-
- var $curtime = 0;
- var $query_hold = '';
- var $html_hold = '';
- var $sql_report = '';
-
- var $persistency = false;
- var $user = '';
- var $server = '';
- var $dbname = '';
-
- // Set to true if error triggered
- var $sql_error_triggered = false;
-
- // Holding the last sql query on sql error
- var $sql_error_sql = '';
- // Holding the error information - only populated if sql_error_triggered is set
- var $sql_error_returned = array();
-
- // Holding transaction count
- var $transactions = 0;
-
- // Supports multi inserts?
- var $multi_insert = false;
-
- /**
- * Current sql layer
- */
- var $sql_layer = '';
-
- /**
- * Wildcards for matching any (%) or exactly one (_) character within LIKE expressions
- */
- var $any_char;
- var $one_char;
-
- /**
- * Exact version of the DBAL, directly queried
- */
- var $sql_server_version = false;
-
- /**
- * Constructor
- */
- function dbal()
- {
- $this->num_queries = array(
- 'cached' => 0,
- 'normal' => 0,
- 'total' => 0,
- );
-
- // Fill default sql layer based on the class being called.
- // This can be changed by the specified layer itself later if needed.
- $this->sql_layer = substr(get_class($this), 5);
-
- // Do not change this please! This variable is used to easy the use of it - and is hardcoded.
- $this->any_char = chr(0) . '%';
- $this->one_char = chr(0) . '_';
- }
-
- /**
- * return on error or display error message
- */
- function sql_return_on_error($fail = false)
- {
- $this->sql_error_triggered = false;
- $this->sql_error_sql = '';
-
- $this->return_on_error = $fail;
- }
-
- /**
- * Return number of sql queries and cached sql queries used
- */
- function sql_num_queries($cached = false)
- {
- return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal'];
- }
-
- /**
- * Add to query count
- */
- function sql_add_num_queries($cached = false)
- {
- $this->num_queries['cached'] += ($cached !== false) ? 1 : 0;
- $this->num_queries['normal'] += ($cached !== false) ? 0 : 1;
- $this->num_queries['total'] += 1;
- }
-
- /**
- * DBAL garbage collection, close sql connection
- */
- function sql_close()
- {
- if (!$this->db_connect_id)
- {
- return false;
- }
-
- if ($this->transaction)
- {
- do
- {
- $this->sql_transaction('commit');
- }
- while ($this->transaction);
- }
-
- foreach ($this->open_queries as $query_id)
- {
- $this->sql_freeresult($query_id);
- }
-
- // Connection closed correctly. Set db_connect_id to false to prevent errors
- if ($result = $this->_sql_close())
- {
- $this->db_connect_id = false;
- }
-
- return $result;
- }
-
- /**
- * Build LIMIT query
- * Doing some validation here.
- */
- function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- if (empty($query))
- {
- return false;
- }
-
- // Never use a negative total or offset
- $total = ($total < 0) ? 0 : $total;
- $offset = ($offset < 0) ? 0 : $offset;
-
- return $this->_sql_query_limit($query, $total, $offset, $cache_ttl);
- }
-
- /**
- * Fetch all rows
- */
- function sql_fetchrowset($query_id = false)
- {
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($query_id !== false)
- {
- $result = array();
- while ($row = $this->sql_fetchrow($query_id))
- {
- $result[] = $row;
- }
-
- return $result;
- }
-
- return false;
- }
-
- /**
- * Seek to given row number
- * rownum is zero-based
- */
- function sql_rowseek($rownum, &$query_id)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_rowseek($rownum, $query_id);
- }
-
- if ($query_id === false)
- {
- return false;
- }
-
- $this->sql_freeresult($query_id);
- $query_id = $this->sql_query($this->last_query_text);
-
- if ($query_id === false)
- {
- return false;
- }
-
- // We do not fetch the row for rownum == 0 because then the next resultset would be the second row
- for ($i = 0; $i < $rownum; $i++)
- {
- if (!$this->sql_fetchrow($query_id))
- {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Fetch field
- * if rownum is false, the current row is used, else it is pointing to the row (zero-based)
- */
- function sql_fetchfield($field, $rownum = false, $query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($query_id !== false)
- {
- if ($rownum !== false)
- {
- $this->sql_rowseek($rownum, $query_id);
- }
-
- if (!is_object($query_id) && $cache->sql_exists($query_id))
- {
- return $cache->sql_fetchfield($query_id, $field);
- }
-
- $row = $this->sql_fetchrow($query_id);
- return (isset($row[$field])) ? $row[$field] : false;
- }
-
- return false;
- }
-
- /**
- * Correctly adjust LIKE expression for special characters
- * Some DBMS are handling them in a different way
- *
- * @param string $expression The expression to use. Every wildcard is escaped, except $this->any_char and $this->one_char
- * @return string LIKE expression including the keyword!
- */
- function sql_like_expression($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) . '\'');
- }
-
- /**
- * Build a case expression
- *
- * Note: The two statements action_true and action_false must have the same data type (int, vchar, ...) in the database!
- *
- * @param string $condition The condition which must be true, to use action_true rather then action_else
- * @param string $action_true SQL expression that is used, if the condition is true
- * @param string $action_else SQL expression that is used, if the condition is false, optional
- * @return string CASE expression including the condition and statements
- */
- public function sql_case($condition, $action_true, $action_false = false)
- {
- $sql_case = 'CASE WHEN ' . $condition;
- $sql_case .= ' THEN ' . $action_true;
- $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : '';
- $sql_case .= ' END';
- return $sql_case;
- }
-
- /**
- * Build a concatenated expression
- *
- * @param string $expr1 Base SQL expression where we append the second one
- * @param string $expr2 SQL expression that is appended to the first expression
- * @return string Concatenated string
- */
- public function sql_concatenate($expr1, $expr2)
- {
- return $expr1 . ' || ' . $expr2;
- }
-
- /**
- * Returns whether results of a query need to be buffered to run a transaction while iterating over them.
- *
- * @return bool Whether buffering is required.
- */
- function sql_buffer_nested_transactions()
- {
- return false;
- }
-
- /**
- * SQL Transaction
- * @access private
- */
- function sql_transaction($status = 'begin')
- {
- switch ($status)
- {
- case 'begin':
- // If we are within a transaction we will not open another one, but enclose the current one to not loose data (prevening auto commit)
- if ($this->transaction)
- {
- $this->transactions++;
- return true;
- }
-
- $result = $this->_sql_transaction('begin');
-
- if (!$result)
- {
- $this->sql_error();
- }
-
- $this->transaction = true;
- break;
-
- case 'commit':
- // If there was a previously opened transaction we do not commit yet... but count back the number of inner transactions
- if ($this->transaction && $this->transactions)
- {
- $this->transactions--;
- return true;
- }
-
- // Check if there is a transaction (no transaction can happen if there was an error, with a combined rollback and error returning enabled)
- // This implies we have transaction always set for autocommit db's
- if (!$this->transaction)
- {
- return false;
- }
-
- $result = $this->_sql_transaction('commit');
-
- if (!$result)
- {
- $this->sql_error();
- }
-
- $this->transaction = false;
- $this->transactions = 0;
- break;
-
- case 'rollback':
- $result = $this->_sql_transaction('rollback');
- $this->transaction = false;
- $this->transactions = 0;
- break;
-
- default:
- $result = $this->_sql_transaction($status);
- break;
- }
-
- return $result;
- }
-
- /**
- * Build sql statement from array for insert/update/select statements
- *
- * Idea for this from Ikonboard
- * Possible query values: INSERT, INSERT_SELECT, UPDATE, SELECT
- *
- */
- function sql_build_array($query, $assoc_ary = false)
- {
- if (!is_array($assoc_ary))
- {
- return false;
- }
-
- $fields = $values = array();
-
- if ($query == 'INSERT' || $query == 'INSERT_SELECT')
- {
- foreach ($assoc_ary as $key => $var)
- {
- $fields[] = $key;
-
- if (is_array($var) && is_string($var[0]))
- {
- // This is used for INSERT_SELECT(s)
- $values[] = $var[0];
- }
- else
- {
- $values[] = $this->_sql_validate_value($var);
- }
- }
-
- $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' ';
- }
- else if ($query == 'MULTI_INSERT')
- {
- trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR);
- }
- else if ($query == 'UPDATE' || $query == 'SELECT')
- {
- $values = array();
- foreach ($assoc_ary as $key => $var)
- {
- $values[] = "$key = " . $this->_sql_validate_value($var);
- }
- $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values);
- }
-
- return $query;
- }
-
- /**
- * Build IN or NOT IN sql comparison string, uses <> or = on single element
- * arrays to improve comparison speed
- *
- * @access public
- * @param string $field name of the sql column that shall be compared
- * @param array $array array of values that are allowed (IN) or not allowed (NOT IN)
- * @param bool $negate true for NOT IN (), false for IN () (default)
- * @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false.
- */
- function sql_in_set($field, $array, $negate = false, $allow_empty_set = false)
- {
- if (!sizeof($array))
- {
- if (!$allow_empty_set)
- {
- // Print the backtrace to help identifying the location of the problematic code
- $this->sql_error('No values specified for SQL IN comparison');
- }
- else
- {
- // NOT IN () actually means everything so use a tautology
- if ($negate)
- {
- return '1=1';
- }
- // IN () actually means nothing so use a contradiction
- else
- {
- return '1=0';
- }
- }
- }
-
- if (!is_array($array))
- {
- $array = array($array);
- }
-
- if (sizeof($array) == 1)
- {
- @reset($array);
- $var = current($array);
-
- return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var);
- }
- else
- {
- return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')';
- }
- }
-
- /**
- * 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 binary OR operator on DB column.
- * Results in sql statement: "{$column_name} | (1 << {$bit}) {$compare}"
- *
- * @param string $column_name The column name to use
- * @param int $bit The value to use for the OR operator, will be converted to (1 << $bit). Is used by options, using the number schema... 0, 1, 2...29
- * @param string $compare Any custom SQL code after the check (for example "= 0")
- */
- function sql_bit_or($column_name, $bit, $compare = '')
- {
- if (method_exists($this, '_sql_bit_or'))
- {
- return $this->_sql_bit_or($column_name, $bit, $compare);
- }
-
- return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : '');
- }
-
- /**
- * Returns SQL string to cast a string expression to an int.
- *
- * @param string $expression An expression evaluating to string
- * @return string Expression returning an int
- */
- function cast_expr_to_bigint($expression)
- {
- return $expression;
- }
-
- /**
- * Returns SQL string to cast an integer expression to a string.
- *
- * @param string $expression An expression evaluating to int
- * @return string Expression returning a string
- */
- function cast_expr_to_string($expression)
- {
- return $expression;
- }
-
- /**
- * Run LOWER() on DB column of type text (i.e. neither varchar nor char).
- *
- * @param string $column_name The column name to use
- *
- * @return string A SQL statement like "LOWER($column_name)"
- */
- function sql_lower_text($column_name)
- {
- return "LOWER($column_name)";
- }
-
- /**
- * Run more than one insert statement.
- *
- * @param string $table table name to run the statements on
- * @param array &$sql_ary multi-dimensional array holding the statement data.
- *
- * @return bool false if no statements were executed.
- * @access public
- */
- function sql_multi_insert($table, &$sql_ary)
- {
- if (!sizeof($sql_ary))
- {
- return false;
- }
-
- if ($this->multi_insert)
- {
- $ary = array();
- foreach ($sql_ary as $id => $_sql_ary)
- {
- // If by accident the sql array is only one-dimensional we build a normal insert statement
- if (!is_array($_sql_ary))
- {
- return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary));
- }
-
- $values = array();
- foreach ($_sql_ary as $key => $var)
- {
- $values[] = $this->_sql_validate_value($var);
- }
- $ary[] = '(' . implode(', ', $values) . ')';
- }
-
- return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary));
- }
- else
- {
- foreach ($sql_ary as $ary)
- {
- if (!is_array($ary))
- {
- return false;
- }
-
- $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary));
-
- if (!$result)
- {
- return false;
- }
- }
- }
-
- return true;
- }
-
- /**
- * Function for validating values
- * @access private
- */
- function _sql_validate_value($var)
- {
- if (is_null($var))
- {
- return 'NULL';
- }
- else if (is_string($var))
- {
- return "'" . $this->sql_escape($var) . "'";
- }
- else
- {
- return (is_bool($var)) ? intval($var) : $var;
- }
- }
-
- /**
- * Build sql statement from array for select and select distinct statements
- *
- * Possible query values: SELECT, SELECT_DISTINCT
- */
- function sql_build_query($query, $array)
- {
- $sql = '';
- switch ($query)
- {
- case 'SELECT':
- case 'SELECT_DISTINCT';
-
- $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM ';
-
- // Build table array. We also build an alias array for later checks.
- $table_array = $aliases = array();
- $used_multi_alias = false;
-
- foreach ($array['FROM'] as $table_name => $alias)
- {
- if (is_array($alias))
- {
- $used_multi_alias = true;
-
- foreach ($alias as $multi_alias)
- {
- $table_array[] = $table_name . ' ' . $multi_alias;
- $aliases[] = $multi_alias;
- }
- }
- else
- {
- $table_array[] = $table_name . ' ' . $alias;
- $aliases[] = $alias;
- }
- }
-
- // We run the following code to determine if we need to re-order the table array. ;)
- // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison.
- // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is.
- if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false)
- {
- // Take first LEFT JOIN
- $join = current($array['LEFT_JOIN']);
-
- // Determine the table used there (even if there are more than one used, we only want to have one
- preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches);
-
- // If there is a first join match, we need to make sure the table order is correct
- if (!empty($matches[1]))
- {
- $first_join_match = trim($matches[1]);
- $table_array = $last = array();
-
- foreach ($array['FROM'] as $table_name => $alias)
- {
- if (is_array($alias))
- {
- foreach ($alias as $multi_alias)
- {
- ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias;
- }
- }
- else
- {
- ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias;
- }
- }
-
- $table_array = array_merge($table_array, $last);
- }
- }
-
- $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array));
-
- if (!empty($array['LEFT_JOIN']))
- {
- foreach ($array['LEFT_JOIN'] as $join)
- {
- $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')';
- }
- }
-
- if (!empty($array['WHERE']))
- {
- $sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']);
- }
-
- if (!empty($array['GROUP_BY']))
- {
- $sql .= ' GROUP BY ' . $array['GROUP_BY'];
- }
-
- if (!empty($array['ORDER_BY']))
- {
- $sql .= ' ORDER BY ' . $array['ORDER_BY'];
- }
-
- break;
- }
-
- return $sql;
- }
-
- /**
- * display sql error page
- */
- function sql_error($sql = '')
- {
- global $auth, $user, $config;
-
- // Set var to retrieve errored status
- $this->sql_error_triggered = true;
- $this->sql_error_sql = $sql;
-
- $this->sql_error_returned = $this->_sql_error();
-
- if (!$this->return_on_error)
- {
- $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]<br /><br />' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']';
-
- // Show complete SQL error and path to administrators only
- // Additionally show complete error on installation or if extended debug mode is enabled
- // The DEBUG constant is for development only!
- if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG'))
- {
- $message .= ($sql) ? '<br /><br />SQL<br /><br />' . htmlspecialchars($sql) : '';
- }
- else
- {
- // If error occurs in initiating the session we need to use a pre-defined language string
- // This could happen if the connection could not be established for example (then we are not able to grab the default language)
- if (!isset($user->lang['SQL_ERROR_OCCURRED']))
- {
- $message .= '<br /><br />An sql error occurred while fetching this page. Please contact an administrator if this problem persists.';
- }
- else
- {
- if (!empty($config['board_contact']))
- {
- $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>');
- }
- else
- {
- $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', '');
- }
- }
- }
-
- if ($this->transaction)
- {
- $this->sql_transaction('rollback');
- }
-
- if (strlen($message) > 1024)
- {
- // We need to define $msg_long_text here to circumvent text stripping.
- global $msg_long_text;
- $msg_long_text = $message;
-
- trigger_error(false, E_USER_ERROR);
- }
-
- trigger_error($message, E_USER_ERROR);
- }
-
- if ($this->transaction)
- {
- $this->sql_transaction('rollback');
- }
-
- return $this->sql_error_returned;
- }
-
- /**
- * Explain queries
- */
- function sql_report($mode, $query = '')
- {
- global $cache, $starttime, $phpbb_root_path, $user;
- global $request;
-
- if (is_object($request) && !$request->variable('explain', false))
- {
- return false;
- }
-
- if (!$query && $this->query_hold != '')
- {
- $query = $this->query_hold;
- }
-
- switch ($mode)
- {
- case 'display':
- if (!empty($cache))
- {
- $cache->unload();
- }
- $this->sql_close();
-
- $mtime = explode(' ', microtime());
- $totaltime = $mtime[0] + $mtime[1] - $starttime;
-
- echo '<!DOCTYPE html>
- <html dir="ltr">
- <head>
- <meta charset="utf-8">
- <title>SQL Report</title>
- <link href="' . $phpbb_root_path . 'adm/style/admin.css" rel="stylesheet" type="text/css" media="screen" />
- </head>
- <body id="errorpage">
- <div id="wrap">
- <div id="page-header">
- <a href="' . build_url('explain') . '">Return to previous page</a>
- </div>
- <div id="page-body">
- <div id="acp">
- <div class="panel">
- <span class="corners-top"><span></span></span>
- <div id="content">
- <h1>SQL Report</h1>
- <br />
- <p><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></p>
-
- <p>Time spent on ' . $this->sql_layer . ' queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></p>
-
- <br /><br />
- ' . $this->sql_report . '
- </div>
- <span class="corners-bottom"><span></span></span>
- </div>
- </div>
- </div>
- <div id="page-footer">
- Powered by <a href="http://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Group
- </div>
- </div>
- </body>
- </html>';
-
- exit_handler();
-
- break;
-
- case 'stop':
- $endtime = explode(' ', microtime());
- $endtime = $endtime[0] + $endtime[1];
-
- $this->sql_report .= '
-
- <table cellspacing="1">
- <thead>
- <tr>
- <th>Query #' . $this->num_queries['total'] . '</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td class="row3"><textarea style="font-family:\'Courier New\',monospace;width:99%" rows="5" cols="10">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td>
- </tr>
- </tbody>
- </table>
-
- ' . $this->html_hold . '
-
- <p style="text-align: center;">
- ';
-
- if ($this->query_result)
- {
- if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query))
- {
- $this->sql_report .= 'Affected rows: <b>' . $this->sql_affectedrows($this->query_result) . '</b> | ';
- }
- $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $this->curtime) . 's</b>';
- }
- else
- {
- $error = $this->sql_error();
- $this->sql_report .= '<b style="color: red">FAILED</b> - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']);
- }
-
- $this->sql_report .= '</p><br /><br />';
-
- $this->sql_time += $endtime - $this->curtime;
- break;
-
- case 'start':
- $this->query_hold = $query;
- $this->html_hold = '';
-
- $this->_sql_report($mode, $query);
-
- $this->curtime = explode(' ', microtime());
- $this->curtime = $this->curtime[0] + $this->curtime[1];
-
- break;
-
- case 'add_select_row':
-
- $html_table = func_get_arg(2);
- $row = func_get_arg(3);
-
- if (!$html_table && sizeof($row))
- {
- $html_table = true;
- $this->html_hold .= '<table cellspacing="1"><tr>';
-
- foreach (array_keys($row) as $val)
- {
- $this->html_hold .= '<th>' . (($val) ? ucwords(str_replace('_', ' ', $val)) : '&nbsp;') . '</th>';
- }
- $this->html_hold .= '</tr>';
- }
- $this->html_hold .= '<tr>';
-
- $class = 'row1';
- foreach (array_values($row) as $val)
- {
- $class = ($class == 'row1') ? 'row2' : 'row1';
- $this->html_hold .= '<td class="' . $class . '">' . (($val) ? $val : '&nbsp;') . '</td>';
- }
- $this->html_hold .= '</tr>';
-
- return $html_table;
-
- break;
-
- case 'fromcache':
-
- $this->_sql_report($mode, $query);
-
- break;
-
- case 'record_fromcache':
-
- $endtime = func_get_arg(2);
- $splittime = func_get_arg(3);
-
- $time_cache = $endtime - $this->curtime;
- $time_db = $splittime - $endtime;
- $color = ($time_db > $time_cache) ? 'green' : 'red';
-
- $this->sql_report .= '<table cellspacing="1"><thead><tr><th>Query results obtained from the cache</th></tr></thead><tbody><tr>';
- $this->sql_report .= '<td class="row3"><textarea style="font-family:\'Courier New\',monospace;width:99%" rows="5" cols="10">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></tbody></table>';
- $this->sql_report .= '<p style="text-align: center;">';
- $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p><br /><br />';
-
- // Pad the start time to not interfere with page timing
- $starttime += $time_db;
-
- break;
-
- default:
-
- $this->_sql_report($mode, $query);
-
- break;
- }
-
- return true;
- }
-
- /**
- * Gets the estimated number of rows in a specified table.
- *
- * @param string $table_name Table name
- *
- * @return string Number of rows in $table_name.
- * Prefixed with ~ if estimated (otherwise exact).
- *
- * @access public
- */
- function get_estimated_row_count($table_name)
- {
- return $this->get_row_count($table_name);
- }
-
- /**
- * Gets the exact number of rows in a specified table.
- *
- * @param string $table_name Table name
- *
- * @return string Exact number of rows in $table_name.
- *
- * @access public
- */
- function get_row_count($table_name)
- {
- $sql = 'SELECT COUNT(*) AS rows_total
- FROM ' . $this->sql_escape($table_name);
- $result = $this->sql_query($sql);
- $rows_total = $this->sql_fetchfield('rows_total');
- $this->sql_freeresult($result);
-
- return $rows_total;
- }
-}
-
-/**
-* This variable holds the class name to use later
-*/
-$sql_db = (!empty($dbms)) ? 'dbal_' . basename($dbms) : 'dbal';
diff --git a/phpBB/includes/db/firebird.php b/phpBB/includes/db/firebird.php
deleted file mode 100644
index 5728eb901c..0000000000
--- a/phpBB/includes/db/firebird.php
+++ /dev/null
@@ -1,540 +0,0 @@
-<?php
-/**
-*
-* @package dbal
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
-
-/**
-* Firebird/Interbase Database Abstraction Layer
-* Minimum Requirement is Firebird 2.1
-* @package dbal
-*/
-class dbal_firebird extends dbal
-{
- var $last_query_text = '';
- var $service_handle = false;
- var $affected_rows = 0;
- var $connect_error = '';
-
- /**
- * Connect to server
- */
- function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
- {
- $this->persistency = $persistency;
- $this->user = $sqluser;
- $this->server = $sqlserver . (($port) ? ':' . $port : '');
- $this->dbname = str_replace('\\', '/', $database);
-
- // There are three possibilities to connect to an interbase db
- if (!$this->server)
- {
- $use_database = $this->dbname;
- }
- else if (strpos($this->server, '//') === 0)
- {
- $use_database = $this->server . $this->dbname;
- }
- else
- {
- $use_database = $this->server . ':' . $this->dbname;
- }
-
- if ($this->persistency)
- {
- if (!function_exists('ibase_pconnect'))
- {
- $this->connect_error = 'ibase_pconnect function does not exist, is interbase extension installed?';
- return $this->sql_error('');
- }
- $this->db_connect_id = @ibase_pconnect($use_database, $this->user, $sqlpassword, false, false, 3);
- }
- else
- {
- if (!function_exists('ibase_connect'))
- {
- $this->connect_error = 'ibase_connect function does not exist, is interbase extension installed?';
- return $this->sql_error('');
- }
- $this->db_connect_id = @ibase_connect($use_database, $this->user, $sqlpassword, false, false, 3);
- }
-
- // Do not call ibase_service_attach if connection failed,
- // otherwise error message from ibase_(p)connect call will be clobbered.
- if ($this->db_connect_id && function_exists('ibase_service_attach') && $this->server)
- {
- $this->service_handle = @ibase_service_attach($this->server, $this->user, $sqlpassword);
- }
- else
- {
- $this->service_handle = false;
- }
-
- return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
- }
-
- /**
- * Version information about used database
- * @param bool $raw if true, only return the fetched sql_server_version
- * @param bool $use_cache forced to false for Interbase
- * @return string sql server version
- */
- function sql_server_info($raw = false, $use_cache = true)
- {
- /**
- * force $use_cache false. I didn't research why the caching code there is no caching code
- * but I assume its because the IB extension provides a direct method to access it
- * without a query.
- */
-
- $use_cache = false;
-
- if ($this->service_handle !== false && function_exists('ibase_server_info'))
- {
- return @ibase_server_info($this->service_handle, IBASE_SVC_SERVER_VERSION);
- }
-
- return ($raw) ? '2.1' : 'Firebird/Interbase';
- }
-
- /**
- * SQL Transaction
- * @access private
- */
- function _sql_transaction($status = 'begin')
- {
- switch ($status)
- {
- case 'begin':
- return true;
- break;
-
- case 'commit':
- return @ibase_commit();
- break;
-
- case 'rollback':
- return @ibase_rollback();
- break;
- }
-
- return true;
- }
-
- /**
- * Base query method
- *
- * @param string $query Contains the SQL query which shall be executed
- * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
- * @return mixed When casted to bool the returned value returns true on success and false on failure
- *
- * @access public
- */
- function sql_query($query = '', $cache_ttl = 0)
- {
- if ($query != '')
- {
- global $cache;
-
- // EXPLAIN only in extra debug mode
- if (defined('DEBUG'))
- {
- $this->sql_report('start', $query);
- }
-
- $this->last_query_text = $query;
- $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false;
- $this->sql_add_num_queries($this->query_result);
-
- if ($this->query_result === false)
- {
- $array = array();
- // We overcome Firebird's 32767 char limit by binding vars
- if (strlen($query) > 32767)
- {
- if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/s', $query, $regs))
- {
- if (strlen($regs[3]) > 32767)
- {
- preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER);
-
- $inserts = $vals[0];
- unset($vals);
-
- foreach ($inserts as $key => $value)
- {
- if (!empty($value) && $value[0] === "'" && strlen($value) > 32769) // check to see if this thing is greater than the max + 'x2
- {
- $inserts[$key] = '?';
- $array[] = str_replace("''", "'", substr($value, 1, -1));
- }
- }
-
- $query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')';
- }
- }
- else if (preg_match('/^(UPDATE ([\\w_]++)\\s+SET )([\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|\\d+)(?:,\\s*[\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+)\\s+(WHERE.*)$/s', $query, $data))
- {
- if (strlen($data[3]) > 32767)
- {
- $update = $data[1];
- $where = $data[4];
- preg_match_all('/(\\w++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[3], $temp, PREG_SET_ORDER);
- unset($data);
-
- $cols = array();
- foreach ($temp as $value)
- {
- if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 32769) // check to see if this thing is greater than the max + 'x2
- {
- $array[] = str_replace("''", "'", substr($value[2], 1, -1));
- $cols[] = $value[1] . '=?';
- }
- else
- {
- $cols[] = $value[1] . '=' . $value[2];
- }
- }
-
- $query = $update . implode(', ', $cols) . ' ' . $where;
- unset($cols);
- }
- }
- }
-
- if (!function_exists('ibase_affected_rows') && (preg_match('/^UPDATE ([\w_]++)\s+SET [\w_]++\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+)(?:,\s*[\w_]++\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+\s+(WHERE.*)?$/s', $query, $regs) || preg_match('/^DELETE FROM ([\w_]++)\s*(WHERE\s*.*)?$/s', $query, $regs)))
- {
- $affected_sql = 'SELECT COUNT(*) as num_rows_affected FROM ' . $regs[1];
- if (!empty($regs[2]))
- {
- $affected_sql .= ' ' . $regs[2];
- }
-
- if (!($temp_q_id = @ibase_query($this->db_connect_id, $affected_sql)))
- {
- return false;
- }
-
- $temp_result = @ibase_fetch_assoc($temp_q_id);
- @ibase_free_result($temp_q_id);
-
- $this->affected_rows = ($temp_result) ? $temp_result['NUM_ROWS_AFFECTED'] : false;
- }
-
- if (sizeof($array))
- {
- $p_query = @ibase_prepare($this->db_connect_id, $query);
- array_unshift($array, $p_query);
- $this->query_result = call_user_func_array('ibase_execute', $array);
- unset($array);
-
- if ($this->query_result === false)
- {
- $this->sql_error($query);
- }
- }
- else if (($this->query_result = @ibase_query($this->db_connect_id, $query)) === false)
- {
- $this->sql_error($query);
- }
-
- if (defined('DEBUG'))
- {
- $this->sql_report('stop', $query);
- }
-
- if (!$this->transaction)
- {
- if (function_exists('ibase_commit_ret'))
- {
- @ibase_commit_ret();
- }
- else
- {
- // way cooler than ibase_commit_ret :D
- @ibase_query('COMMIT RETAIN;');
- }
- }
-
- if ($cache_ttl)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl);
- }
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- }
- }
- else if (defined('DEBUG'))
- {
- $this->sql_report('fromcache', $query);
- }
- }
- else
- {
- return false;
- }
-
- return $this->query_result;
- }
-
- /**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- $query = 'SELECT FIRST ' . $total . ((!empty($offset)) ? ' SKIP ' . $offset : '') . substr($query, 6);
-
- return $this->sql_query($query, $cache_ttl);
- }
-
- /**
- * Return number of affected rows
- */
- function sql_affectedrows()
- {
- // PHP 5+ function
- if (function_exists('ibase_affected_rows'))
- {
- return ($this->db_connect_id) ? @ibase_affected_rows($this->db_connect_id) : false;
- }
- else
- {
- return $this->affected_rows;
- }
- }
-
- /**
- * Fetch current row
- */
- function sql_fetchrow($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_fetchrow($query_id);
- }
-
- if ($query_id === false)
- {
- return false;
- }
-
- $row = array();
- $cur_row = @ibase_fetch_object($query_id, IBASE_TEXT);
-
- if (!$cur_row)
- {
- return false;
- }
-
- foreach (get_object_vars($cur_row) as $key => $value)
- {
- $row[strtolower($key)] = (is_string($value)) ? trim(str_replace(array("\\0", "\\n"), array("\0", "\n"), $value)) : $value;
- }
-
- return (sizeof($row)) ? $row : false;
- }
-
- /**
- * Get last inserted id after insert statement
- */
- function sql_nextid()
- {
- $query_id = $this->query_result;
-
- if ($query_id !== false && $this->last_query_text != '')
- {
- if ($this->query_result && preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#i', $this->last_query_text, $tablename))
- {
- $sql = 'SELECT GEN_ID(' . $tablename[1] . '_gen, 0) AS new_id FROM RDB$DATABASE';
-
- if (!($temp_q_id = @ibase_query($this->db_connect_id, $sql)))
- {
- return false;
- }
-
- $temp_result = @ibase_fetch_assoc($temp_q_id);
- @ibase_free_result($temp_q_id);
-
- return ($temp_result) ? $temp_result['NEW_ID'] : false;
- }
- }
-
- return false;
- }
-
- /**
- * Free sql result
- */
- function sql_freeresult($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_freeresult($query_id);
- }
-
- if (isset($this->open_queries[(int) $query_id]))
- {
- unset($this->open_queries[(int) $query_id]);
- return @ibase_free_result($query_id);
- }
-
- return false;
- }
-
- /**
- * Escape string used in sql query
- */
- function sql_escape($msg)
- {
- return str_replace(array("'", "\0"), array("''", ''), $msg);
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression . " ESCAPE '\\'";
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- return $data;
- }
-
- function _sql_bit_and($column_name, $bit, $compare = '')
- {
- return 'BIN_AND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : '');
- }
-
- function _sql_bit_or($column_name, $bit, $compare = '')
- {
- return 'BIN_OR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : '');
- }
-
- /**
- * @inheritdoc
- */
- function cast_expr_to_bigint($expression)
- {
- // Precision must be from 1 to 18
- return 'CAST(' . $expression . ' as DECIMAL(18, 0))';
- }
-
- /**
- * @inheritdoc
- */
- function cast_expr_to_string($expression)
- {
- return 'CAST(' . $expression . ' as VARCHAR(255))';
- }
-
- /**
- * return sql error array
- * @access private
- */
- function _sql_error()
- {
- // Need special handling here because ibase_errmsg returns
- // connection errors, however if the interbase extension
- // is not installed then ibase_errmsg does not exist and
- // we cannot call it.
- if (function_exists('ibase_errmsg'))
- {
- $msg = @ibase_errmsg();
- if (!$msg)
- {
- $msg = $this->connect_error;
- }
- }
- else
- {
- $msg = $this->connect_error;
- }
- return array(
- 'message' => $msg,
- 'code' => (@function_exists('ibase_errcode') ? @ibase_errcode() : '')
- );
- }
-
- /**
- * Close sql connection
- * @access private
- */
- function _sql_close()
- {
- if ($this->service_handle !== false)
- {
- @ibase_service_detach($this->service_handle);
- }
-
- return @ibase_close($this->db_connect_id);
- }
-
- /**
- * Build db-specific report
- * @access private
- */
- function _sql_report($mode, $query = '')
- {
- switch ($mode)
- {
- case 'start':
- break;
-
- case 'fromcache':
- $endtime = explode(' ', microtime());
- $endtime = $endtime[0] + $endtime[1];
-
- $result = @ibase_query($this->db_connect_id, $query);
- while ($void = @ibase_fetch_object($result, IBASE_TEXT))
- {
- // Take the time spent on parsing rows into account
- }
- @ibase_free_result($result);
-
- $splittime = explode(' ', microtime());
- $splittime = $splittime[0] + $splittime[1];
-
- $this->sql_report('record_fromcache', $query, $endtime, $splittime);
-
- break;
- }
- }
-}
diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/mssql.php
deleted file mode 100644
index 1ec8517308..0000000000
--- a/phpBB/includes/db/mssql.php
+++ /dev/null
@@ -1,456 +0,0 @@
-<?php
-/**
-*
-* @package dbal
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
-
-/**
-* MSSQL Database Abstraction Layer
-* Minimum Requirement is MSSQL 2000+
-* @package dbal
-*/
-class dbal_mssql extends dbal
-{
- /**
- * Connect to server
- */
- function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
- {
- $this->persistency = $persistency;
- $this->user = $sqluser;
- $this->dbname = $database;
-
- $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':';
- $this->server = $sqlserver . (($port) ? $port_delimiter . $port : '');
-
- @ini_set('mssql.charset', 'UTF-8');
- @ini_set('mssql.textlimit', 2147483647);
- @ini_set('mssql.textsize', 2147483647);
-
- $this->db_connect_id = ($this->persistency) ? @mssql_pconnect($this->server, $this->user, $sqlpassword, $new_link) : @mssql_connect($this->server, $this->user, $sqlpassword, $new_link);
-
- if ($this->db_connect_id && $this->dbname != '')
- {
- if (!@mssql_select_db($this->dbname, $this->db_connect_id))
- {
- @mssql_close($this->db_connect_id);
- return false;
- }
- }
-
- return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
- }
-
- /**
- * Version information about used database
- * @param bool $raw if true, only return the fetched sql_server_version
- * @param bool $use_cache If true, it is safe to retrieve the value from the cache
- * @return string sql server version
- */
- function sql_server_info($raw = false, $use_cache = true)
- {
- global $cache;
-
- if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mssql_version')) === false)
- {
- $result_id = @mssql_query("SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')", $this->db_connect_id);
-
- $row = false;
- if ($result_id)
- {
- $row = @mssql_fetch_assoc($result_id);
- @mssql_free_result($result_id);
- }
-
- $this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0;
-
- if (!empty($cache) && $use_cache)
- {
- $cache->put('mssql_version', $this->sql_server_version);
- }
- }
-
- if ($raw)
- {
- return $this->sql_server_version;
- }
-
- return ($this->sql_server_version) ? 'MSSQL<br />' . $this->sql_server_version : 'MSSQL';
- }
-
- /**
- * {@inheritDoc}
- */
- public function sql_concatenate($expr1, $expr2)
- {
- return $expr1 . ' + ' . $expr2;
- }
-
- /**
- * SQL Transaction
- * @access private
- */
- function _sql_transaction($status = 'begin')
- {
- switch ($status)
- {
- case 'begin':
- return @mssql_query('BEGIN TRANSACTION', $this->db_connect_id);
- break;
-
- case 'commit':
- return @mssql_query('COMMIT TRANSACTION', $this->db_connect_id);
- break;
-
- case 'rollback':
- return @mssql_query('ROLLBACK TRANSACTION', $this->db_connect_id);
- break;
- }
-
- return true;
- }
-
- /**
- * Base query method
- *
- * @param string $query Contains the SQL query which shall be executed
- * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
- * @return mixed When casted to bool the returned value returns true on success and false on failure
- *
- * @access public
- */
- function sql_query($query = '', $cache_ttl = 0)
- {
- if ($query != '')
- {
- global $cache;
-
- // EXPLAIN only in extra debug mode
- if (defined('DEBUG'))
- {
- $this->sql_report('start', $query);
- }
-
- $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false;
- $this->sql_add_num_queries($this->query_result);
-
- if ($this->query_result === false)
- {
- if (($this->query_result = @mssql_query($query, $this->db_connect_id)) === false)
- {
- $this->sql_error($query);
- }
-
- if (defined('DEBUG'))
- {
- $this->sql_report('stop', $query);
- }
-
- if ($cache_ttl)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl);
- }
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- }
- }
- else if (defined('DEBUG'))
- {
- $this->sql_report('fromcache', $query);
- }
- }
- else
- {
- return false;
- }
-
- return $this->query_result;
- }
-
- /**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- // Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows)
- if ($total)
- {
- // We need to grab the total number of rows + the offset number of rows to get the correct result
- if (strpos($query, 'SELECT DISTINCT') === 0)
- {
- $query = 'SELECT DISTINCT TOP ' . ($total + $offset) . ' ' . substr($query, 15);
- }
- else
- {
- $query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6);
- }
- }
-
- $result = $this->sql_query($query, $cache_ttl);
-
- // Seek by $offset rows
- if ($offset)
- {
- $this->sql_rowseek($offset, $result);
- }
-
- return $result;
- }
-
- /**
- * Return number of affected rows
- */
- function sql_affectedrows()
- {
- return ($this->db_connect_id) ? @mssql_rows_affected($this->db_connect_id) : false;
- }
-
- /**
- * Fetch current row
- */
- function sql_fetchrow($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_fetchrow($query_id);
- }
-
- if ($query_id === false)
- {
- return false;
- }
-
- $row = @mssql_fetch_assoc($query_id);
-
- // I hope i am able to remove this later... hopefully only a PHP or MSSQL bug
- if ($row)
- {
- foreach ($row as $key => $value)
- {
- $row[$key] = ($value === ' ' || $value === NULL) ? '' : $value;
- }
- }
-
- return $row;
- }
-
- /**
- * Seek to given row number
- * rownum is zero-based
- */
- function sql_rowseek($rownum, &$query_id)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_rowseek($rownum, $query_id);
- }
-
- return ($query_id !== false) ? @mssql_data_seek($query_id, $rownum) : false;
- }
-
- /**
- * Get last inserted id after insert statement
- */
- function sql_nextid()
- {
- $result_id = @mssql_query('SELECT SCOPE_IDENTITY()', $this->db_connect_id);
- if ($result_id)
- {
- if ($row = @mssql_fetch_assoc($result_id))
- {
- @mssql_free_result($result_id);
- return $row['computed'];
- }
- @mssql_free_result($result_id);
- }
-
- return false;
- }
-
- /**
- * Free sql result
- */
- function sql_freeresult($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_freeresult($query_id);
- }
-
- if (isset($this->open_queries[$query_id]))
- {
- unset($this->open_queries[$query_id]);
- return @mssql_free_result($query_id);
- }
-
- return false;
- }
-
- /**
- * Escape string used in sql query
- */
- function sql_escape($msg)
- {
- return str_replace(array("'", "\0"), array("''", ''), $msg);
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_lower_text($column_name)
- {
- return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))";
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression . " ESCAPE '\\'";
- }
-
- /**
- * return sql error array
- * @access private
- */
- function _sql_error()
- {
- $error = array(
- 'message' => @mssql_get_last_message(),
- 'code' => ''
- );
-
- // Get error code number
- $result_id = @mssql_query('SELECT @@ERROR as code', $this->db_connect_id);
- if ($result_id)
- {
- $row = @mssql_fetch_assoc($result_id);
- $error['code'] = $row['code'];
- @mssql_free_result($result_id);
- }
-
- // Get full error message if possible
- $sql = 'SELECT CAST(description as varchar(255)) as message
- FROM master.dbo.sysmessages
- WHERE error = ' . $error['code'];
- $result_id = @mssql_query($sql);
-
- if ($result_id)
- {
- $row = @mssql_fetch_assoc($result_id);
- if (!empty($row['message']))
- {
- $error['message'] .= '<br />' . $row['message'];
- }
- @mssql_free_result($result_id);
- }
-
- return $error;
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- return $data;
- }
-
- /**
- * Close sql connection
- * @access private
- */
- function _sql_close()
- {
- return @mssql_close($this->db_connect_id);
- }
-
- /**
- * Build db-specific report
- * @access private
- */
- function _sql_report($mode, $query = '')
- {
- switch ($mode)
- {
- case 'start':
- $html_table = false;
- @mssql_query('SET SHOWPLAN_TEXT ON;', $this->db_connect_id);
- if ($result = @mssql_query($query, $this->db_connect_id))
- {
- @mssql_next_result($result);
- while ($row = @mssql_fetch_row($result))
- {
- $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
- }
- }
- @mssql_query('SET SHOWPLAN_TEXT OFF;', $this->db_connect_id);
- @mssql_free_result($result);
-
- if ($html_table)
- {
- $this->html_hold .= '</table>';
- }
- break;
-
- case 'fromcache':
- $endtime = explode(' ', microtime());
- $endtime = $endtime[0] + $endtime[1];
-
- $result = @mssql_query($query, $this->db_connect_id);
- while ($void = @mssql_fetch_assoc($result))
- {
- // Take the time spent on parsing rows into account
- }
- @mssql_free_result($result);
-
- $splittime = explode(' ', microtime());
- $splittime = $splittime[0] + $splittime[1];
-
- $this->sql_report('record_fromcache', $query, $endtime, $splittime);
-
- break;
- }
- }
-}
diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/mssql_odbc.php
deleted file mode 100644
index 7c1ffbc808..0000000000
--- a/phpBB/includes/db/mssql_odbc.php
+++ /dev/null
@@ -1,397 +0,0 @@
-<?php
-/**
-*
-* @package dbal
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
-
-/**
-* Unified ODBC functions
-* Unified ODBC functions support any database having ODBC driver, for example Adabas D, IBM DB2, iODBC, Solid, Sybase SQL Anywhere...
-* Here we only support MSSQL Server 2000+ because of the provided schema
-*
-* @note number of bytes returned for returning data depends on odbc.defaultlrl php.ini setting.
-* If it is limited to 4K for example only 4K of data is returned max, resulting in incomplete theme data for example.
-* @note odbc.defaultbinmode may affect UTF8 characters
-*
-* @package dbal
-*/
-class dbal_mssql_odbc extends dbal
-{
- var $last_query_text = '';
-
- /**
- * Connect to server
- */
- function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
- {
- $this->persistency = $persistency;
- $this->user = $sqluser;
- $this->dbname = $database;
-
- $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':';
- $this->server = $sqlserver . (($port) ? $port_delimiter . $port : '');
-
- $max_size = @ini_get('odbc.defaultlrl');
- if (!empty($max_size))
- {
- $unit = strtolower(substr($max_size, -1, 1));
- $max_size = (int) $max_size;
-
- if ($unit == 'k')
- {
- $max_size = floor($max_size / 1024);
- }
- else if ($unit == 'g')
- {
- $max_size *= 1024;
- }
- else if (is_numeric($unit))
- {
- $max_size = floor((int) ($max_size . $unit) / 1048576);
- }
- $max_size = max(8, $max_size) . 'M';
-
- @ini_set('odbc.defaultlrl', $max_size);
- }
-
- $this->db_connect_id = ($this->persistency) ? @odbc_pconnect($this->server, $this->user, $sqlpassword) : @odbc_connect($this->server, $this->user, $sqlpassword);
-
- return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
- }
-
- /**
- * Version information about used database
- * @param bool $raw if true, only return the fetched sql_server_version
- * @param bool $use_cache If true, it is safe to retrieve the value from the cache
- * @return string sql server version
- */
- function sql_server_info($raw = false, $use_cache = true)
- {
- global $cache;
-
- if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mssqlodbc_version')) === false)
- {
- $result_id = @odbc_exec($this->db_connect_id, "SELECT SERVERPROPERTY('productversion'), SERVERPROPERTY('productlevel'), SERVERPROPERTY('edition')");
-
- $row = false;
- if ($result_id)
- {
- $row = @odbc_fetch_array($result_id);
- @odbc_free_result($result_id);
- }
-
- $this->sql_server_version = ($row) ? trim(implode(' ', $row)) : 0;
-
- if (!empty($cache) && $use_cache)
- {
- $cache->put('mssqlodbc_version', $this->sql_server_version);
- }
- }
-
- if ($raw)
- {
- return $this->sql_server_version;
- }
-
- return ($this->sql_server_version) ? 'MSSQL (ODBC)<br />' . $this->sql_server_version : 'MSSQL (ODBC)';
- }
-
- /**
- * {@inheritDoc}
- */
- public function sql_concatenate($expr1, $expr2)
- {
- return $expr1 . ' + ' . $expr2;
- }
-
- /**
- * SQL Transaction
- * @access private
- */
- function _sql_transaction($status = 'begin')
- {
- switch ($status)
- {
- case 'begin':
- return @odbc_exec($this->db_connect_id, 'BEGIN TRANSACTION');
- break;
-
- case 'commit':
- return @odbc_exec($this->db_connect_id, 'COMMIT TRANSACTION');
- break;
-
- case 'rollback':
- return @odbc_exec($this->db_connect_id, 'ROLLBACK TRANSACTION');
- break;
- }
-
- return true;
- }
-
- /**
- * Base query method
- *
- * @param string $query Contains the SQL query which shall be executed
- * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
- * @return mixed When casted to bool the returned value returns true on success and false on failure
- *
- * @access public
- */
- function sql_query($query = '', $cache_ttl = 0)
- {
- if ($query != '')
- {
- global $cache;
-
- // EXPLAIN only in extra debug mode
- if (defined('DEBUG'))
- {
- $this->sql_report('start', $query);
- }
-
- $this->last_query_text = $query;
- $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false;
- $this->sql_add_num_queries($this->query_result);
-
- if ($this->query_result === false)
- {
- if (($this->query_result = @odbc_exec($this->db_connect_id, $query)) === false)
- {
- $this->sql_error($query);
- }
-
- if (defined('DEBUG'))
- {
- $this->sql_report('stop', $query);
- }
-
- if ($cache_ttl)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl);
- }
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- }
- }
- else if (defined('DEBUG'))
- {
- $this->sql_report('fromcache', $query);
- }
- }
- else
- {
- return false;
- }
-
- return $this->query_result;
- }
-
- /**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- // Since TOP is only returning a set number of rows we won't need it if total is set to 0 (return all rows)
- if ($total)
- {
- // We need to grab the total number of rows + the offset number of rows to get the correct result
- if (strpos($query, 'SELECT DISTINCT') === 0)
- {
- $query = 'SELECT DISTINCT TOP ' . ($total + $offset) . ' ' . substr($query, 15);
- }
- else
- {
- $query = 'SELECT TOP ' . ($total + $offset) . ' ' . substr($query, 6);
- }
- }
-
- $result = $this->sql_query($query, $cache_ttl);
-
- // Seek by $offset rows
- if ($offset)
- {
- $this->sql_rowseek($offset, $result);
- }
-
- return $result;
- }
-
- /**
- * Return number of affected rows
- */
- function sql_affectedrows()
- {
- return ($this->db_connect_id) ? @odbc_num_rows($this->query_result) : false;
- }
-
- /**
- * Fetch current row
- * @note number of bytes returned depends on odbc.defaultlrl php.ini setting. If it is limited to 4K for example only 4K of data is returned max.
- */
- function sql_fetchrow($query_id = false, $debug = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_fetchrow($query_id);
- }
-
- return ($query_id !== false) ? @odbc_fetch_array($query_id) : false;
- }
-
- /**
- * Get last inserted id after insert statement
- */
- function sql_nextid()
- {
- $result_id = @odbc_exec($this->db_connect_id, 'SELECT @@IDENTITY');
-
- if ($result_id)
- {
- if (@odbc_fetch_array($result_id))
- {
- $id = @odbc_result($result_id, 1);
- @odbc_free_result($result_id);
- return $id;
- }
- @odbc_free_result($result_id);
- }
-
- return false;
- }
-
- /**
- * Free sql result
- */
- function sql_freeresult($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_freeresult($query_id);
- }
-
- if (isset($this->open_queries[(int) $query_id]))
- {
- unset($this->open_queries[(int) $query_id]);
- return @odbc_free_result($query_id);
- }
-
- return false;
- }
-
- /**
- * Escape string used in sql query
- */
- function sql_escape($msg)
- {
- return str_replace(array("'", "\0"), array("''", ''), $msg);
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_lower_text($column_name)
- {
- return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))";
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression . " ESCAPE '\\'";
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- return $data;
- }
-
- /**
- * return sql error array
- * @access private
- */
- function _sql_error()
- {
- return array(
- 'message' => @odbc_errormsg(),
- 'code' => @odbc_error()
- );
- }
-
- /**
- * Close sql connection
- * @access private
- */
- function _sql_close()
- {
- return @odbc_close($this->db_connect_id);
- }
-
- /**
- * Build db-specific report
- * @access private
- */
- function _sql_report($mode, $query = '')
- {
- switch ($mode)
- {
- case 'start':
- break;
-
- case 'fromcache':
- $endtime = explode(' ', microtime());
- $endtime = $endtime[0] + $endtime[1];
-
- $result = @odbc_exec($this->db_connect_id, $query);
- while ($void = @odbc_fetch_array($result))
- {
- // Take the time spent on parsing rows into account
- }
- @odbc_free_result($result);
-
- $splittime = explode(' ', microtime());
- $splittime = $splittime[0] + $splittime[1];
-
- $this->sql_report('record_fromcache', $query, $endtime, $splittime);
-
- break;
- }
- }
-}
diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/mssqlnative.php
deleted file mode 100644
index e9191fae8a..0000000000
--- a/phpBB/includes/db/mssqlnative.php
+++ /dev/null
@@ -1,643 +0,0 @@
-<?php
-/**
-*
-* @package dbal
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-* This is the MS SQL Server Native database abstraction layer.
-* PHP mssql native driver required.
-* @author Chris Pucci
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
-
-/**
- * Prior to version 1.1 the SQL Server Native PHP driver didn't support sqlsrv_num_rows, or cursor based seeking so we recall all rows into an array
- * and maintain our own cursor index into that array.
- */
-class result_mssqlnative
-{
- public function result_mssqlnative($queryresult = false)
- {
- $this->m_cursor = 0;
- $this->m_rows = array();
- $this->m_num_fields = sqlsrv_num_fields($queryresult);
- $this->m_field_meta = sqlsrv_field_metadata($queryresult);
-
- while ($row = sqlsrv_fetch_array($queryresult, SQLSRV_FETCH_ASSOC))
- {
- if ($row !== null)
- {
- foreach($row as $k => $v)
- {
- if (is_object($v) && method_exists($v, 'format'))
- {
- $row[$k] = $v->format("Y-m-d\TH:i:s\Z");
- }
- }
- $this->m_rows[] = $row;//read results into memory, cursors are not supported
- }
- }
-
- $this->m_row_count = sizeof($this->m_rows);
- }
-
- private function array_to_obj($array, &$obj)
- {
- foreach ($array as $key => $value)
- {
- if (is_array($value))
- {
- $obj->$key = new stdClass();
- array_to_obj($value, $obj->$key);
- }
- else
- {
- $obj->$key = $value;
- }
- }
- return $obj;
- }
-
- public function fetch($mode = SQLSRV_FETCH_BOTH, $object_class = 'stdClass')
- {
- if ($this->m_cursor >= $this->m_row_count || $this->m_row_count == 0)
- {
- return false;
- }
-
- $ret = false;
- $arr_num = array();
-
- if ($mode == SQLSRV_FETCH_NUMERIC || $mode == SQLSRV_FETCH_BOTH)
- {
- foreach($this->m_rows[$this->m_cursor] as $key => $value)
- {
- $arr_num[] = $value;
- }
- }
-
- switch ($mode)
- {
- case SQLSRV_FETCH_ASSOC:
- $ret = $this->m_rows[$this->m_cursor];
- break;
- case SQLSRV_FETCH_NUMERIC:
- $ret = $arr_num;
- break;
- case 'OBJECT':
- $ret = $this->array_to_obj($this->m_rows[$this->m_cursor], $o = new $object_class);
- break;
- case SQLSRV_FETCH_BOTH:
- default:
- $ret = $this->m_rows[$this->m_cursor] + $arr_num;
- break;
- }
- $this->m_cursor++;
- return $ret;
- }
-
- public function get($pos, $fld)
- {
- return $this->m_rows[$pos][$fld];
- }
-
- public function num_rows()
- {
- return $this->m_row_count;
- }
-
- public function seek($iRow)
- {
- $this->m_cursor = min($iRow, $this->m_row_count);
- }
-
- public function num_fields()
- {
- return $this->m_num_fields;
- }
-
- public function field_name($nr)
- {
- $arr_keys = array_keys($this->m_rows[0]);
- return $arr_keys[$nr];
- }
-
- public function field_type($nr)
- {
- $i = 0;
- $int_type = -1;
- $str_type = '';
-
- foreach ($this->m_field_meta as $meta)
- {
- if ($nr == $i)
- {
- $int_type = $meta['Type'];
- break;
- }
- $i++;
- }
-
- //http://msdn.microsoft.com/en-us/library/cc296183.aspx contains type table
- switch ($int_type)
- {
- case SQLSRV_SQLTYPE_BIGINT: $str_type = 'bigint'; break;
- case SQLSRV_SQLTYPE_BINARY: $str_type = 'binary'; break;
- case SQLSRV_SQLTYPE_BIT: $str_type = 'bit'; break;
- case SQLSRV_SQLTYPE_CHAR: $str_type = 'char'; break;
- case SQLSRV_SQLTYPE_DATETIME: $str_type = 'datetime'; break;
- case SQLSRV_SQLTYPE_DECIMAL/*($precision, $scale)*/: $str_type = 'decimal'; break;
- case SQLSRV_SQLTYPE_FLOAT: $str_type = 'float'; break;
- case SQLSRV_SQLTYPE_IMAGE: $str_type = 'image'; break;
- case SQLSRV_SQLTYPE_INT: $str_type = 'int'; break;
- case SQLSRV_SQLTYPE_MONEY: $str_type = 'money'; break;
- case SQLSRV_SQLTYPE_NCHAR/*($charCount)*/: $str_type = 'nchar'; break;
- case SQLSRV_SQLTYPE_NUMERIC/*($precision, $scale)*/: $str_type = 'numeric'; break;
- case SQLSRV_SQLTYPE_NVARCHAR/*($charCount)*/: $str_type = 'nvarchar'; break;
- case SQLSRV_SQLTYPE_NTEXT: $str_type = 'ntext'; break;
- case SQLSRV_SQLTYPE_REAL: $str_type = 'real'; break;
- case SQLSRV_SQLTYPE_SMALLDATETIME: $str_type = 'smalldatetime'; break;
- case SQLSRV_SQLTYPE_SMALLINT: $str_type = 'smallint'; break;
- case SQLSRV_SQLTYPE_SMALLMONEY: $str_type = 'smallmoney'; break;
- case SQLSRV_SQLTYPE_TEXT: $str_type = 'text'; break;
- case SQLSRV_SQLTYPE_TIMESTAMP: $str_type = 'timestamp'; break;
- case SQLSRV_SQLTYPE_TINYINT: $str_type = 'tinyint'; break;
- case SQLSRV_SQLTYPE_UNIQUEIDENTIFIER: $str_type = 'uniqueidentifier'; break;
- case SQLSRV_SQLTYPE_UDT: $str_type = 'UDT'; break;
- case SQLSRV_SQLTYPE_VARBINARY/*($byteCount)*/: $str_type = 'varbinary'; break;
- case SQLSRV_SQLTYPE_VARCHAR/*($charCount)*/: $str_type = 'varchar'; break;
- case SQLSRV_SQLTYPE_XML: $str_type = 'xml'; break;
- default: $str_type = $int_type;
- }
- return $str_type;
- }
-
- public function free()
- {
- unset($this->m_rows);
- return;
- }
-}
-
-/**
-* @package dbal
-*/
-class dbal_mssqlnative extends dbal
-{
- var $m_insert_id = NULL;
- var $last_query_text = '';
- var $query_options = array();
-
- /**
- * Connect to server
- */
- function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
- {
- # Test for driver support, to avoid suppressed fatal error
- if (!function_exists('sqlsrv_connect'))
- {
- trigger_error('Native MS SQL Server driver for PHP is missing or needs to be updated. Version 1.1 or later is required to install phpBB3. You can download the driver from: http://www.microsoft.com/sqlserver/2005/en/us/PHP-Driver.aspx\n', E_USER_ERROR);
- }
-
- //set up connection variables
- $this->persistency = $persistency;
- $this->user = $sqluser;
- $this->dbname = $database;
- $port_delimiter = (defined('PHP_OS') && substr(PHP_OS, 0, 3) === 'WIN') ? ',' : ':';
- $this->server = $sqlserver . (($port) ? $port_delimiter . $port : '');
-
- //connect to database
- $this->db_connect_id = sqlsrv_connect($this->server, array(
- 'Database' => $this->dbname,
- 'UID' => $this->user,
- 'PWD' => $sqlpassword
- ));
-
- return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
- }
-
- /**
- * Version information about used database
- * @param bool $raw if true, only return the fetched sql_server_version
- * @param bool $use_cache If true, it is safe to retrieve the value from the cache
- * @return string sql server version
- */
- function sql_server_info($raw = false, $use_cache = true)
- {
- global $cache;
-
- if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mssql_version')) === false)
- {
- $arr_server_info = sqlsrv_server_info($this->db_connect_id);
- $this->sql_server_version = $arr_server_info['SQLServerVersion'];
-
- if (!empty($cache) && $use_cache)
- {
- $cache->put('mssql_version', $this->sql_server_version);
- }
- }
-
- if ($raw)
- {
- return $this->sql_server_version;
- }
-
- return ($this->sql_server_version) ? 'MSSQL<br />' . $this->sql_server_version : 'MSSQL';
- }
-
- /**
- * {@inheritDoc}
- */
- public function sql_concatenate($expr1, $expr2)
- {
- return $expr1 . ' + ' . $expr2;
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_buffer_nested_transactions()
- {
- return true;
- }
-
- /**
- * SQL Transaction
- * @access private
- */
- function _sql_transaction($status = 'begin')
- {
- switch ($status)
- {
- case 'begin':
- return sqlsrv_begin_transaction($this->db_connect_id);
- break;
-
- case 'commit':
- return sqlsrv_commit($this->db_connect_id);
- break;
-
- case 'rollback':
- return sqlsrv_rollback($this->db_connect_id);
- break;
- }
- return true;
- }
-
- /**
- * Base query method
- *
- * @param string $query Contains the SQL query which shall be executed
- * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
- * @return mixed When casted to bool the returned value returns true on success and false on failure
- *
- * @access public
- */
- function sql_query($query = '', $cache_ttl = 0)
- {
- if ($query != '')
- {
- global $cache;
-
- // EXPLAIN only in extra debug mode
- if (defined('DEBUG'))
- {
- $this->sql_report('start', $query);
- }
-
- $this->last_query_text = $query;
- $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false;
- $this->sql_add_num_queries($this->query_result);
-
- if ($this->query_result === false)
- {
- if (($this->query_result = @sqlsrv_query($this->db_connect_id, $query, array(), $this->query_options)) === false)
- {
- $this->sql_error($query);
- }
- // reset options for next query
- $this->query_options = array();
-
- if (defined('DEBUG'))
- {
- $this->sql_report('stop', $query);
- }
-
- if ($cache_ttl)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl);
- }
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- }
- }
- else if (defined('DEBUG'))
- {
- $this->sql_report('fromcache', $query);
- }
- }
- else
- {
- return false;
- }
- return $this->query_result;
- }
-
- /**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- // total == 0 means all results - not zero results
- if ($offset == 0 && $total !== 0)
- {
- if (strpos($query, "SELECT") === false)
- {
- $query = "TOP {$total} " . $query;
- }
- else
- {
- $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP '.$total, $query);
- }
- }
- else if ($offset > 0)
- {
- $query = preg_replace('/SELECT(\s*DISTINCT)?/Dsi', 'SELECT$1 TOP(10000000) ', $query);
- $query = 'SELECT *
- FROM (SELECT sub2.*, ROW_NUMBER() OVER(ORDER BY sub2.line2) AS line3
- FROM (SELECT 1 AS line2, sub1.* FROM (' . $query . ') AS sub1) as sub2) AS sub3';
-
- if ($total > 0)
- {
- $query .= ' WHERE line3 BETWEEN ' . ($offset+1) . ' AND ' . ($offset + $total);
- }
- else
- {
- $query .= ' WHERE line3 > ' . $offset;
- }
- }
-
- $result = $this->sql_query($query, $cache_ttl);
-
- return $result;
- }
-
- /**
- * Return number of affected rows
- */
- function sql_affectedrows()
- {
- return (!empty($this->query_result)) ? @sqlsrv_rows_affected($this->query_result) : false;
- }
-
- /**
- * Fetch current row
- */
- function sql_fetchrow($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_fetchrow($query_id);
- }
-
- if ($query_id === false)
- {
- return false;
- }
-
- $row = @sqlsrv_fetch_array($query_id, SQLSRV_FETCH_ASSOC);
-
- if ($row)
- {
- foreach ($row as $key => $value)
- {
- $row[$key] = ($value === ' ' || $value === NULL) ? '' : $value;
- }
-
- // remove helper values from LIMIT queries
- if (isset($row['line2']))
- {
- unset($row['line2'], $row['line3']);
- }
- }
- return (sizeof($row)) ? $row : false;
- }
-
- /**
- * Get last inserted id after insert statement
- */
- function sql_nextid()
- {
- $result_id = @sqlsrv_query($this->db_connect_id, 'SELECT @@IDENTITY');
-
- if ($result_id !== false)
- {
- $row = @sqlsrv_fetch_array($result_id);
- $id = $row[0];
- @sqlsrv_free_stmt($result_id);
- return $id;
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Free sql result
- */
- function sql_freeresult($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_freeresult($query_id);
- }
-
- if (isset($this->open_queries[$query_id]))
- {
- unset($this->open_queries[$query_id]);
- return @sqlsrv_free_stmt($query_id);
- }
- return false;
- }
-
- /**
- * Escape string used in sql query
- */
- function sql_escape($msg)
- {
- return str_replace(array("'", "\0"), array("''", ''), $msg);
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_lower_text($column_name)
- {
- return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))";
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression . " ESCAPE '\\'";
- }
-
- /**
- * return sql error array
- * @access private
- */
- function _sql_error()
- {
- $errors = @sqlsrv_errors(SQLSRV_ERR_ERRORS);
- $error_message = '';
- $code = 0;
-
- if ($errors != null)
- {
- foreach ($errors as $error)
- {
- $error_message .= "SQLSTATE: ".$error[ 'SQLSTATE']."\n";
- $error_message .= "code: ".$error[ 'code']."\n";
- $code = $error['code'];
- $error_message .= "message: ".$error[ 'message']."\n";
- }
- $this->last_error_result = $error_message;
- $error = $this->last_error_result;
- }
- else
- {
- $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array();
- }
-
- return array(
- 'message' => $error,
- 'code' => $code,
- );
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- return $data;
- }
-
- /**
- * Close sql connection
- * @access private
- */
- function _sql_close()
- {
- return @sqlsrv_close($this->db_connect_id);
- }
-
- /**
- * Build db-specific report
- * @access private
- */
- function _sql_report($mode, $query = '')
- {
- switch ($mode)
- {
- case 'start':
- $html_table = false;
- @sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT ON;');
- if ($result = @sqlsrv_query($this->db_connect_id, $query))
- {
- @sqlsrv_next_result($result);
- while ($row = @sqlsrv_fetch_array($result))
- {
- $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
- }
- }
- @sqlsrv_query($this->db_connect_id, 'SET SHOWPLAN_TEXT OFF;');
- @sqlsrv_free_stmt($result);
-
- if ($html_table)
- {
- $this->html_hold .= '</table>';
- }
- break;
-
- case 'fromcache':
- $endtime = explode(' ', microtime());
- $endtime = $endtime[0] + $endtime[1];
-
- $result = @sqlsrv_query($this->db_connect_id, $query);
- while ($void = @sqlsrv_fetch_array($result))
- {
- // Take the time spent on parsing rows into account
- }
- @sqlsrv_free_stmt($result);
-
- $splittime = explode(' ', microtime());
- $splittime = $splittime[0] + $splittime[1];
-
- $this->sql_report('record_fromcache', $query, $endtime, $splittime);
-
- break;
- }
- }
-
- /**
- * Utility method used to retrieve number of rows
- * Emulates mysql_num_rows
- * Used in acp_database.php -> write_data_mssqlnative()
- * Requires a static or keyset cursor to be definde via
- * mssqlnative_set_query_options()
- */
- function mssqlnative_num_rows($res)
- {
- if ($res !== false)
- {
- return sqlsrv_num_rows($res);
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Allows setting mssqlnative specific query options passed to sqlsrv_query as 4th parameter.
- */
- function mssqlnative_set_query_options($options)
- {
- $this->query_options = $options;
- }
-}
diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/mysql.php
deleted file mode 100644
index f685ab055c..0000000000
--- a/phpBB/includes/db/mysql.php
+++ /dev/null
@@ -1,567 +0,0 @@
-<?php
-/**
-*
-* @package dbal
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
-
-/**
-* MySQL4 Database Abstraction Layer
-* Compatible with:
-* MySQL 3.23+
-* MySQL 4.0+
-* MySQL 4.1+
-* MySQL 5.0+
-* @package dbal
-*/
-class dbal_mysql extends dbal
-{
- var $multi_insert = true;
-
- /**
- * Connect to server
- * @access public
- */
- function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
- {
- $this->persistency = $persistency;
- $this->user = $sqluser;
- $this->server = $sqlserver . (($port) ? ':' . $port : '');
- $this->dbname = $database;
-
- $this->sql_layer = 'mysql4';
-
- $this->db_connect_id = ($this->persistency) ? @mysql_pconnect($this->server, $this->user, $sqlpassword) : @mysql_connect($this->server, $this->user, $sqlpassword, $new_link);
-
- if ($this->db_connect_id && $this->dbname != '')
- {
- if (@mysql_select_db($this->dbname, $this->db_connect_id))
- {
- // Determine what version we are using and if it natively supports UNICODE
- if (version_compare($this->sql_server_info(true), '4.1.0', '>='))
- {
- @mysql_query("SET NAMES 'utf8'", $this->db_connect_id);
-
- // enforce strict mode on databases that support it
- if (version_compare($this->sql_server_info(true), '5.0.2', '>='))
- {
- $result = @mysql_query('SELECT @@session.sql_mode AS sql_mode', $this->db_connect_id);
- $row = @mysql_fetch_assoc($result);
- @mysql_free_result($result);
- $modes = array_map('trim', explode(',', $row['sql_mode']));
-
- // TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES
- if (!in_array('TRADITIONAL', $modes))
- {
- if (!in_array('STRICT_ALL_TABLES', $modes))
- {
- $modes[] = 'STRICT_ALL_TABLES';
- }
-
- if (!in_array('STRICT_TRANS_TABLES', $modes))
- {
- $modes[] = 'STRICT_TRANS_TABLES';
- }
- }
-
- $mode = implode(',', $modes);
- @mysql_query("SET SESSION sql_mode='{$mode}'", $this->db_connect_id);
- }
- }
- else if (version_compare($this->sql_server_info(true), '4.0.0', '<'))
- {
- $this->sql_layer = 'mysql';
- }
-
- return $this->db_connect_id;
- }
- }
-
- return $this->sql_error('');
- }
-
- /**
- * Version information about used database
- * @param bool $raw if true, only return the fetched sql_server_version
- * @param bool $use_cache If true, it is safe to retrieve the value from the cache
- * @return string sql server version
- */
- function sql_server_info($raw = false, $use_cache = true)
- {
- global $cache;
-
- if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysql_version')) === false)
- {
- $result = @mysql_query('SELECT VERSION() AS version', $this->db_connect_id);
- $row = @mysql_fetch_assoc($result);
- @mysql_free_result($result);
-
- $this->sql_server_version = $row['version'];
-
- if (!empty($cache) && $use_cache)
- {
- $cache->put('mysql_version', $this->sql_server_version);
- }
- }
-
- return ($raw) ? $this->sql_server_version : 'MySQL ' . $this->sql_server_version;
- }
-
- /**
- * {@inheritDoc}
- */
- public function sql_concatenate($expr1, $expr2)
- {
- return 'CONCAT(' . $expr1 . ', ' . $expr2 . ')';
- }
-
- /**
- * SQL Transaction
- * @access private
- */
- function _sql_transaction($status = 'begin')
- {
- switch ($status)
- {
- case 'begin':
- return @mysql_query('BEGIN', $this->db_connect_id);
- break;
-
- case 'commit':
- return @mysql_query('COMMIT', $this->db_connect_id);
- break;
-
- case 'rollback':
- return @mysql_query('ROLLBACK', $this->db_connect_id);
- break;
- }
-
- return true;
- }
-
- /**
- * Base query method
- *
- * @param string $query Contains the SQL query which shall be executed
- * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
- * @return mixed When casted to bool the returned value returns true on success and false on failure
- *
- * @access public
- */
- function sql_query($query = '', $cache_ttl = 0)
- {
- if ($query != '')
- {
- global $cache;
-
- // EXPLAIN only in extra debug mode
- if (defined('DEBUG'))
- {
- $this->sql_report('start', $query);
- }
-
- $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false;
- $this->sql_add_num_queries($this->query_result);
-
- if ($this->query_result === false)
- {
- if (($this->query_result = @mysql_query($query, $this->db_connect_id)) === false)
- {
- $this->sql_error($query);
- }
-
- if (defined('DEBUG'))
- {
- $this->sql_report('stop', $query);
- }
-
- if ($cache_ttl)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl);
- }
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- }
- }
- else if (defined('DEBUG'))
- {
- $this->sql_report('fromcache', $query);
- }
- }
- else
- {
- return false;
- }
-
- return $this->query_result;
- }
-
- /**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- // if $total is set to 0 we do not want to limit the number of rows
- if ($total == 0)
- {
- // Having a value of -1 was always a bug
- $total = '18446744073709551615';
- }
-
- $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total);
-
- return $this->sql_query($query, $cache_ttl);
- }
-
- /**
- * Return number of affected rows
- */
- function sql_affectedrows()
- {
- return ($this->db_connect_id) ? @mysql_affected_rows($this->db_connect_id) : false;
- }
-
- /**
- * Fetch current row
- */
- function sql_fetchrow($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_fetchrow($query_id);
- }
-
- return ($query_id !== false) ? @mysql_fetch_assoc($query_id) : false;
- }
-
- /**
- * Seek to given row number
- * rownum is zero-based
- */
- function sql_rowseek($rownum, &$query_id)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_rowseek($rownum, $query_id);
- }
-
- return ($query_id !== false) ? @mysql_data_seek($query_id, $rownum) : false;
- }
-
- /**
- * Get last inserted id after insert statement
- */
- function sql_nextid()
- {
- return ($this->db_connect_id) ? @mysql_insert_id($this->db_connect_id) : false;
- }
-
- /**
- * Free sql result
- */
- function sql_freeresult($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_freeresult($query_id);
- }
-
- if (isset($this->open_queries[(int) $query_id]))
- {
- unset($this->open_queries[(int) $query_id]);
- return @mysql_free_result($query_id);
- }
-
- return false;
- }
-
- /**
- * Escape string used in sql query
- */
- function sql_escape($msg)
- {
- if (!$this->db_connect_id)
- {
- return @mysql_real_escape_string($msg);
- }
-
- return @mysql_real_escape_string($msg, $this->db_connect_id);
- }
-
- /**
- * Gets the estimated number of rows in a specified table.
- *
- * @param string $table_name Table name
- *
- * @return string Number of rows in $table_name.
- * Prefixed with ~ if estimated (otherwise exact).
- *
- * @access public
- */
- function get_estimated_row_count($table_name)
- {
- $table_status = $this->get_table_status($table_name);
-
- if (isset($table_status['Engine']))
- {
- if ($table_status['Engine'] === 'MyISAM')
- {
- return $table_status['Rows'];
- }
- else if ($table_status['Engine'] === 'InnoDB' && $table_status['Rows'] > 100000)
- {
- return '~' . $table_status['Rows'];
- }
- }
-
- return parent::get_row_count($table_name);
- }
-
- /**
- * Gets the exact number of rows in a specified table.
- *
- * @param string $table_name Table name
- *
- * @return string Exact number of rows in $table_name.
- *
- * @access public
- */
- function get_row_count($table_name)
- {
- $table_status = $this->get_table_status($table_name);
-
- if (isset($table_status['Engine']) && $table_status['Engine'] === 'MyISAM')
- {
- return $table_status['Rows'];
- }
-
- return parent::get_row_count($table_name);
- }
-
- /**
- * Gets some information about the specified table.
- *
- * @param string $table_name Table name
- *
- * @return array
- *
- * @access protected
- */
- function get_table_status($table_name)
- {
- $sql = "SHOW TABLE STATUS
- LIKE '" . $this->sql_escape($table_name) . "'";
- $result = $this->sql_query($sql);
- $table_status = $this->sql_fetchrow($result);
- $this->sql_freeresult($result);
-
- return $table_status;
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression;
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- switch ($stage)
- {
- case 'FROM':
- $data = '(' . $data . ')';
- break;
- }
-
- return $data;
- }
-
- /**
- * return sql error array
- * @access private
- */
- function _sql_error()
- {
- if (!$this->db_connect_id)
- {
- return array(
- 'message' => @mysql_error(),
- 'code' => @mysql_errno()
- );
- }
-
- return array(
- 'message' => @mysql_error($this->db_connect_id),
- 'code' => @mysql_errno($this->db_connect_id)
- );
- }
-
- /**
- * Close sql connection
- * @access private
- */
- function _sql_close()
- {
- return @mysql_close($this->db_connect_id);
- }
-
- /**
- * Build db-specific report
- * @access private
- */
- function _sql_report($mode, $query = '')
- {
- static $test_prof;
-
- // current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING
- if ($test_prof === null)
- {
- $test_prof = false;
- if (version_compare($this->sql_server_info(true), '5.0.37', '>=') && version_compare($this->sql_server_info(true), '5.1', '<'))
- {
- $test_prof = true;
- }
- }
-
- switch ($mode)
- {
- case 'start':
-
- $explain_query = $query;
- if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
- {
- $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
- }
- else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
- {
- $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
- }
-
- if (preg_match('/^SELECT/', $explain_query))
- {
- $html_table = false;
-
- // begin profiling
- if ($test_prof)
- {
- @mysql_query('SET profiling = 1;', $this->db_connect_id);
- }
-
- if ($result = @mysql_query("EXPLAIN $explain_query", $this->db_connect_id))
- {
- while ($row = @mysql_fetch_assoc($result))
- {
- $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
- }
- }
- @mysql_free_result($result);
-
- if ($html_table)
- {
- $this->html_hold .= '</table>';
- }
-
- if ($test_prof)
- {
- $html_table = false;
-
- // get the last profile
- if ($result = @mysql_query('SHOW PROFILE ALL;', $this->db_connect_id))
- {
- $this->html_hold .= '<br />';
- while ($row = @mysql_fetch_assoc($result))
- {
- // make <unknown> HTML safe
- if (!empty($row['Source_function']))
- {
- $row['Source_function'] = str_replace(array('<', '>'), array('&lt;', '&gt;'), $row['Source_function']);
- }
-
- // remove unsupported features
- foreach ($row as $key => $val)
- {
- if ($val === null)
- {
- unset($row[$key]);
- }
- }
- $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
- }
- }
- @mysql_free_result($result);
-
- if ($html_table)
- {
- $this->html_hold .= '</table>';
- }
-
- @mysql_query('SET profiling = 0;', $this->db_connect_id);
- }
- }
-
- break;
-
- case 'fromcache':
- $endtime = explode(' ', microtime());
- $endtime = $endtime[0] + $endtime[1];
-
- $result = @mysql_query($query, $this->db_connect_id);
- while ($void = @mysql_fetch_assoc($result))
- {
- // Take the time spent on parsing rows into account
- }
- @mysql_free_result($result);
-
- $splittime = explode(' ', microtime());
- $splittime = $splittime[0] + $splittime[1];
-
- $this->sql_report('record_fromcache', $query, $endtime, $splittime);
-
- break;
- }
- }
-}
diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/mysqli.php
deleted file mode 100644
index 6d81b8bc3e..0000000000
--- a/phpBB/includes/db/mysqli.php
+++ /dev/null
@@ -1,568 +0,0 @@
-<?php
-/**
-*
-* @package dbal
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
-
-/**
-* MySQLi Database Abstraction Layer
-* mysqli-extension has to be compiled with:
-* MySQL 4.1+ or MySQL 5.0+
-* @package dbal
-*/
-class dbal_mysqli extends dbal
-{
- var $multi_insert = true;
-
- /**
- * Connect to server
- */
- function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false , $new_link = false)
- {
- // Mysqli extension supports persistent connection since PHP 5.3.0
- $this->persistency = (version_compare(PHP_VERSION, '5.3.0', '>=')) ? $persistency : false;
- $this->user = $sqluser;
-
- // If persistent connection, set dbhost to localhost when empty and prepend it with 'p:' prefix
- $this->server = ($this->persistency) ? 'p:' . (($sqlserver) ? $sqlserver : 'localhost') : $sqlserver;
-
- $this->dbname = $database;
- $port = (!$port) ? NULL : $port;
-
- // If port is set and it is not numeric, most likely mysqli socket is set.
- // Try to map it to the $socket parameter.
- $socket = NULL;
- if ($port)
- {
- if (is_numeric($port))
- {
- $port = (int) $port;
- }
- else
- {
- $socket = $port;
- $port = NULL;
- }
- }
-
- $this->db_connect_id = @mysqli_connect($this->server, $this->user, $sqlpassword, $this->dbname, $port, $socket);
-
- if ($this->db_connect_id && $this->dbname != '')
- {
- @mysqli_query($this->db_connect_id, "SET NAMES 'utf8'");
-
- // enforce strict mode on databases that support it
- if (version_compare($this->sql_server_info(true), '5.0.2', '>='))
- {
- $result = @mysqli_query($this->db_connect_id, 'SELECT @@session.sql_mode AS sql_mode');
- $row = @mysqli_fetch_assoc($result);
- @mysqli_free_result($result);
-
- $modes = array_map('trim', explode(',', $row['sql_mode']));
-
- // TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES
- if (!in_array('TRADITIONAL', $modes))
- {
- if (!in_array('STRICT_ALL_TABLES', $modes))
- {
- $modes[] = 'STRICT_ALL_TABLES';
- }
-
- if (!in_array('STRICT_TRANS_TABLES', $modes))
- {
- $modes[] = 'STRICT_TRANS_TABLES';
- }
- }
-
- $mode = implode(',', $modes);
- @mysqli_query($this->db_connect_id, "SET SESSION sql_mode='{$mode}'");
- }
- return $this->db_connect_id;
- }
-
- return $this->sql_error('');
- }
-
- /**
- * Version information about used database
- * @param bool $use_cache If true, it is safe to retrieve the value from the cache
- * @return string sql server version
- */
- function sql_server_info($raw = false, $use_cache = true)
- {
- global $cache;
-
- if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysqli_version')) === false)
- {
- $result = @mysqli_query($this->db_connect_id, 'SELECT VERSION() AS version');
- $row = @mysqli_fetch_assoc($result);
- @mysqli_free_result($result);
-
- $this->sql_server_version = $row['version'];
-
- if (!empty($cache) && $use_cache)
- {
- $cache->put('mysqli_version', $this->sql_server_version);
- }
- }
-
- return ($raw) ? $this->sql_server_version : 'MySQL(i) ' . $this->sql_server_version;
- }
-
- /**
- * {@inheritDoc}
- */
- public function sql_concatenate($expr1, $expr2)
- {
- return 'CONCAT(' . $expr1 . ', ' . $expr2 . ')';
- }
-
- /**
- * SQL Transaction
- * @access private
- */
- function _sql_transaction($status = 'begin')
- {
- switch ($status)
- {
- case 'begin':
- return @mysqli_autocommit($this->db_connect_id, false);
- break;
-
- case 'commit':
- $result = @mysqli_commit($this->db_connect_id);
- @mysqli_autocommit($this->db_connect_id, true);
- return $result;
- break;
-
- case 'rollback':
- $result = @mysqli_rollback($this->db_connect_id);
- @mysqli_autocommit($this->db_connect_id, true);
- return $result;
- break;
- }
-
- return true;
- }
-
- /**
- * Base query method
- *
- * @param string $query Contains the SQL query which shall be executed
- * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
- * @return mixed When casted to bool the returned value returns true on success and false on failure
- *
- * @access public
- */
- function sql_query($query = '', $cache_ttl = 0)
- {
- if ($query != '')
- {
- global $cache;
-
- // EXPLAIN only in extra debug mode
- if (defined('DEBUG'))
- {
- $this->sql_report('start', $query);
- }
-
- $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false;
- $this->sql_add_num_queries($this->query_result);
-
- if ($this->query_result === false)
- {
- if (($this->query_result = @mysqli_query($this->db_connect_id, $query)) === false)
- {
- $this->sql_error($query);
- }
-
- if (defined('DEBUG'))
- {
- $this->sql_report('stop', $query);
- }
-
- if ($cache_ttl)
- {
- $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl);
- }
- }
- else if (defined('DEBUG'))
- {
- $this->sql_report('fromcache', $query);
- }
- }
- else
- {
- return false;
- }
-
- return $this->query_result;
- }
-
- /**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- // if $total is set to 0 we do not want to limit the number of rows
- if ($total == 0)
- {
- // MySQL 4.1+ no longer supports -1 in limit queries
- $total = '18446744073709551615';
- }
-
- $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total);
-
- return $this->sql_query($query, $cache_ttl);
- }
-
- /**
- * Return number of affected rows
- */
- function sql_affectedrows()
- {
- return ($this->db_connect_id) ? @mysqli_affected_rows($this->db_connect_id) : false;
- }
-
- /**
- * Fetch current row
- */
- function sql_fetchrow($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if (!is_object($query_id) && $cache->sql_exists($query_id))
- {
- return $cache->sql_fetchrow($query_id);
- }
-
- if ($query_id !== false)
- {
- $result = @mysqli_fetch_assoc($query_id);
- return $result !== null ? $result : false;
- }
-
- return false;
- }
-
- /**
- * Seek to given row number
- * rownum is zero-based
- */
- function sql_rowseek($rownum, &$query_id)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if (!is_object($query_id) && $cache->sql_exists($query_id))
- {
- return $cache->sql_rowseek($rownum, $query_id);
- }
-
- return ($query_id !== false) ? @mysqli_data_seek($query_id, $rownum) : false;
- }
-
- /**
- * Get last inserted id after insert statement
- */
- function sql_nextid()
- {
- return ($this->db_connect_id) ? @mysqli_insert_id($this->db_connect_id) : false;
- }
-
- /**
- * Free sql result
- */
- function sql_freeresult($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if (!is_object($query_id) && $cache->sql_exists($query_id))
- {
- return $cache->sql_freeresult($query_id);
- }
-
- return @mysqli_free_result($query_id);
- }
-
- /**
- * Escape string used in sql query
- */
- function sql_escape($msg)
- {
- return @mysqli_real_escape_string($this->db_connect_id, $msg);
- }
-
- /**
- * Gets the estimated number of rows in a specified table.
- *
- * @param string $table_name Table name
- *
- * @return string Number of rows in $table_name.
- * Prefixed with ~ if estimated (otherwise exact).
- *
- * @access public
- */
- function get_estimated_row_count($table_name)
- {
- $table_status = $this->get_table_status($table_name);
-
- if (isset($table_status['Engine']))
- {
- if ($table_status['Engine'] === 'MyISAM')
- {
- return $table_status['Rows'];
- }
- else if ($table_status['Engine'] === 'InnoDB' && $table_status['Rows'] > 100000)
- {
- return '~' . $table_status['Rows'];
- }
- }
-
- return parent::get_row_count($table_name);
- }
-
- /**
- * Gets the exact number of rows in a specified table.
- *
- * @param string $table_name Table name
- *
- * @return string Exact number of rows in $table_name.
- *
- * @access public
- */
- function get_row_count($table_name)
- {
- $table_status = $this->get_table_status($table_name);
-
- if (isset($table_status['Engine']) && $table_status['Engine'] === 'MyISAM')
- {
- return $table_status['Rows'];
- }
-
- return parent::get_row_count($table_name);
- }
-
- /**
- * Gets some information about the specified table.
- *
- * @param string $table_name Table name
- *
- * @return array
- *
- * @access protected
- */
- function get_table_status($table_name)
- {
- $sql = "SHOW TABLE STATUS
- LIKE '" . $this->sql_escape($table_name) . "'";
- $result = $this->sql_query($sql);
- $table_status = $this->sql_fetchrow($result);
- $this->sql_freeresult($result);
-
- return $table_status;
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression;
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- switch ($stage)
- {
- case 'FROM':
- $data = '(' . $data . ')';
- break;
- }
-
- return $data;
- }
-
- /**
- * return sql error array
- * @access private
- */
- function _sql_error()
- {
- if (!$this->db_connect_id)
- {
- return array(
- 'message' => @mysqli_connect_error(),
- 'code' => @mysqli_connect_errno()
- );
- }
-
- return array(
- 'message' => @mysqli_error($this->db_connect_id),
- 'code' => @mysqli_errno($this->db_connect_id)
- );
- }
-
- /**
- * Close sql connection
- * @access private
- */
- function _sql_close()
- {
- return @mysqli_close($this->db_connect_id);
- }
-
- /**
- * Build db-specific report
- * @access private
- */
- function _sql_report($mode, $query = '')
- {
- static $test_prof;
-
- // current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING
- if ($test_prof === null)
- {
- $test_prof = false;
- if (strpos(mysqli_get_server_info($this->db_connect_id), 'community') !== false)
- {
- $ver = mysqli_get_server_version($this->db_connect_id);
- if ($ver >= 50037 && $ver < 50100)
- {
- $test_prof = true;
- }
- }
- }
-
- switch ($mode)
- {
- case 'start':
-
- $explain_query = $query;
- if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
- {
- $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
- }
- else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
- {
- $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
- }
-
- if (preg_match('/^SELECT/', $explain_query))
- {
- $html_table = false;
-
- // begin profiling
- if ($test_prof)
- {
- @mysqli_query($this->db_connect_id, 'SET profiling = 1;');
- }
-
- if ($result = @mysqli_query($this->db_connect_id, "EXPLAIN $explain_query"))
- {
- while ($row = @mysqli_fetch_assoc($result))
- {
- $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
- }
- }
- @mysqli_free_result($result);
-
- if ($html_table)
- {
- $this->html_hold .= '</table>';
- }
-
- if ($test_prof)
- {
- $html_table = false;
-
- // get the last profile
- if ($result = @mysqli_query($this->db_connect_id, 'SHOW PROFILE ALL;'))
- {
- $this->html_hold .= '<br />';
- while ($row = @mysqli_fetch_assoc($result))
- {
- // make <unknown> HTML safe
- if (!empty($row['Source_function']))
- {
- $row['Source_function'] = str_replace(array('<', '>'), array('&lt;', '&gt;'), $row['Source_function']);
- }
-
- // remove unsupported features
- foreach ($row as $key => $val)
- {
- if ($val === null)
- {
- unset($row[$key]);
- }
- }
- $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
- }
- }
- @mysqli_free_result($result);
-
- if ($html_table)
- {
- $this->html_hold .= '</table>';
- }
-
- @mysqli_query($this->db_connect_id, 'SET profiling = 0;');
- }
- }
-
- break;
-
- case 'fromcache':
- $endtime = explode(' ', microtime());
- $endtime = $endtime[0] + $endtime[1];
-
- $result = @mysqli_query($this->db_connect_id, $query);
- while ($void = @mysqli_fetch_assoc($result))
- {
- // Take the time spent on parsing rows into account
- }
- @mysqli_free_result($result);
-
- $splittime = explode(' ', microtime());
- $splittime = $splittime[0] + $splittime[1];
-
- $this->sql_report('record_fromcache', $query, $endtime, $splittime);
-
- break;
- }
- }
-}
diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/oracle.php
deleted file mode 100644
index 6d9339b2d8..0000000000
--- a/phpBB/includes/db/oracle.php
+++ /dev/null
@@ -1,768 +0,0 @@
-<?php
-/**
-*
-* @package dbal
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
-
-/**
-* Oracle Database Abstraction Layer
-* @package dbal
-*/
-class dbal_oracle extends dbal
-{
- var $last_query_text = '';
-
- /**
- * Connect to server
- */
- function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
- {
- $this->persistency = $persistency;
- $this->user = $sqluser;
- $this->server = $sqlserver . (($port) ? ':' . $port : '');
- $this->dbname = $database;
-
- $connect = $database;
-
- // support for "easy connect naming"
- if ($sqlserver !== '' && $sqlserver !== '/')
- {
- if (substr($sqlserver, -1, 1) == '/')
- {
- $sqlserver == substr($sqlserver, 0, -1);
- }
- $connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database;
- }
-
- $this->db_connect_id = ($new_link) ? @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8') : (($this->persistency) ? @ociplogon($this->user, $sqlpassword, $connect, 'UTF8') : @ocilogon($this->user, $sqlpassword, $connect, 'UTF8'));
-
- return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
- }
-
- /**
- * Version information about used database
- * @param bool $raw if true, only return the fetched sql_server_version
- * @param bool $use_cache forced to false for Oracle
- * @return string sql server version
- */
- function sql_server_info($raw = false, $use_cache = true)
- {
- /**
- * force $use_cache false. I didn't research why the caching code below is commented out
- * but I assume its because the Oracle extension provides a direct method to access it
- * without a query.
- */
-
- $use_cache = false;
-/*
- global $cache;
-
- if (empty($cache) || ($this->sql_server_version = $cache->get('oracle_version')) === false)
- {
- $result = @ociparse($this->db_connect_id, 'SELECT * FROM v$version WHERE banner LIKE \'Oracle%\'');
- @ociexecute($result, OCI_DEFAULT);
- @ocicommit($this->db_connect_id);
-
- $row = array();
- @ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS);
- @ocifreestatement($result);
- $this->sql_server_version = trim($row['BANNER']);
-
- $cache->put('oracle_version', $this->sql_server_version);
- }
-*/
- $this->sql_server_version = @ociserverversion($this->db_connect_id);
-
- return $this->sql_server_version;
- }
-
- /**
- * SQL Transaction
- * @access private
- */
- function _sql_transaction($status = 'begin')
- {
- switch ($status)
- {
- case 'begin':
- return true;
- break;
-
- case 'commit':
- return @ocicommit($this->db_connect_id);
- break;
-
- case 'rollback':
- return @ocirollback($this->db_connect_id);
- break;
- }
-
- return true;
- }
-
- /**
- * Oracle specific code to handle the fact that it does not compare columns properly
- * @access private
- */
- function _rewrite_col_compare($args)
- {
- if (sizeof($args) == 4)
- {
- if ($args[2] == '=')
- {
- return '(' . $args[0] . ' OR (' . $args[1] . ' is NULL AND ' . $args[3] . ' is NULL))';
- }
- else if ($args[2] == '<>')
- {
- // really just a fancy way of saying foo <> bar or (foo is NULL XOR bar is NULL) but SQL has no XOR :P
- return '(' . $args[0] . ' OR ((' . $args[1] . ' is NULL AND ' . $args[3] . ' is NOT NULL) OR (' . $args[1] . ' is NOT NULL AND ' . $args[3] . ' is NULL)))';
- }
- }
- else
- {
- return $this->_rewrite_where($args[0]);
- }
- }
-
- /**
- * Oracle specific code to handle it's lack of sanity
- * @access private
- */
- function _rewrite_where($where_clause)
- {
- preg_match_all('/\s*(AND|OR)?\s*([\w_.()]++)\s*(?:(=|<[=>]?|>=?|LIKE)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d-.()]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER);
- $out = '';
- foreach ($result as $val)
- {
- if (!isset($val[5]))
- {
- if ($val[4] !== "''")
- {
- $out .= $val[0];
- }
- else
- {
- $out .= ' ' . $val[1] . ' ' . $val[2];
- if ($val[3] == '=')
- {
- $out .= ' is NULL';
- }
- else if ($val[3] == '<>')
- {
- $out .= ' is NOT NULL';
- }
- }
- }
- else
- {
- $in_clause = array();
- $sub_exp = substr($val[5], strpos($val[5], '(') + 1, -1);
- $extra = false;
- preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER);
- $i = 0;
- foreach ($sub_vals[0] as $sub_val)
- {
- // two things:
- // 1) This determines if an empty string was in the IN clausing, making us turn it into a NULL comparison
- // 2) This fixes the 1000 list limit that Oracle has (ORA-01795)
- if ($sub_val !== "''")
- {
- $in_clause[(int) $i++/1000][] = $sub_val;
- }
- else
- {
- $extra = true;
- }
- }
- if (!$extra && $i < 1000)
- {
- $out .= $val[0];
- }
- else
- {
- $out .= ' ' . $val[1] . '(';
- $in_array = array();
-
- // constuct each IN() clause
- foreach ($in_clause as $in_values)
- {
- $in_array[] = $val[2] . ' ' . (isset($val[6]) ? $val[6] : '') . 'IN(' . implode(', ', $in_values) . ')';
- }
-
- // Join the IN() clauses against a few ORs (IN is just a nicer OR anyway)
- $out .= implode(' OR ', $in_array);
-
- // handle the empty string case
- if ($extra)
- {
- $out .= ' OR ' . $val[2] . ' is ' . (isset($val[6]) ? $val[6] : '') . 'NULL';
- }
- $out .= ')';
-
- unset($in_array, $in_clause);
- }
- }
- }
-
- return $out;
- }
-
- /**
- * Base query method
- *
- * @param string $query Contains the SQL query which shall be executed
- * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
- * @return mixed When casted to bool the returned value returns true on success and false on failure
- *
- * @access public
- */
- function sql_query($query = '', $cache_ttl = 0)
- {
- if ($query != '')
- {
- global $cache;
-
- // EXPLAIN only in extra debug mode
- if (defined('DEBUG'))
- {
- $this->sql_report('start', $query);
- }
-
- $this->last_query_text = $query;
- $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false;
- $this->sql_add_num_queries($this->query_result);
-
- if ($this->query_result === false)
- {
- $in_transaction = false;
- if (!$this->transaction)
- {
- $this->sql_transaction('begin');
- }
- else
- {
- $in_transaction = true;
- }
-
- $array = array();
-
- // We overcome Oracle's 4000 char limit by binding vars
- if (strlen($query) > 4000)
- {
- if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/sU', $query, $regs))
- {
- if (strlen($regs[3]) > 4000)
- {
- $cols = explode(', ', $regs[2]);
-
- preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER);
-
-/* The code inside this comment block breaks clob handling, but does allow the
- database restore script to work. If you want to allow no posts longer than 4KB
- and/or need the db restore script, uncomment this.
-
-
- if (sizeof($cols) !== sizeof($vals))
- {
- // Try to replace some common data we know is from our restore script or from other sources
- $regs[3] = str_replace("'||chr(47)||'", '/', $regs[3]);
- $_vals = explode(', ', $regs[3]);
-
- $vals = array();
- $is_in_val = false;
- $i = 0;
- $string = '';
-
- foreach ($_vals as $value)
- {
- if (strpos($value, "'") === false && !$is_in_val)
- {
- $vals[$i++] = $value;
- continue;
- }
-
- if (substr($value, -1) === "'")
- {
- $vals[$i] = $string . (($is_in_val) ? ', ' : '') . $value;
- $string = '';
- $is_in_val = false;
-
- if ($vals[$i][0] !== "'")
- {
- $vals[$i] = "''" . $vals[$i];
- }
- $i++;
- continue;
- }
- else
- {
- $string .= (($is_in_val) ? ', ' : '') . $value;
- $is_in_val = true;
- }
- }
-
- if ($string)
- {
- // New value if cols != value
- $vals[(sizeof($cols) !== sizeof($vals)) ? $i : $i - 1] .= $string;
- }
-
- $vals = array(0 => $vals);
- }
-*/
-
- $inserts = $vals[0];
- unset($vals);
-
- foreach ($inserts as $key => $value)
- {
- if (!empty($value) && $value[0] === "'" && strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2
- {
- $inserts[$key] = ':' . strtoupper($cols[$key]);
- $array[$inserts[$key]] = str_replace("''", "'", substr($value, 1, -1));
- }
- }
-
- $query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')';
- }
- }
- else if (preg_match_all('/^(UPDATE [\\w_]++\\s+SET )([\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+)(?:,\\s*[\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+)\\s+(WHERE.*)$/s', $query, $data, PREG_SET_ORDER))
- {
- if (strlen($data[0][2]) > 4000)
- {
- $update = $data[0][1];
- $where = $data[0][3];
- preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[0][2], $temp, PREG_SET_ORDER);
- unset($data);
-
- $cols = array();
- foreach ($temp as $value)
- {
- if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 4002) // check to see if this thing is greater than the max + 'x2
- {
- $cols[] = $value[1] . '=:' . strtoupper($value[1]);
- $array[$value[1]] = str_replace("''", "'", substr($value[2], 1, -1));
- }
- else
- {
- $cols[] = $value[1] . '=' . $value[2];
- }
- }
-
- $query = $update . implode(', ', $cols) . ' ' . $where;
- unset($cols);
- }
- }
- }
-
- switch (substr($query, 0, 6))
- {
- case 'DELETE':
- if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))*+)$/', $query, $regs))
- {
- $query = $regs[1] . $this->_rewrite_where($regs[2]);
- unset($regs);
- }
- break;
-
- case 'UPDATE':
- if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++))*+\\s+WHERE)(.*)$/s', $query, $regs))
- {
- $query = $regs[1] . $this->_rewrite_where($regs[2]);
- unset($regs);
- }
- break;
-
- case 'SELECT':
- $query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query);
- break;
- }
-
- $this->query_result = @ociparse($this->db_connect_id, $query);
-
- foreach ($array as $key => $value)
- {
- @ocibindbyname($this->query_result, $key, $array[$key], -1);
- }
-
- $success = @ociexecute($this->query_result, OCI_DEFAULT);
-
- if (!$success)
- {
- $this->sql_error($query);
- $this->query_result = false;
- }
- else
- {
- if (!$in_transaction)
- {
- $this->sql_transaction('commit');
- }
- }
-
- if (defined('DEBUG'))
- {
- $this->sql_report('stop', $query);
- }
-
- if ($cache_ttl)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl);
- }
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- }
- }
- else if (defined('DEBUG'))
- {
- $this->sql_report('fromcache', $query);
- }
- }
- else
- {
- return false;
- }
-
- return $this->query_result;
- }
-
- /**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- $query = 'SELECT * FROM (SELECT /*+ FIRST_ROWS */ rownum AS xrownum, a.* FROM (' . $query . ') a WHERE rownum <= ' . ($offset + $total) . ') WHERE xrownum >= ' . $offset;
-
- return $this->sql_query($query, $cache_ttl);
- }
-
- /**
- * Return number of affected rows
- */
- function sql_affectedrows()
- {
- return ($this->query_result) ? @ocirowcount($this->query_result) : false;
- }
-
- /**
- * Fetch current row
- */
- function sql_fetchrow($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_fetchrow($query_id);
- }
-
- if ($query_id !== false)
- {
- $row = array();
- $result = @ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS);
-
- if (!$result || !$row)
- {
- return false;
- }
-
- $result_row = array();
- foreach ($row as $key => $value)
- {
- // Oracle treats empty strings as null
- if (is_null($value))
- {
- $value = '';
- }
-
- // OCI->CLOB?
- if (is_object($value))
- {
- $value = $value->load();
- }
-
- $result_row[strtolower($key)] = $value;
- }
-
- return $result_row;
- }
-
- return false;
- }
-
- /**
- * Seek to given row number
- * rownum is zero-based
- */
- function sql_rowseek($rownum, &$query_id)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_rowseek($rownum, $query_id);
- }
-
- if ($query_id === false)
- {
- return false;
- }
-
- // Reset internal pointer
- @ociexecute($query_id, OCI_DEFAULT);
-
- // We do not fetch the row for rownum == 0 because then the next resultset would be the second row
- for ($i = 0; $i < $rownum; $i++)
- {
- if (!$this->sql_fetchrow($query_id))
- {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Get last inserted id after insert statement
- */
- function sql_nextid()
- {
- $query_id = $this->query_result;
-
- if ($query_id !== false && $this->last_query_text != '')
- {
- if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename))
- {
- $query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL';
- $stmt = @ociparse($this->db_connect_id, $query);
- @ociexecute($stmt, OCI_DEFAULT);
-
- $temp_result = @ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS);
- @ocifreestatement($stmt);
-
- if ($temp_result)
- {
- return $temp_array['CURRVAL'];
- }
- else
- {
- return false;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Free sql result
- */
- function sql_freeresult($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_freeresult($query_id);
- }
-
- if (isset($this->open_queries[(int) $query_id]))
- {
- unset($this->open_queries[(int) $query_id]);
- return @ocifreestatement($query_id);
- }
-
- return false;
- }
-
- /**
- * Escape string used in sql query
- */
- function sql_escape($msg)
- {
- return str_replace(array("'", "\0"), array("''", ''), $msg);
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression . " ESCAPE '\\'";
- }
-
- function _sql_custom_build($stage, $data)
- {
- return $data;
- }
-
- function _sql_bit_and($column_name, $bit, $compare = '')
- {
- return 'BITAND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : '');
- }
-
- function _sql_bit_or($column_name, $bit, $compare = '')
- {
- return 'BITOR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : '');
- }
-
- /**
- * return sql error array
- * @access private
- */
- function _sql_error()
- {
- $error = @ocierror();
- $error = (!$error) ? @ocierror($this->query_result) : $error;
- $error = (!$error) ? @ocierror($this->db_connect_id) : $error;
-
- if ($error)
- {
- $this->last_error_result = $error;
- }
- else
- {
- $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array();
- }
-
- return $error;
- }
-
- /**
- * Close sql connection
- * @access private
- */
- function _sql_close()
- {
- return @ocilogoff($this->db_connect_id);
- }
-
- /**
- * Build db-specific report
- * @access private
- */
- function _sql_report($mode, $query = '')
- {
- switch ($mode)
- {
- case 'start':
-
- $html_table = false;
-
- // Grab a plan table, any will do
- $sql = "SELECT table_name
- FROM USER_TABLES
- WHERE table_name LIKE '%PLAN_TABLE%'";
- $stmt = ociparse($this->db_connect_id, $sql);
- ociexecute($stmt);
- $result = array();
-
- if (ocifetchinto($stmt, $result, OCI_ASSOC + OCI_RETURN_NULLS))
- {
- $table = $result['TABLE_NAME'];
-
- // This is the statement_id that will allow us to track the plan
- $statement_id = substr(md5($query), 0, 30);
-
- // Remove any stale plans
- $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'");
- ociexecute($stmt2);
- ocifreestatement($stmt2);
-
- // Explain the plan
- $sql = "EXPLAIN PLAN
- SET STATEMENT_ID = '$statement_id'
- FOR $query";
- $stmt2 = ociparse($this->db_connect_id, $sql);
- ociexecute($stmt2);
- ocifreestatement($stmt2);
-
- // Get the data from the plan
- $sql = "SELECT operation, options, object_name, object_type, cardinality, cost
- FROM plan_table
- START WITH id = 0 AND statement_id = '$statement_id'
- CONNECT BY PRIOR id = parent_id
- AND statement_id = '$statement_id'";
- $stmt2 = ociparse($this->db_connect_id, $sql);
- ociexecute($stmt2);
-
- $row = array();
- while (ocifetchinto($stmt2, $row, OCI_ASSOC + OCI_RETURN_NULLS))
- {
- $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
- }
-
- ocifreestatement($stmt2);
-
- // Remove the plan we just made, we delete them on request anyway
- $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'");
- ociexecute($stmt2);
- ocifreestatement($stmt2);
- }
-
- ocifreestatement($stmt);
-
- if ($html_table)
- {
- $this->html_hold .= '</table>';
- }
-
- break;
-
- case 'fromcache':
- $endtime = explode(' ', microtime());
- $endtime = $endtime[0] + $endtime[1];
-
- $result = @ociparse($this->db_connect_id, $query);
- $success = @ociexecute($result, OCI_DEFAULT);
- $row = array();
-
- while (@ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS))
- {
- // Take the time spent on parsing rows into account
- }
- @ocifreestatement($result);
-
- $splittime = explode(' ', microtime());
- $splittime = $splittime[0] + $splittime[1];
-
- $this->sql_report('record_fromcache', $query, $endtime, $splittime);
-
- break;
- }
- }
-}
diff --git a/phpBB/includes/db/postgres.php b/phpBB/includes/db/postgres.php
deleted file mode 100644
index 8dfbfc3b60..0000000000
--- a/phpBB/includes/db/postgres.php
+++ /dev/null
@@ -1,498 +0,0 @@
-<?php
-/**
-*
-* @package dbal
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
-
-if (!class_exists('phpbb_error_collector'))
-{
- include($phpbb_root_path . 'includes/error_collector.' . $phpEx);
-}
-
-/**
-* PostgreSQL Database Abstraction Layer
-* Minimum Requirement is Version 7.3+
-* @package dbal
-*/
-class dbal_postgres extends dbal
-{
- var $last_query_text = '';
- var $connect_error = '';
-
- /**
- * Connect to server
- */
- function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
- {
- $connect_string = '';
-
- if ($sqluser)
- {
- $connect_string .= "user=$sqluser ";
- }
-
- if ($sqlpassword)
- {
- $connect_string .= "password=$sqlpassword ";
- }
-
- if ($sqlserver)
- {
- // $sqlserver can carry a port separated by : for compatibility reasons
- // If $sqlserver has more than one : it's probably an IPv6 address.
- // In this case we only allow passing a port via the $port variable.
- if (substr_count($sqlserver, ':') === 1)
- {
- list($sqlserver, $port) = explode(':', $sqlserver);
- }
-
- if ($sqlserver !== 'localhost')
- {
- $connect_string .= "host=$sqlserver ";
- }
-
- if ($port)
- {
- $connect_string .= "port=$port ";
- }
- }
-
- $schema = '';
-
- if ($database)
- {
- $this->dbname = $database;
- if (strpos($database, '.') !== false)
- {
- list($database, $schema) = explode('.', $database);
- }
- $connect_string .= "dbname=$database";
- }
-
- $this->persistency = $persistency;
-
- if ($this->persistency)
- {
- if (!function_exists('pg_pconnect'))
- {
- $this->connect_error = 'pg_pconnect function does not exist, is pgsql extension installed?';
- return $this->sql_error('');
- }
- $collector = new phpbb_error_collector;
- $collector->install();
- $this->db_connect_id = (!$new_link) ? @pg_pconnect($connect_string) : @pg_pconnect($connect_string, PGSQL_CONNECT_FORCE_NEW);
- }
- else
- {
- if (!function_exists('pg_connect'))
- {
- $this->connect_error = 'pg_connect function does not exist, is pgsql extension installed?';
- return $this->sql_error('');
- }
- $collector = new phpbb_error_collector;
- $collector->install();
- $this->db_connect_id = (!$new_link) ? @pg_connect($connect_string) : @pg_connect($connect_string, PGSQL_CONNECT_FORCE_NEW);
- }
-
- $collector->uninstall();
-
- if ($this->db_connect_id)
- {
- if (version_compare($this->sql_server_info(true), '8.2', '>='))
- {
- $this->multi_insert = true;
- }
-
- if ($schema !== '')
- {
- @pg_query($this->db_connect_id, 'SET search_path TO ' . $schema);
- }
- return $this->db_connect_id;
- }
-
- $this->connect_error = $collector->format_errors();
- return $this->sql_error('');
- }
-
- /**
- * Version information about used database
- * @param bool $raw if true, only return the fetched sql_server_version
- * @param bool $use_cache If true, it is safe to retrieve the value from the cache
- * @return string sql server version
- */
- function sql_server_info($raw = false, $use_cache = true)
- {
- global $cache;
-
- if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('pgsql_version')) === false)
- {
- $query_id = @pg_query($this->db_connect_id, 'SELECT VERSION() AS version');
- $row = @pg_fetch_assoc($query_id, null);
- @pg_free_result($query_id);
-
- $this->sql_server_version = (!empty($row['version'])) ? trim(substr($row['version'], 10)) : 0;
-
- if (!empty($cache) && $use_cache)
- {
- $cache->put('pgsql_version', $this->sql_server_version);
- }
- }
-
- return ($raw) ? $this->sql_server_version : 'PostgreSQL ' . $this->sql_server_version;
- }
-
- /**
- * SQL Transaction
- * @access private
- */
- function _sql_transaction($status = 'begin')
- {
- switch ($status)
- {
- case 'begin':
- return @pg_query($this->db_connect_id, 'BEGIN');
- break;
-
- case 'commit':
- return @pg_query($this->db_connect_id, 'COMMIT');
- break;
-
- case 'rollback':
- return @pg_query($this->db_connect_id, 'ROLLBACK');
- break;
- }
-
- return true;
- }
-
- /**
- * Base query method
- *
- * @param string $query Contains the SQL query which shall be executed
- * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
- * @return mixed When casted to bool the returned value returns true on success and false on failure
- *
- * @access public
- */
- function sql_query($query = '', $cache_ttl = 0)
- {
- if ($query != '')
- {
- global $cache;
-
- // EXPLAIN only in extra debug mode
- if (defined('DEBUG'))
- {
- $this->sql_report('start', $query);
- }
-
- $this->last_query_text = $query;
- $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false;
- $this->sql_add_num_queries($this->query_result);
-
- if ($this->query_result === false)
- {
- if (($this->query_result = @pg_query($this->db_connect_id, $query)) === false)
- {
- $this->sql_error($query);
- }
-
- if (defined('DEBUG'))
- {
- $this->sql_report('stop', $query);
- }
-
- if ($cache_ttl)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl);
- }
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- }
- }
- else if (defined('DEBUG'))
- {
- $this->sql_report('fromcache', $query);
- }
- }
- else
- {
- return false;
- }
-
- return $this->query_result;
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- return $data;
- }
-
- /**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- // if $total is set to 0 we do not want to limit the number of rows
- if ($total == 0)
- {
- $total = 'ALL';
- }
-
- $query .= "\n LIMIT $total OFFSET $offset";
-
- return $this->sql_query($query, $cache_ttl);
- }
-
- /**
- * Return number of affected rows
- */
- function sql_affectedrows()
- {
- return ($this->query_result) ? @pg_affected_rows($this->query_result) : false;
- }
-
- /**
- * Fetch current row
- */
- function sql_fetchrow($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_fetchrow($query_id);
- }
-
- return ($query_id !== false) ? @pg_fetch_assoc($query_id, null) : false;
- }
-
- /**
- * Seek to given row number
- * rownum is zero-based
- */
- function sql_rowseek($rownum, &$query_id)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_rowseek($rownum, $query_id);
- }
-
- return ($query_id !== false) ? @pg_result_seek($query_id, $rownum) : false;
- }
-
- /**
- * Get last inserted id after insert statement
- */
- function sql_nextid()
- {
- $query_id = $this->query_result;
-
- if ($query_id !== false && $this->last_query_text != '')
- {
- if (preg_match("/^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)/is", $this->last_query_text, $tablename))
- {
- $query = "SELECT currval('" . $tablename[1] . "_seq') AS last_value";
- $temp_q_id = @pg_query($this->db_connect_id, $query);
-
- if (!$temp_q_id)
- {
- return false;
- }
-
- $temp_result = @pg_fetch_assoc($temp_q_id, NULL);
- @pg_free_result($query_id);
-
- return ($temp_result) ? $temp_result['last_value'] : false;
- }
- }
-
- return false;
- }
-
- /**
- * Free sql result
- */
- function sql_freeresult($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_freeresult($query_id);
- }
-
- if (isset($this->open_queries[(int) $query_id]))
- {
- unset($this->open_queries[(int) $query_id]);
- return @pg_free_result($query_id);
- }
-
- return false;
- }
-
- /**
- * Escape string used in sql query
- * Note: Do not use for bytea values if we may use them at a later stage
- */
- function sql_escape($msg)
- {
- return @pg_escape_string($msg);
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression;
- }
-
- /**
- * @inheritdoc
- */
- function cast_expr_to_bigint($expression)
- {
- return 'CAST(' . $expression . ' as DECIMAL(255, 0))';
- }
-
- /**
- * @inheritdoc
- */
- function cast_expr_to_string($expression)
- {
- return 'CAST(' . $expression . ' as VARCHAR(255))';
- }
-
- /**
- * return sql error array
- * @access private
- */
- function _sql_error()
- {
- // pg_last_error only works when there is an established connection.
- // Connection errors have to be tracked by us manually.
- if ($this->db_connect_id)
- {
- $message = @pg_last_error($this->db_connect_id);
- }
- else
- {
- $message = $this->connect_error;
- }
-
- return array(
- 'message' => $message,
- 'code' => ''
- );
- }
-
- /**
- * Close sql connection
- * @access private
- */
- function _sql_close()
- {
- return @pg_close($this->db_connect_id);
- }
-
- /**
- * Build db-specific report
- * @access private
- */
- function _sql_report($mode, $query = '')
- {
- switch ($mode)
- {
- case 'start':
-
- $explain_query = $query;
- if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
- {
- $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
- }
- else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
- {
- $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
- }
-
- if (preg_match('/^SELECT/', $explain_query))
- {
- $html_table = false;
-
- if ($result = @pg_query($this->db_connect_id, "EXPLAIN $explain_query"))
- {
- while ($row = @pg_fetch_assoc($result, NULL))
- {
- $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
- }
- }
- @pg_free_result($result);
-
- if ($html_table)
- {
- $this->html_hold .= '</table>';
- }
- }
-
- break;
-
- case 'fromcache':
- $endtime = explode(' ', microtime());
- $endtime = $endtime[0] + $endtime[1];
-
- $result = @pg_query($this->db_connect_id, $query);
- while ($void = @pg_fetch_assoc($result, NULL))
- {
- // Take the time spent on parsing rows into account
- }
- @pg_free_result($result);
-
- $splittime = explode(' ', microtime());
- $splittime = $splittime[0] + $splittime[1];
-
- $this->sql_report('record_fromcache', $query, $endtime, $splittime);
-
- break;
- }
- }
-}
diff --git a/phpBB/includes/db/schema_data.php b/phpBB/includes/db/schema_data.php
new file mode 100644
index 0000000000..9940a9380f
--- /dev/null
+++ b/phpBB/includes/db/schema_data.php
@@ -0,0 +1,1194 @@
+<?php
+/**
+*
+* @package dbal
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+$schema_data = array();
+
+/**
+* Define the basic structure
+* The format:
+* array('{TABLE_NAME}' => {TABLE_DATA})
+* {TABLE_DATA}:
+* COLUMNS = array({column_name} = array({column_type}, {default}, {auto_increment}))
+* PRIMARY_KEY = {column_name(s)}
+* KEYS = array({key_name} = array({key_type}, {column_name(s)})),
+*
+* Column Types:
+* INT:x => SIGNED int(x)
+* BINT => BIGINT
+* UINT => mediumint(8) UNSIGNED
+* UINT:x => int(x) UNSIGNED
+* TINT:x => tinyint(x)
+* USINT => smallint(4) UNSIGNED (for _order columns)
+* BOOL => tinyint(1) UNSIGNED
+* VCHAR => varchar(255)
+* CHAR:x => char(x)
+* XSTEXT_UNI => text for storing 100 characters (topic_title for example)
+* STEXT_UNI => text for storing 255 characters (normal input field with a max of 255 single-byte chars) - same as VCHAR_UNI
+* TEXT_UNI => text for storing 3000 characters (short text, descriptions, comments, etc.)
+* MTEXT_UNI => mediumtext (post text, large text)
+* VCHAR:x => varchar(x)
+* TIMESTAMP => int(11) UNSIGNED
+* DECIMAL => decimal number (5,2)
+* DECIMAL: => decimal number (x,2)
+* PDECIMAL => precision decimal number (6,3)
+* PDECIMAL: => precision decimal number (x,3)
+* VCHAR_UNI => varchar(255) BINARY
+* VCHAR_CI => varchar_ci for postgresql, others VCHAR
+*/
+$schema_data['phpbb_attachments'] = array(
+ 'COLUMNS' => array(
+ 'attach_id' => array('UINT', NULL, 'auto_increment'),
+ 'post_msg_id' => array('UINT', 0),
+ 'topic_id' => array('UINT', 0),
+ 'in_message' => array('BOOL', 0),
+ 'poster_id' => array('UINT', 0),
+ 'is_orphan' => array('BOOL', 1),
+ 'physical_filename' => array('VCHAR', ''),
+ 'real_filename' => array('VCHAR', ''),
+ 'download_count' => array('UINT', 0),
+ 'attach_comment' => array('TEXT_UNI', ''),
+ 'extension' => array('VCHAR:100', ''),
+ 'mimetype' => array('VCHAR:100', ''),
+ 'filesize' => array('UINT:20', 0),
+ 'filetime' => array('TIMESTAMP', 0),
+ 'thumbnail' => array('BOOL', 0),
+ ),
+ 'PRIMARY_KEY' => 'attach_id',
+ 'KEYS' => array(
+ 'filetime' => array('INDEX', 'filetime'),
+ 'post_msg_id' => array('INDEX', 'post_msg_id'),
+ 'topic_id' => array('INDEX', 'topic_id'),
+ 'poster_id' => array('INDEX', 'poster_id'),
+ 'is_orphan' => array('INDEX', 'is_orphan'),
+ ),
+);
+
+$schema_data['phpbb_acl_groups'] = array(
+ 'COLUMNS' => array(
+ 'group_id' => array('UINT', 0),
+ 'forum_id' => array('UINT', 0),
+ 'auth_option_id' => array('UINT', 0),
+ 'auth_role_id' => array('UINT', 0),
+ 'auth_setting' => array('TINT:2', 0),
+ ),
+ 'KEYS' => array(
+ 'group_id' => array('INDEX', 'group_id'),
+ 'auth_opt_id' => array('INDEX', 'auth_option_id'),
+ 'auth_role_id' => array('INDEX', 'auth_role_id'),
+ ),
+);
+
+$schema_data['phpbb_acl_options'] = array(
+ 'COLUMNS' => array(
+ 'auth_option_id' => array('UINT', NULL, 'auto_increment'),
+ 'auth_option' => array('VCHAR:50', ''),
+ 'is_global' => array('BOOL', 0),
+ 'is_local' => array('BOOL', 0),
+ 'founder_only' => array('BOOL', 0),
+ ),
+ 'PRIMARY_KEY' => 'auth_option_id',
+ 'KEYS' => array(
+ 'auth_option' => array('UNIQUE', 'auth_option'),
+ ),
+);
+
+$schema_data['phpbb_acl_roles'] = array(
+ 'COLUMNS' => array(
+ 'role_id' => array('UINT', NULL, 'auto_increment'),
+ 'role_name' => array('VCHAR_UNI', ''),
+ 'role_description' => array('TEXT_UNI', ''),
+ 'role_type' => array('VCHAR:10', ''),
+ 'role_order' => array('USINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'role_id',
+ 'KEYS' => array(
+ 'role_type' => array('INDEX', 'role_type'),
+ 'role_order' => array('INDEX', 'role_order'),
+ ),
+);
+
+$schema_data['phpbb_acl_roles_data'] = array(
+ 'COLUMNS' => array(
+ 'role_id' => array('UINT', 0),
+ 'auth_option_id' => array('UINT', 0),
+ 'auth_setting' => array('TINT:2', 0),
+ ),
+ 'PRIMARY_KEY' => array('role_id', 'auth_option_id'),
+ 'KEYS' => array(
+ 'ath_op_id' => array('INDEX', 'auth_option_id'),
+ ),
+);
+
+$schema_data['phpbb_acl_users'] = array(
+ 'COLUMNS' => array(
+ 'user_id' => array('UINT', 0),
+ 'forum_id' => array('UINT', 0),
+ 'auth_option_id' => array('UINT', 0),
+ 'auth_role_id' => array('UINT', 0),
+ 'auth_setting' => array('TINT:2', 0),
+ ),
+ 'KEYS' => array(
+ 'user_id' => array('INDEX', 'user_id'),
+ 'auth_option_id' => array('INDEX', 'auth_option_id'),
+ 'auth_role_id' => array('INDEX', 'auth_role_id'),
+ ),
+);
+
+$schema_data['phpbb_banlist'] = array(
+ 'COLUMNS' => array(
+ 'ban_id' => array('UINT', NULL, 'auto_increment'),
+ 'ban_userid' => array('UINT', 0),
+ 'ban_ip' => array('VCHAR:40', ''),
+ 'ban_email' => array('VCHAR_UNI:100', ''),
+ 'ban_start' => array('TIMESTAMP', 0),
+ 'ban_end' => array('TIMESTAMP', 0),
+ 'ban_exclude' => array('BOOL', 0),
+ 'ban_reason' => array('VCHAR_UNI', ''),
+ 'ban_give_reason' => array('VCHAR_UNI', ''),
+ ),
+ 'PRIMARY_KEY' => 'ban_id',
+ 'KEYS' => array(
+ 'ban_end' => array('INDEX', 'ban_end'),
+ 'ban_user' => array('INDEX', array('ban_userid', 'ban_exclude')),
+ 'ban_email' => array('INDEX', array('ban_email', 'ban_exclude')),
+ 'ban_ip' => array('INDEX', array('ban_ip', 'ban_exclude')),
+ ),
+);
+
+$schema_data['phpbb_bbcodes'] = array(
+ 'COLUMNS' => array(
+ 'bbcode_id' => array('USINT', 0),
+ 'bbcode_tag' => array('VCHAR:16', ''),
+ 'bbcode_helpline' => array('VCHAR_UNI', ''),
+ 'display_on_posting' => array('BOOL', 0),
+ 'bbcode_match' => array('TEXT_UNI', ''),
+ 'bbcode_tpl' => array('MTEXT_UNI', ''),
+ 'first_pass_match' => array('MTEXT_UNI', ''),
+ 'first_pass_replace' => array('MTEXT_UNI', ''),
+ 'second_pass_match' => array('MTEXT_UNI', ''),
+ 'second_pass_replace' => array('MTEXT_UNI', ''),
+ ),
+ 'PRIMARY_KEY' => 'bbcode_id',
+ 'KEYS' => array(
+ 'display_on_post' => array('INDEX', 'display_on_posting'),
+ ),
+);
+
+$schema_data['phpbb_bookmarks'] = array(
+ 'COLUMNS' => array(
+ 'topic_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => array('topic_id', 'user_id'),
+);
+
+$schema_data['phpbb_bots'] = array(
+ 'COLUMNS' => array(
+ 'bot_id' => array('UINT', NULL, 'auto_increment'),
+ 'bot_active' => array('BOOL', 1),
+ 'bot_name' => array('STEXT_UNI', ''),
+ 'user_id' => array('UINT', 0),
+ 'bot_agent' => array('VCHAR', ''),
+ 'bot_ip' => array('VCHAR', ''),
+ ),
+ 'PRIMARY_KEY' => 'bot_id',
+ 'KEYS' => array(
+ 'bot_active' => array('INDEX', 'bot_active'),
+ ),
+);
+
+$schema_data['phpbb_config'] = array(
+ 'COLUMNS' => array(
+ 'config_name' => array('VCHAR', ''),
+ 'config_value' => array('VCHAR_UNI', ''),
+ 'is_dynamic' => array('BOOL', 0),
+ ),
+ 'PRIMARY_KEY' => 'config_name',
+ 'KEYS' => array(
+ 'is_dynamic' => array('INDEX', 'is_dynamic'),
+ ),
+);
+
+$schema_data['phpbb_config_text'] = array(
+ 'COLUMNS' => array(
+ 'config_name' => array('VCHAR', ''),
+ 'config_value' => array('MTEXT', ''),
+ ),
+ 'PRIMARY_KEY' => 'config_name',
+);
+
+$schema_data['phpbb_confirm'] = array(
+ 'COLUMNS' => array(
+ 'confirm_id' => array('CHAR:32', ''),
+ 'session_id' => array('CHAR:32', ''),
+ '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(
+ 'confirm_type' => array('INDEX', 'confirm_type'),
+ ),
+);
+
+$schema_data['phpbb_disallow'] = array(
+ 'COLUMNS' => array(
+ 'disallow_id' => array('UINT', NULL, 'auto_increment'),
+ 'disallow_username' => array('VCHAR_UNI:255', ''),
+ ),
+ 'PRIMARY_KEY' => 'disallow_id',
+);
+
+$schema_data['phpbb_drafts'] = array(
+ 'COLUMNS' => array(
+ 'draft_id' => array('UINT', NULL, 'auto_increment'),
+ 'user_id' => array('UINT', 0),
+ 'topic_id' => array('UINT', 0),
+ 'forum_id' => array('UINT', 0),
+ 'save_time' => array('TIMESTAMP', 0),
+ 'draft_subject' => array('STEXT_UNI', ''),
+ 'draft_message' => array('MTEXT_UNI', ''),
+ ),
+ 'PRIMARY_KEY' => 'draft_id',
+ 'KEYS' => array(
+ 'save_time' => array('INDEX', 'save_time'),
+ ),
+);
+
+$schema_data['phpbb_ext'] = array(
+ 'COLUMNS' => array(
+ 'ext_name' => array('VCHAR', ''),
+ 'ext_active' => array('BOOL', 0),
+ 'ext_state' => array('TEXT', ''),
+ ),
+ 'KEYS' => array(
+ 'ext_name' => array('UNIQUE', 'ext_name'),
+ ),
+);
+
+$schema_data['phpbb_extensions'] = array(
+ 'COLUMNS' => array(
+ 'extension_id' => array('UINT', NULL, 'auto_increment'),
+ 'group_id' => array('UINT', 0),
+ 'extension' => array('VCHAR:100', ''),
+ ),
+ 'PRIMARY_KEY' => 'extension_id',
+);
+
+$schema_data['phpbb_extension_groups'] = array(
+ 'COLUMNS' => array(
+ 'group_id' => array('UINT', NULL, 'auto_increment'),
+ 'group_name' => array('VCHAR_UNI', ''),
+ 'cat_id' => array('TINT:2', 0),
+ 'allow_group' => array('BOOL', 0),
+ 'download_mode' => array('BOOL', 1),
+ 'upload_icon' => array('VCHAR', ''),
+ 'max_filesize' => array('UINT:20', 0),
+ 'allowed_forums' => array('TEXT', ''),
+ 'allow_in_pm' => array('BOOL', 0),
+ ),
+ 'PRIMARY_KEY' => 'group_id',
+);
+
+$schema_data['phpbb_forums'] = array(
+ 'COLUMNS' => array(
+ 'forum_id' => array('UINT', NULL, 'auto_increment'),
+ 'parent_id' => array('UINT', 0),
+ 'left_id' => array('UINT', 0),
+ 'right_id' => array('UINT', 0),
+ 'forum_parents' => array('MTEXT', ''),
+ 'forum_name' => array('STEXT_UNI', ''),
+ 'forum_desc' => array('TEXT_UNI', ''),
+ 'forum_desc_bitfield' => array('VCHAR:255', ''),
+ 'forum_desc_options' => array('UINT:11', 7),
+ 'forum_desc_uid' => array('VCHAR:8', ''),
+ 'forum_link' => array('VCHAR_UNI', ''),
+ 'forum_password' => array('VCHAR_UNI:40', ''),
+ 'forum_style' => array('UINT', 0),
+ 'forum_image' => array('VCHAR', ''),
+ 'forum_rules' => array('TEXT_UNI', ''),
+ 'forum_rules_link' => array('VCHAR_UNI', ''),
+ 'forum_rules_bitfield' => array('VCHAR:255', ''),
+ 'forum_rules_options' => array('UINT:11', 7),
+ 'forum_rules_uid' => array('VCHAR:8', ''),
+ 'forum_topics_per_page' => array('TINT:4', 0),
+ 'forum_type' => array('TINT:4', 0),
+ 'forum_status' => array('TINT:4', 0),
+ 'forum_posts_approved' => array('UINT', 0),
+ 'forum_posts_unapproved' => array('UINT', 0),
+ 'forum_posts_softdeleted' => array('UINT', 0),
+ 'forum_topics_approved' => array('UINT', 0),
+ 'forum_topics_unapproved' => array('UINT', 0),
+ 'forum_topics_softdeleted' => array('UINT', 0),
+ 'forum_last_post_id' => array('UINT', 0),
+ 'forum_last_poster_id' => array('UINT', 0),
+ 'forum_last_post_subject' => array('STEXT_UNI', ''),
+ 'forum_last_post_time' => array('TIMESTAMP', 0),
+ '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),
+ 'enable_icons' => array('BOOL', 1),
+ 'enable_prune' => array('BOOL', 0),
+ 'prune_next' => array('TIMESTAMP', 0),
+ 'prune_days' => array('UINT', 0),
+ 'prune_viewed' => array('UINT', 0),
+ 'prune_freq' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'forum_id',
+ 'KEYS' => array(
+ 'left_right_id' => array('INDEX', array('left_id', 'right_id')),
+ 'forum_lastpost_id' => array('INDEX', 'forum_last_post_id'),
+ ),
+);
+
+$schema_data['phpbb_forums_access'] = array(
+ 'COLUMNS' => array(
+ 'forum_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'session_id' => array('CHAR:32', ''),
+ ),
+ 'PRIMARY_KEY' => array('forum_id', 'user_id', 'session_id'),
+);
+
+$schema_data['phpbb_forums_track'] = array(
+ 'COLUMNS' => array(
+ 'user_id' => array('UINT', 0),
+ 'forum_id' => array('UINT', 0),
+ 'mark_time' => array('TIMESTAMP', 0),
+ ),
+ 'PRIMARY_KEY' => array('user_id', 'forum_id'),
+);
+
+$schema_data['phpbb_forums_watch'] = array(
+ 'COLUMNS' => array(
+ 'forum_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'notify_status' => array('BOOL', 0),
+ ),
+ 'KEYS' => array(
+ 'forum_id' => array('INDEX', 'forum_id'),
+ 'user_id' => array('INDEX', 'user_id'),
+ 'notify_stat' => array('INDEX', 'notify_status'),
+ ),
+);
+
+$schema_data['phpbb_groups'] = array(
+ 'COLUMNS' => array(
+ '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', ''),
+ 'group_desc_options' => array('UINT:11', 7),
+ 'group_desc_uid' => array('VCHAR:8', ''),
+ 'group_display' => array('BOOL', 0),
+ 'group_avatar' => array('VCHAR', ''),
+ 'group_avatar_type' => array('VCHAR:255', ''),
+ 'group_avatar_width' => array('USINT', 0),
+ 'group_avatar_height' => array('USINT', 0),
+ 'group_rank' => array('UINT', 0),
+ 'group_colour' => array('VCHAR:6', ''),
+ 'group_sig_chars' => array('UINT', 0),
+ 'group_receive_pm' => array('BOOL', 0),
+ 'group_message_limit' => array('UINT', 0),
+ 'group_max_recipients' => array('UINT', 0),
+ 'group_legend' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'group_id',
+ 'KEYS' => array(
+ 'group_legend_name' => array('INDEX', array('group_legend', 'group_name')),
+ ),
+);
+
+$schema_data['phpbb_icons'] = array(
+ 'COLUMNS' => array(
+ 'icons_id' => array('UINT', NULL, 'auto_increment'),
+ 'icons_url' => array('VCHAR', ''),
+ 'icons_width' => array('TINT:4', 0),
+ 'icons_height' => array('TINT:4', 0),
+ 'icons_order' => array('UINT', 0),
+ 'display_on_posting' => array('BOOL', 1),
+ ),
+ 'PRIMARY_KEY' => 'icons_id',
+ 'KEYS' => array(
+ 'display_on_posting' => array('INDEX', 'display_on_posting'),
+ ),
+);
+
+$schema_data['phpbb_lang'] = array(
+ 'COLUMNS' => array(
+ 'lang_id' => array('TINT:4', NULL, 'auto_increment'),
+ 'lang_iso' => array('VCHAR:30', ''),
+ 'lang_dir' => array('VCHAR:30', ''),
+ 'lang_english_name' => array('VCHAR_UNI:100', ''),
+ 'lang_local_name' => array('VCHAR_UNI:255', ''),
+ 'lang_author' => array('VCHAR_UNI:255', ''),
+ ),
+ 'PRIMARY_KEY' => 'lang_id',
+ 'KEYS' => array(
+ 'lang_iso' => array('INDEX', 'lang_iso'),
+ ),
+);
+
+$schema_data['phpbb_log'] = array(
+ 'COLUMNS' => array(
+ 'log_id' => array('UINT', NULL, 'auto_increment'),
+ 'log_type' => array('TINT:4', 0),
+ 'user_id' => array('UINT', 0),
+ 'forum_id' => array('UINT', 0),
+ 'topic_id' => array('UINT', 0),
+ 'reportee_id' => array('UINT', 0),
+ 'log_ip' => array('VCHAR:40', ''),
+ 'log_time' => array('TIMESTAMP', 0),
+ 'log_operation' => array('TEXT_UNI', ''),
+ 'log_data' => array('MTEXT_UNI', ''),
+ ),
+ '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'),
+ 'user_id' => array('INDEX', 'user_id'),
+ ),
+);
+
+$schema_data['phpbb_login_attempts'] = array(
+ 'COLUMNS' => array(
+ 'attempt_ip' => array('VCHAR:40', ''),
+ 'attempt_browser' => array('VCHAR:150', ''),
+ 'attempt_forwarded_for' => array('VCHAR:255', ''),
+ 'attempt_time' => array('TIMESTAMP', 0),
+ 'user_id' => array('UINT', 0),
+ 'username' => array('VCHAR_UNI:255', 0),
+ 'username_clean' => array('VCHAR_CI', 0),
+ ),
+ 'KEYS' => array(
+ 'att_ip' => array('INDEX', array('attempt_ip', 'attempt_time')),
+ 'att_for' => array('INDEX', array('attempt_forwarded_for', 'attempt_time')),
+ 'att_time' => array('INDEX', array('attempt_time')),
+ 'user_id' => array('INDEX', 'user_id'),
+ ),
+);
+
+$schema_data['phpbb_moderator_cache'] = array(
+ 'COLUMNS' => array(
+ 'forum_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'username' => array('VCHAR_UNI:255', ''),
+ 'group_id' => array('UINT', 0),
+ 'group_name' => array('VCHAR_UNI', ''),
+ 'display_on_index' => array('BOOL', 1),
+ ),
+ 'KEYS' => array(
+ 'disp_idx' => array('INDEX', 'display_on_index'),
+ 'forum_id' => array('INDEX', 'forum_id'),
+ ),
+);
+
+$schema_data['phpbb_migrations'] = array(
+ 'COLUMNS' => array(
+ 'migration_name' => array('VCHAR', ''),
+ 'migration_depends_on' => array('TEXT', ''),
+ 'migration_schema_done' => array('BOOL', 0),
+ 'migration_data_done' => array('BOOL', 0),
+ 'migration_data_state' => array('TEXT', ''),
+ 'migration_start_time' => array('TIMESTAMP', 0),
+ 'migration_end_time' => array('TIMESTAMP', 0),
+ ),
+ 'PRIMARY_KEY' => 'migration_name',
+);
+
+$schema_data['phpbb_modules'] = array(
+ 'COLUMNS' => array(
+ 'module_id' => array('UINT', NULL, 'auto_increment'),
+ 'module_enabled' => array('BOOL', 1),
+ 'module_display' => array('BOOL', 1),
+ 'module_basename' => array('VCHAR', ''),
+ 'module_class' => array('VCHAR:10', ''),
+ 'parent_id' => array('UINT', 0),
+ 'left_id' => array('UINT', 0),
+ 'right_id' => array('UINT', 0),
+ 'module_langname' => array('VCHAR', ''),
+ 'module_mode' => array('VCHAR', ''),
+ 'module_auth' => array('VCHAR', ''),
+ ),
+ 'PRIMARY_KEY' => 'module_id',
+ 'KEYS' => array(
+ 'left_right_id' => array('INDEX', array('left_id', 'right_id')),
+ 'module_enabled' => array('INDEX', 'module_enabled'),
+ 'class_left_id' => array('INDEX', array('module_class', 'left_id')),
+ ),
+);
+
+$schema_data['phpbb_notification_types'] = array(
+ 'COLUMNS' => array(
+ 'notification_type_id' => array('USINT', NULL, 'auto_increment'),
+ 'notification_type_name' => array('VCHAR:255', ''),
+ 'notification_type_enabled' => array('BOOL', 1),
+ ),
+ 'PRIMARY_KEY' => array('notification_type_id'),
+ 'KEYS' => array(
+ 'type' => array('UNIQUE', array('notification_type_name')),
+ ),
+);
+
+$schema_data['phpbb_notifications'] = array(
+ 'COLUMNS' => array(
+ 'notification_id' => array('UINT:10', NULL, 'auto_increment'),
+ 'notification_type_id' => array('USINT', 0),
+ 'item_id' => array('UINT', 0),
+ 'item_parent_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'notification_read' => array('BOOL', 0),
+ 'notification_time' => array('TIMESTAMP', 1),
+ 'notification_data' => array('TEXT_UNI', ''),
+ ),
+ 'PRIMARY_KEY' => 'notification_id',
+ 'KEYS' => array(
+ 'item_ident' => array('INDEX', array('notification_type_id', 'item_id')),
+ 'user' => array('INDEX', array('user_id', 'notification_read')),
+ ),
+);
+
+$schema_data['phpbb_poll_options'] = array(
+ 'COLUMNS' => array(
+ 'poll_option_id' => array('TINT:4', 0),
+ 'topic_id' => array('UINT', 0),
+ 'poll_option_text' => array('TEXT_UNI', ''),
+ 'poll_option_total' => array('UINT', 0),
+ ),
+ 'KEYS' => array(
+ 'poll_opt_id' => array('INDEX', 'poll_option_id'),
+ 'topic_id' => array('INDEX', 'topic_id'),
+ ),
+);
+
+$schema_data['phpbb_poll_votes'] = array(
+ 'COLUMNS' => array(
+ 'topic_id' => array('UINT', 0),
+ 'poll_option_id' => array('TINT:4', 0),
+ 'vote_user_id' => array('UINT', 0),
+ 'vote_user_ip' => array('VCHAR:40', ''),
+ ),
+ 'KEYS' => array(
+ 'topic_id' => array('INDEX', 'topic_id'),
+ 'vote_user_id' => array('INDEX', 'vote_user_id'),
+ 'vote_user_ip' => array('INDEX', 'vote_user_ip'),
+ ),
+);
+
+$schema_data['phpbb_posts'] = array(
+ 'COLUMNS' => array(
+ 'post_id' => array('UINT', NULL, 'auto_increment'),
+ 'topic_id' => array('UINT', 0),
+ 'forum_id' => array('UINT', 0),
+ 'poster_id' => array('UINT', 0),
+ 'icon_id' => array('UINT', 0),
+ 'poster_ip' => array('VCHAR:40', ''),
+ 'post_time' => array('TIMESTAMP', 0),
+ 'post_visibility' => array('TINT:3', 0),
+ 'post_reported' => array('BOOL', 0),
+ 'enable_bbcode' => array('BOOL', 1),
+ 'enable_smilies' => array('BOOL', 1),
+ 'enable_magic_url' => array('BOOL', 1),
+ 'enable_sig' => array('BOOL', 1),
+ 'post_username' => array('VCHAR_UNI:255', ''),
+ 'post_subject' => array('STEXT_UNI', '', 'true_sort'),
+ 'post_text' => array('MTEXT_UNI', ''),
+ 'post_checksum' => array('VCHAR:32', ''),
+ 'post_attachment' => array('BOOL', 0),
+ 'bbcode_bitfield' => array('VCHAR:255', ''),
+ 'bbcode_uid' => array('VCHAR:8', ''),
+ 'post_postcount' => array('BOOL', 1),
+ 'post_edit_time' => array('TIMESTAMP', 0),
+ 'post_edit_reason' => array('STEXT_UNI', ''),
+ 'post_edit_user' => array('UINT', 0),
+ 'post_edit_count' => array('USINT', 0),
+ 'post_edit_locked' => array('BOOL', 0),
+ 'post_delete_time' => array('TIMESTAMP', 0),
+ 'post_delete_reason' => array('STEXT_UNI', ''),
+ 'post_delete_user' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'post_id',
+ 'KEYS' => array(
+ 'forum_id' => array('INDEX', 'forum_id'),
+ 'topic_id' => array('INDEX', 'topic_id'),
+ 'poster_ip' => array('INDEX', 'poster_ip'),
+ 'poster_id' => array('INDEX', 'poster_id'),
+ 'post_visibility' => array('INDEX', 'post_visibility'),
+ 'post_username' => array('INDEX', 'post_username'),
+ 'tid_post_time' => array('INDEX', array('topic_id', 'post_time')),
+ ),
+);
+
+$schema_data['phpbb_privmsgs'] = array(
+ 'COLUMNS' => array(
+ 'msg_id' => array('UINT', NULL, 'auto_increment'),
+ 'root_level' => array('UINT', 0),
+ 'author_id' => array('UINT', 0),
+ 'icon_id' => array('UINT', 0),
+ 'author_ip' => array('VCHAR:40', ''),
+ 'message_time' => array('TIMESTAMP', 0),
+ 'enable_bbcode' => array('BOOL', 1),
+ 'enable_smilies' => array('BOOL', 1),
+ 'enable_magic_url' => array('BOOL', 1),
+ 'enable_sig' => array('BOOL', 1),
+ 'message_subject' => array('STEXT_UNI', ''),
+ 'message_text' => array('MTEXT_UNI', ''),
+ 'message_edit_reason' => array('STEXT_UNI', ''),
+ 'message_edit_user' => array('UINT', 0),
+ 'message_attachment' => array('BOOL', 0),
+ 'bbcode_bitfield' => array('VCHAR:255', ''),
+ 'bbcode_uid' => array('VCHAR:8', ''),
+ 'message_edit_time' => array('TIMESTAMP', 0),
+ '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(
+ 'author_ip' => array('INDEX', 'author_ip'),
+ 'message_time' => array('INDEX', 'message_time'),
+ 'author_id' => array('INDEX', 'author_id'),
+ 'root_level' => array('INDEX', 'root_level'),
+ ),
+);
+
+$schema_data['phpbb_privmsgs_folder'] = array(
+ 'COLUMNS' => array(
+ 'folder_id' => array('UINT', NULL, 'auto_increment'),
+ 'user_id' => array('UINT', 0),
+ 'folder_name' => array('VCHAR_UNI', ''),
+ 'pm_count' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'folder_id',
+ 'KEYS' => array(
+ 'user_id' => array('INDEX', 'user_id'),
+ ),
+);
+
+$schema_data['phpbb_privmsgs_rules'] = array(
+ 'COLUMNS' => array(
+ 'rule_id' => array('UINT', NULL, 'auto_increment'),
+ 'user_id' => array('UINT', 0),
+ 'rule_check' => array('UINT', 0),
+ 'rule_connection' => array('UINT', 0),
+ 'rule_string' => array('VCHAR_UNI', ''),
+ 'rule_user_id' => array('UINT', 0),
+ 'rule_group_id' => array('UINT', 0),
+ 'rule_action' => array('UINT', 0),
+ 'rule_folder_id' => array('INT:11', 0),
+ ),
+ 'PRIMARY_KEY' => 'rule_id',
+ 'KEYS' => array(
+ 'user_id' => array('INDEX', 'user_id'),
+ ),
+);
+
+$schema_data['phpbb_privmsgs_to'] = array(
+ 'COLUMNS' => array(
+ 'msg_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'author_id' => array('UINT', 0),
+ 'pm_deleted' => array('BOOL', 0),
+ 'pm_new' => array('BOOL', 1),
+ 'pm_unread' => array('BOOL', 1),
+ 'pm_replied' => array('BOOL', 0),
+ 'pm_marked' => array('BOOL', 0),
+ 'pm_forwarded' => array('BOOL', 0),
+ 'folder_id' => array('INT:11', 0),
+ ),
+ 'KEYS' => array(
+ 'msg_id' => array('INDEX', 'msg_id'),
+ 'author_id' => array('INDEX', 'author_id'),
+ 'usr_flder_id' => array('INDEX', array('user_id', 'folder_id')),
+ ),
+);
+
+$schema_data['phpbb_profile_fields'] = array(
+ 'COLUMNS' => array(
+ 'field_id' => array('UINT', NULL, 'auto_increment'),
+ 'field_name' => array('VCHAR_UNI', ''),
+ 'field_type' => array('TINT:4', 0),
+ 'field_ident' => array('VCHAR:20', ''),
+ 'field_length' => array('VCHAR:20', ''),
+ 'field_minlen' => array('VCHAR', ''),
+ 'field_maxlen' => array('VCHAR', ''),
+ 'field_novalue' => array('VCHAR_UNI', ''),
+ 'field_default_value' => array('VCHAR_UNI', ''),
+ 'field_validation' => array('VCHAR_UNI:20', ''),
+ 'field_required' => array('BOOL', 0),
+ 'field_show_novalue' => array('BOOL', 0),
+ 'field_show_on_reg' => array('BOOL', 0),
+ 'field_show_on_pm' => 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),
+ 'field_active' => array('BOOL', 0),
+ 'field_order' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'field_id',
+ 'KEYS' => array(
+ 'fld_type' => array('INDEX', 'field_type'),
+ 'fld_ordr' => array('INDEX', 'field_order'),
+ ),
+);
+
+$schema_data['phpbb_profile_fields_data'] = array(
+ 'COLUMNS' => array(
+ 'user_id' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'user_id',
+);
+
+$schema_data['phpbb_profile_fields_lang'] = array(
+ 'COLUMNS' => array(
+ 'field_id' => array('UINT', 0),
+ 'lang_id' => array('UINT', 0),
+ 'option_id' => array('UINT', 0),
+ 'field_type' => array('TINT:4', 0),
+ 'lang_value' => array('VCHAR_UNI', ''),
+ ),
+ 'PRIMARY_KEY' => array('field_id', 'lang_id', 'option_id'),
+);
+
+$schema_data['phpbb_profile_lang'] = array(
+ 'COLUMNS' => array(
+ 'field_id' => array('UINT', 0),
+ 'lang_id' => array('UINT', 0),
+ 'lang_name' => array('VCHAR_UNI', ''),
+ 'lang_explain' => array('TEXT_UNI', ''),
+ 'lang_default_value' => array('VCHAR_UNI', ''),
+ ),
+ 'PRIMARY_KEY' => array('field_id', 'lang_id'),
+);
+
+$schema_data['phpbb_ranks'] = array(
+ 'COLUMNS' => array(
+ 'rank_id' => array('UINT', NULL, 'auto_increment'),
+ 'rank_title' => array('VCHAR_UNI', ''),
+ 'rank_min' => array('UINT', 0),
+ 'rank_special' => array('BOOL', 0),
+ 'rank_image' => array('VCHAR', ''),
+ ),
+ 'PRIMARY_KEY' => 'rank_id',
+);
+
+$schema_data['phpbb_reports'] = array(
+ 'COLUMNS' => array(
+ '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),
+ 'report_time' => array('TIMESTAMP', 0),
+ 'report_text' => array('MTEXT_UNI', ''),
+ 'reported_post_text' => array('MTEXT_UNI', ''),
+ 'reported_post_uid' => array('VCHAR:8', ''),
+ 'reported_post_bitfield' => array('VCHAR:255', ''),
+ 'reported_post_enable_magic_url' => array('BOOL', 1),
+ 'reported_post_enable_smilies' => array('BOOL', 1),
+ 'reported_post_enable_bbcode' => array('BOOL', 1)
+ ),
+ 'PRIMARY_KEY' => 'report_id',
+ 'KEYS' => array(
+ 'post_id' => array('INDEX', 'post_id'),
+ 'pm_id' => array('INDEX', 'pm_id'),
+ ),
+);
+
+$schema_data['phpbb_reports_reasons'] = array(
+ 'COLUMNS' => array(
+ 'reason_id' => array('USINT', NULL, 'auto_increment'),
+ 'reason_title' => array('VCHAR_UNI', ''),
+ 'reason_description' => array('MTEXT_UNI', ''),
+ 'reason_order' => array('USINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'reason_id',
+);
+
+$schema_data['phpbb_search_results'] = array(
+ 'COLUMNS' => array(
+ 'search_key' => array('VCHAR:32', ''),
+ 'search_time' => array('TIMESTAMP', 0),
+ 'search_keywords' => array('MTEXT_UNI', ''),
+ 'search_authors' => array('MTEXT', ''),
+ ),
+ 'PRIMARY_KEY' => 'search_key',
+);
+
+$schema_data['phpbb_search_wordlist'] = array(
+ 'COLUMNS' => array(
+ 'word_id' => array('UINT', NULL, 'auto_increment'),
+ 'word_text' => array('VCHAR_UNI', ''),
+ 'word_common' => array('BOOL', 0),
+ 'word_count' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'word_id',
+ 'KEYS' => array(
+ 'wrd_txt' => array('UNIQUE', 'word_text'),
+ 'wrd_cnt' => array('INDEX', 'word_count'),
+ ),
+);
+
+$schema_data['phpbb_search_wordmatch'] = array(
+ 'COLUMNS' => array(
+ 'post_id' => array('UINT', 0),
+ 'word_id' => array('UINT', 0),
+ 'title_match' => array('BOOL', 0),
+ ),
+ 'KEYS' => array(
+ 'unq_mtch' => array('UNIQUE', array('word_id', 'post_id', 'title_match')),
+ 'word_id' => array('INDEX', 'word_id'),
+ 'post_id' => array('INDEX', 'post_id'),
+ ),
+);
+
+$schema_data['phpbb_sessions'] = array(
+ 'COLUMNS' => array(
+ 'session_id' => array('CHAR:32', ''),
+ 'session_user_id' => array('UINT', 0),
+ 'session_forum_id' => array('UINT', 0),
+ 'session_last_visit' => array('TIMESTAMP', 0),
+ 'session_start' => array('TIMESTAMP', 0),
+ 'session_time' => array('TIMESTAMP', 0),
+ 'session_ip' => array('VCHAR:40', ''),
+ 'session_browser' => array('VCHAR:150', ''),
+ 'session_forwarded_for' => array('VCHAR:255', ''),
+ 'session_page' => array('VCHAR_UNI', ''),
+ 'session_viewonline' => array('BOOL', 1),
+ 'session_autologin' => array('BOOL', 0),
+ 'session_admin' => array('BOOL', 0),
+ ),
+ 'PRIMARY_KEY' => 'session_id',
+ 'KEYS' => array(
+ 'session_time' => array('INDEX', 'session_time'),
+ 'session_user_id' => array('INDEX', 'session_user_id'),
+ 'session_fid' => array('INDEX', 'session_forum_id'),
+ ),
+);
+
+$schema_data['phpbb_sessions_keys'] = array(
+ 'COLUMNS' => array(
+ 'key_id' => array('CHAR:32', ''),
+ 'user_id' => array('UINT', 0),
+ 'last_ip' => array('VCHAR:40', ''),
+ 'last_login' => array('TIMESTAMP', 0),
+ ),
+ 'PRIMARY_KEY' => array('key_id', 'user_id'),
+ 'KEYS' => array(
+ 'last_login' => array('INDEX', 'last_login'),
+ ),
+);
+
+$schema_data['phpbb_sitelist'] = array(
+ 'COLUMNS' => array(
+ 'site_id' => array('UINT', NULL, 'auto_increment'),
+ 'site_ip' => array('VCHAR:40', ''),
+ 'site_hostname' => array('VCHAR', ''),
+ 'ip_exclude' => array('BOOL', 0),
+ ),
+ 'PRIMARY_KEY' => 'site_id',
+);
+
+$schema_data['phpbb_smilies'] = array(
+ 'COLUMNS' => array(
+ 'smiley_id' => array('UINT', NULL, 'auto_increment'),
+ // We may want to set 'code' to VCHAR:50 or check if unicode support is possible... at the moment only ASCII characters are allowed.
+ 'code' => array('VCHAR_UNI:50', ''),
+ 'emotion' => array('VCHAR_UNI:50', ''),
+ 'smiley_url' => array('VCHAR:50', ''),
+ 'smiley_width' => array('USINT', 0),
+ 'smiley_height' => array('USINT', 0),
+ 'smiley_order' => array('UINT', 0),
+ 'display_on_posting'=> array('BOOL', 1),
+ ),
+ 'PRIMARY_KEY' => 'smiley_id',
+ 'KEYS' => array(
+ 'display_on_post' => array('INDEX', 'display_on_posting'),
+ ),
+);
+
+$schema_data['phpbb_styles'] = array(
+ 'COLUMNS' => array(
+ 'style_id' => array('UINT', NULL, 'auto_increment'),
+ 'style_name' => array('VCHAR_UNI:255', ''),
+ 'style_copyright' => array('VCHAR_UNI', ''),
+ 'style_active' => array('BOOL', 1),
+ 'style_path' => array('VCHAR:100', ''),
+ 'bbcode_bitfield' => array('VCHAR:255', 'kNg='),
+ 'style_parent_id' => array('UINT:4', 0),
+ 'style_parent_tree' => array('TEXT', ''),
+ ),
+ 'PRIMARY_KEY' => 'style_id',
+ 'KEYS' => array(
+ 'style_name' => array('UNIQUE', 'style_name'),
+ ),
+);
+
+$schema_data['phpbb_teampage'] = array(
+ 'COLUMNS' => array(
+ 'teampage_id' => array('UINT', NULL, 'auto_increment'),
+ 'group_id' => array('UINT', 0),
+ 'teampage_name' => array('VCHAR_UNI:255', ''),
+ 'teampage_position' => array('UINT', 0),
+ 'teampage_parent' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'teampage_id',
+);
+
+$schema_data['phpbb_topics'] = array(
+ 'COLUMNS' => array(
+ 'topic_id' => array('UINT', NULL, 'auto_increment'),
+ 'forum_id' => array('UINT', 0),
+ 'icon_id' => array('UINT', 0),
+ 'topic_attachment' => array('BOOL', 0),
+ 'topic_visibility' => array('TINT:3', 0),
+ 'topic_reported' => array('BOOL', 0),
+ 'topic_title' => array('STEXT_UNI', '', 'true_sort'),
+ 'topic_poster' => array('UINT', 0),
+ 'topic_time' => array('TIMESTAMP', 0),
+ 'topic_time_limit' => array('TIMESTAMP', 0),
+ 'topic_views' => array('UINT', 0),
+ 'topic_posts_approved' => array('UINT', 0),
+ 'topic_posts_unapproved' => array('UINT', 0),
+ 'topic_posts_softdeleted' => array('UINT', 0),
+ 'topic_status' => array('TINT:3', 0),
+ 'topic_type' => array('TINT:3', 0),
+ 'topic_first_post_id' => array('UINT', 0),
+ 'topic_first_poster_name' => array('VCHAR_UNI', ''),
+ 'topic_first_poster_colour' => array('VCHAR:6', ''),
+ 'topic_last_post_id' => array('UINT', 0),
+ 'topic_last_poster_id' => array('UINT', 0),
+ 'topic_last_poster_name' => array('VCHAR_UNI', ''),
+ 'topic_last_poster_colour' => array('VCHAR:6', ''),
+ 'topic_last_post_subject' => array('STEXT_UNI', ''),
+ 'topic_last_post_time' => array('TIMESTAMP', 0),
+ 'topic_last_view_time' => array('TIMESTAMP', 0),
+ 'topic_moved_id' => array('UINT', 0),
+ 'topic_bumped' => array('BOOL', 0),
+ 'topic_bumper' => array('UINT', 0),
+ 'poll_title' => array('STEXT_UNI', ''),
+ 'poll_start' => array('TIMESTAMP', 0),
+ 'poll_length' => array('TIMESTAMP', 0),
+ 'poll_max_options' => array('TINT:4', 1),
+ 'poll_last_vote' => array('TIMESTAMP', 0),
+ 'poll_vote_change' => array('BOOL', 0),
+ 'topic_delete_time' => array('TIMESTAMP', 0),
+ 'topic_delete_reason' => array('STEXT_UNI', ''),
+ 'topic_delete_user' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'topic_id',
+ 'KEYS' => array(
+ 'forum_id' => array('INDEX', 'forum_id'),
+ 'forum_id_type' => array('INDEX', array('forum_id', 'topic_type')),
+ 'last_post_time' => array('INDEX', 'topic_last_post_time'),
+ 'topic_visibility' => array('INDEX', 'topic_visibility'),
+ 'forum_appr_last' => array('INDEX', array('forum_id', 'topic_visibility', 'topic_last_post_id')),
+ 'fid_time_moved' => array('INDEX', array('forum_id', 'topic_last_post_time', 'topic_moved_id')),
+ ),
+);
+
+$schema_data['phpbb_topics_track'] = array(
+ 'COLUMNS' => array(
+ 'user_id' => array('UINT', 0),
+ 'topic_id' => array('UINT', 0),
+ 'forum_id' => array('UINT', 0),
+ 'mark_time' => array('TIMESTAMP', 0),
+ ),
+ 'PRIMARY_KEY' => array('user_id', 'topic_id'),
+ 'KEYS' => array(
+ 'topic_id' => array('INDEX', 'topic_id'),
+ 'forum_id' => array('INDEX', 'forum_id'),
+ ),
+);
+
+$schema_data['phpbb_topics_posted'] = array(
+ 'COLUMNS' => array(
+ 'user_id' => array('UINT', 0),
+ 'topic_id' => array('UINT', 0),
+ 'topic_posted' => array('BOOL', 0),
+ ),
+ 'PRIMARY_KEY' => array('user_id', 'topic_id'),
+);
+
+$schema_data['phpbb_topics_watch'] = array(
+ 'COLUMNS' => array(
+ 'topic_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'notify_status' => array('BOOL', 0),
+ ),
+ 'KEYS' => array(
+ 'topic_id' => array('INDEX', 'topic_id'),
+ 'user_id' => array('INDEX', 'user_id'),
+ 'notify_stat' => array('INDEX', 'notify_status'),
+ ),
+);
+
+$schema_data['phpbb_user_notifications'] = array(
+ 'COLUMNS' => array(
+ 'item_type' => array('VCHAR:255', ''),
+ 'item_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'method' => array('VCHAR:255', ''),
+ 'notify' => array('BOOL', 1),
+ ),
+);
+
+$schema_data['phpbb_user_group'] = array(
+ 'COLUMNS' => array(
+ 'group_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'group_leader' => array('BOOL', 0),
+ 'user_pending' => array('BOOL', 1),
+ ),
+ 'KEYS' => array(
+ 'group_id' => array('INDEX', 'group_id'),
+ 'user_id' => array('INDEX', 'user_id'),
+ 'group_leader' => array('INDEX', 'group_leader'),
+ ),
+);
+
+$schema_data['phpbb_users'] = array(
+ 'COLUMNS' => array(
+ 'user_id' => array('UINT', NULL, 'auto_increment'),
+ 'user_type' => array('TINT:2', 0),
+ 'group_id' => array('UINT', 3),
+ 'user_permissions' => array('MTEXT', ''),
+ 'user_perm_from' => array('UINT', 0),
+ 'user_ip' => array('VCHAR:40', ''),
+ 'user_regdate' => array('TIMESTAMP', 0),
+ 'username' => array('VCHAR_CI', ''),
+ 'username_clean' => array('VCHAR_CI', ''),
+ 'user_password' => array('VCHAR_UNI:40', ''),
+ 'user_passchg' => array('TIMESTAMP', 0),
+ 'user_pass_convert' => array('BOOL', 0),
+ 'user_email' => array('VCHAR_UNI:100', ''),
+ 'user_email_hash' => array('BINT', 0),
+ 'user_birthday' => array('VCHAR:10', ''),
+ 'user_lastvisit' => array('TIMESTAMP', 0),
+ 'user_lastmark' => array('TIMESTAMP', 0),
+ 'user_lastpost_time' => array('TIMESTAMP', 0),
+ 'user_lastpage' => array('VCHAR_UNI:200', ''),
+ 'user_last_confirm_key' => array('VCHAR:10', ''),
+ 'user_last_search' => array('TIMESTAMP', 0),
+ 'user_warnings' => array('TINT:4', 0),
+ 'user_last_warning' => array('TIMESTAMP', 0),
+ 'user_login_attempts' => array('TINT:4', 0),
+ 'user_inactive_reason' => array('TINT:2', 0),
+ 'user_inactive_time' => array('TIMESTAMP', 0),
+ 'user_posts' => array('UINT', 0),
+ 'user_lang' => array('VCHAR:30', ''),
+ 'user_timezone' => array('VCHAR:100', 'UTC'),
+ 'user_dateformat' => array('VCHAR_UNI:30', 'd M Y H:i'),
+ 'user_style' => array('UINT', 0),
+ 'user_rank' => array('UINT', 0),
+ 'user_colour' => array('VCHAR:6', ''),
+ 'user_new_privmsg' => array('INT:4', 0),
+ 'user_unread_privmsg' => array('INT:4', 0),
+ 'user_last_privmsg' => array('TIMESTAMP', 0),
+ 'user_message_rules' => array('BOOL', 0),
+ 'user_full_folder' => array('INT:11', -3),
+ 'user_emailtime' => array('TIMESTAMP', 0),
+ 'user_topic_show_days' => array('USINT', 0),
+ 'user_topic_sortby_type' => array('VCHAR:1', 't'),
+ 'user_topic_sortby_dir' => array('VCHAR:1', 'd'),
+ 'user_post_show_days' => array('USINT', 0),
+ 'user_post_sortby_type' => array('VCHAR:1', 't'),
+ 'user_post_sortby_dir' => array('VCHAR:1', 'a'),
+ 'user_notify' => array('BOOL', 0),
+ 'user_notify_pm' => array('BOOL', 1),
+ 'user_notify_type' => array('TINT:4', 0),
+ 'user_allow_pm' => array('BOOL', 1),
+ 'user_allow_viewonline' => array('BOOL', 1),
+ 'user_allow_viewemail' => array('BOOL', 1),
+ 'user_allow_massemail' => array('BOOL', 1),
+ 'user_options' => array('UINT:11', 230271),
+ 'user_avatar' => array('VCHAR', ''),
+ 'user_avatar_type' => array('VCHAR:255', ''),
+ 'user_avatar_width' => array('USINT', 0),
+ 'user_avatar_height' => array('USINT', 0),
+ 'user_sig' => array('MTEXT_UNI', ''),
+ 'user_sig_bbcode_uid' => array('VCHAR:8', ''),
+ 'user_sig_bbcode_bitfield' => array('VCHAR:255', ''),
+ 'user_from' => array('VCHAR_UNI:100', ''),
+ 'user_icq' => array('VCHAR:15', ''),
+ 'user_aim' => array('VCHAR_UNI', ''),
+ 'user_yim' => array('VCHAR_UNI', ''),
+ 'user_msnm' => array('VCHAR_UNI', ''),
+ 'user_jabber' => array('VCHAR_UNI', ''),
+ 'user_website' => array('VCHAR_UNI:200', ''),
+ 'user_occ' => array('TEXT_UNI', ''),
+ 'user_interests' => array('TEXT_UNI', ''),
+ '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(
+ 'user_birthday' => array('INDEX', 'user_birthday'),
+ 'user_email_hash' => array('INDEX', 'user_email_hash'),
+ 'user_type' => array('INDEX', 'user_type'),
+ 'username_clean' => array('UNIQUE', 'username_clean'),
+ ),
+);
+
+$schema_data['phpbb_warnings'] = array(
+ 'COLUMNS' => array(
+ 'warning_id' => array('UINT', NULL, 'auto_increment'),
+ 'user_id' => array('UINT', 0),
+ 'post_id' => array('UINT', 0),
+ 'log_id' => array('UINT', 0),
+ 'warning_time' => array('TIMESTAMP', 0),
+ ),
+ 'PRIMARY_KEY' => 'warning_id',
+);
+
+$schema_data['phpbb_words'] = array(
+ 'COLUMNS' => array(
+ 'word_id' => array('UINT', NULL, 'auto_increment'),
+ 'word' => array('VCHAR_UNI', ''),
+ 'replacement' => array('VCHAR_UNI', ''),
+ ),
+ 'PRIMARY_KEY' => 'word_id',
+);
+
+$schema_data['phpbb_zebra'] = array(
+ 'COLUMNS' => array(
+ 'user_id' => array('UINT', 0),
+ 'zebra_id' => array('UINT', 0),
+ 'friend' => array('BOOL', 0),
+ 'foe' => array('BOOL', 0),
+ ),
+ 'PRIMARY_KEY' => array('user_id', 'zebra_id'),
+);
diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/sqlite.php
deleted file mode 100644
index 5fc89ced18..0000000000
--- a/phpBB/includes/db/sqlite.php
+++ /dev/null
@@ -1,336 +0,0 @@
-<?php
-/**
-*
-* @package dbal
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx);
-
-/**
-* Sqlite Database Abstraction Layer
-* Minimum Requirement: 2.8.2+
-* @package dbal
-*/
-class dbal_sqlite extends dbal
-{
- /**
- * Connect to server
- */
- function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
- {
- $this->persistency = $persistency;
- $this->user = $sqluser;
- $this->server = $sqlserver . (($port) ? ':' . $port : '');
- $this->dbname = $database;
-
- $error = '';
- $this->db_connect_id = ($this->persistency) ? @sqlite_popen($this->server, 0666, $error) : @sqlite_open($this->server, 0666, $error);
-
- if ($this->db_connect_id)
- {
- @sqlite_query('PRAGMA short_column_names = 1', $this->db_connect_id);
-// @sqlite_query('PRAGMA encoding = "UTF-8"', $this->db_connect_id);
- }
-
- return ($this->db_connect_id) ? true : array('message' => $error);
- }
-
- /**
- * Version information about used database
- * @param bool $raw if true, only return the fetched sql_server_version
- * @param bool $use_cache if true, it is safe to retrieve the stored value from the cache
- * @return string sql server version
- */
- function sql_server_info($raw = false, $use_cache = true)
- {
- global $cache;
-
- if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('sqlite_version')) === false)
- {
- $result = @sqlite_query('SELECT sqlite_version() AS version', $this->db_connect_id);
- $row = @sqlite_fetch_array($result, SQLITE_ASSOC);
-
- $this->sql_server_version = (!empty($row['version'])) ? $row['version'] : 0;
-
- if (!empty($cache) && $use_cache)
- {
- $cache->put('sqlite_version', $this->sql_server_version);
- }
- }
-
- return ($raw) ? $this->sql_server_version : 'SQLite ' . $this->sql_server_version;
- }
-
- /**
- * SQL Transaction
- * @access private
- */
- function _sql_transaction($status = 'begin')
- {
- switch ($status)
- {
- case 'begin':
- return @sqlite_query('BEGIN', $this->db_connect_id);
- break;
-
- case 'commit':
- return @sqlite_query('COMMIT', $this->db_connect_id);
- break;
-
- case 'rollback':
- return @sqlite_query('ROLLBACK', $this->db_connect_id);
- break;
- }
-
- return true;
- }
-
- /**
- * Base query method
- *
- * @param string $query Contains the SQL query which shall be executed
- * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
- * @return mixed When casted to bool the returned value returns true on success and false on failure
- *
- * @access public
- */
- function sql_query($query = '', $cache_ttl = 0)
- {
- if ($query != '')
- {
- global $cache;
-
- // EXPLAIN only in extra debug mode
- if (defined('DEBUG'))
- {
- $this->sql_report('start', $query);
- }
-
- $this->query_result = ($cache_ttl) ? $cache->sql_load($query) : false;
- $this->sql_add_num_queries($this->query_result);
-
- if ($this->query_result === false)
- {
- if (($this->query_result = @sqlite_query($query, $this->db_connect_id)) === false)
- {
- $this->sql_error($query);
- }
-
- if (defined('DEBUG'))
- {
- $this->sql_report('stop', $query);
- }
-
- if ($cache_ttl)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl);
- }
- else if (strpos($query, 'SELECT') === 0 && $this->query_result)
- {
- $this->open_queries[(int) $this->query_result] = $this->query_result;
- }
- }
- else if (defined('DEBUG'))
- {
- $this->sql_report('fromcache', $query);
- }
- }
- else
- {
- return false;
- }
-
- return $this->query_result;
- }
-
- /**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- // if $total is set to 0 we do not want to limit the number of rows
- if ($total == 0)
- {
- $total = -1;
- }
-
- $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total);
-
- return $this->sql_query($query, $cache_ttl);
- }
-
- /**
- * Return number of affected rows
- */
- function sql_affectedrows()
- {
- return ($this->db_connect_id) ? @sqlite_changes($this->db_connect_id) : false;
- }
-
- /**
- * Fetch current row
- */
- function sql_fetchrow($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_fetchrow($query_id);
- }
-
- return ($query_id !== false) ? @sqlite_fetch_array($query_id, SQLITE_ASSOC) : false;
- }
-
- /**
- * Seek to given row number
- * rownum is zero-based
- */
- function sql_rowseek($rownum, &$query_id)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_rowseek($rownum, $query_id);
- }
-
- return ($query_id !== false) ? @sqlite_seek($query_id, $rownum) : false;
- }
-
- /**
- * Get last inserted id after insert statement
- */
- function sql_nextid()
- {
- return ($this->db_connect_id) ? @sqlite_last_insert_rowid($this->db_connect_id) : false;
- }
-
- /**
- * Free sql result
- */
- function sql_freeresult($query_id = false)
- {
- global $cache;
-
- if ($query_id === false)
- {
- $query_id = $this->query_result;
- }
-
- if ($cache->sql_exists($query_id))
- {
- return $cache->sql_freeresult($query_id);
- }
-
- return true;
- }
-
- /**
- * Escape string used in sql query
- */
- function sql_escape($msg)
- {
- return @sqlite_escape_string($msg);
- }
-
- /**
- * Correctly adjust LIKE expression for special characters
- * For SQLite an underscore is a not-known character... this may change with SQLite3
- */
- function sql_like_expression($expression)
- {
- // Unlike LIKE, GLOB is case sensitive (unfortunatly). SQLite users need to live with it!
- // We only catch * and ? here, not the character map possible on file globbing.
- $expression = str_replace(array(chr(0) . '_', chr(0) . '%'), array(chr(0) . '?', chr(0) . '*'), $expression);
-
- $expression = str_replace(array('?', '*'), array("\?", "\*"), $expression);
- $expression = str_replace(array(chr(0) . "\?", chr(0) . "\*"), array('?', '*'), $expression);
-
- return 'GLOB \'' . $this->sql_escape($expression) . '\'';
- }
-
- /**
- * return sql error array
- * @access private
- */
- function _sql_error()
- {
- return array(
- 'message' => @sqlite_error_string(@sqlite_last_error($this->db_connect_id)),
- 'code' => @sqlite_last_error($this->db_connect_id)
- );
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- return $data;
- }
-
- /**
- * Close sql connection
- * @access private
- */
- function _sql_close()
- {
- return @sqlite_close($this->db_connect_id);
- }
-
- /**
- * Build db-specific report
- * @access private
- */
- function _sql_report($mode, $query = '')
- {
- switch ($mode)
- {
- case 'start':
- break;
-
- case 'fromcache':
- $endtime = explode(' ', microtime());
- $endtime = $endtime[0] + $endtime[1];
-
- $result = @sqlite_query($query, $this->db_connect_id);
- while ($void = @sqlite_fetch_array($result, SQLITE_ASSOC))
- {
- // Take the time spent on parsing rows into account
- }
-
- $splittime = explode(' ', microtime());
- $splittime = $splittime[0] + $splittime[1];
-
- $this->sql_report('record_fromcache', $query, $endtime, $splittime);
-
- break;
- }
- }
-}
diff --git a/phpBB/includes/di/extension/config.php b/phpBB/includes/di/extension/config.php
deleted file mode 100644
index fb5ca90070..0000000000
--- a/phpBB/includes/di/extension/config.php
+++ /dev/null
@@ -1,83 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\HttpKernel\DependencyInjection\Extension;
-use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
-use Symfony\Component\Config\FileLocator;
-
-/**
-* Container config extension
-*/
-class phpbb_di_extension_config extends Extension
-{
- public function __construct($config_file)
- {
- $this->config_file = $config_file;
- }
-
- /**
- * Loads a specific configuration.
- *
- * @param array $config An array of configuration values
- * @param ContainerBuilder $container A ContainerBuilder instance
- *
- * @throws InvalidArgumentException When provided tag is not defined in this extension
- */
- public function load(array $config, ContainerBuilder $container)
- {
- require($this->config_file);
-
- $container->setParameter('core.table_prefix', $table_prefix);
- $container->setParameter('cache.driver.class', $this->fix_acm_type($acm_type));
- $container->setParameter('dbal.driver.class', 'dbal_'.$dbms);
- $container->setParameter('dbal.dbhost', $dbhost);
- $container->setParameter('dbal.dbuser', $dbuser);
- $container->setParameter('dbal.dbpasswd', $dbpasswd);
- $container->setParameter('dbal.dbname', $dbname);
- $container->setParameter('dbal.dbport', $dbport);
- $container->setParameter('dbal.new_link', defined('PHPBB_DB_NEW_LINK') && PHPBB_DB_NEW_LINK);
- }
-
- /**
- * Returns the recommended alias to use in XML.
- *
- * This alias is also the mandatory prefix to use when using YAML.
- *
- * @return string The alias
- */
- public function getAlias()
- {
- return 'config';
- }
-
- /**
- * Convert old (3.0) values to 3.1 class names
- *
- * @param style $acm_type ACM type
- * @return ACM type class
- */
- protected function fix_acm_type($acm_type)
- {
- if (preg_match('#^[a-z]+$#', $acm_type))
- {
- return 'phpbb_cache_driver_'.$acm_type;
- }
-
- return $acm_type;
- }
-}
diff --git a/phpBB/includes/di/extension/core.php b/phpBB/includes/di/extension/core.php
deleted file mode 100644
index 9c36ba2fc4..0000000000
--- a/phpBB/includes/di/extension/core.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\HttpKernel\DependencyInjection\Extension;
-use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
-use Symfony\Component\Config\FileLocator;
-
-/**
-* Container core extension
-*/
-class phpbb_di_extension_core extends Extension
-{
- /**
- * phpBB Root path
- * @var string
- */
- protected $root_path;
-
- /**
- * Constructor
- *
- * @param string $root_path Root path
- */
- public function __construct($root_path)
- {
- $this->root_path = $root_path;
- }
-
- /**
- * Loads a specific configuration.
- *
- * @param array $config An array of configuration values
- * @param ContainerBuilder $container A ContainerBuilder instance
- *
- * @throws InvalidArgumentException When provided tag is not defined in this extension
- */
- public function load(array $config, ContainerBuilder $container)
- {
- $loader = new YamlFileLoader($container, new FileLocator(phpbb_realpath($this->root_path . 'config')));
- $loader->load('services.yml');
- }
-
- /**
- * Returns the recommended alias to use in XML.
- *
- * This alias is also the mandatory prefix to use when using YAML.
- *
- * @return string The alias
- */
- public function getAlias()
- {
- return 'core';
- }
-}
diff --git a/phpBB/includes/di/extension/ext.php b/phpBB/includes/di/extension/ext.php
deleted file mode 100644
index 7d9b433751..0000000000
--- a/phpBB/includes/di/extension/ext.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\HttpKernel\DependencyInjection\Extension;
-use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
-use Symfony\Component\Config\FileLocator;
-
-/**
-* Container ext extension
-*/
-class phpbb_di_extension_ext extends Extension
-{
- protected $paths = array();
-
- public function __construct($enabled_extensions)
- {
- foreach ($enabled_extensions as $ext => $path)
- {
- $this->paths[] = $path;
- }
- }
-
- /**
- * Loads a specific configuration.
- *
- * @param array $config An array of configuration values
- * @param ContainerBuilder $container A ContainerBuilder instance
- *
- * @throws InvalidArgumentException When provided tag is not defined in this extension
- */
- public function load(array $config, ContainerBuilder $container)
- {
- foreach ($this->paths as $path)
- {
- if (file_exists($path . '/config/services.yml'))
- {
- $loader = new YamlFileLoader($container, new FileLocator(phpbb_realpath($path . '/config')));
- $loader->load('services.yml');
- }
- }
- }
-
- /**
- * Returns the recommended alias to use in XML.
- *
- * This alias is also the mandatory prefix to use when using YAML.
- *
- * @return string The alias
- */
- public function getAlias()
- {
- return 'ext';
- }
-}
diff --git a/phpBB/includes/di/pass/collection_pass.php b/phpBB/includes/di/pass/collection_pass.php
deleted file mode 100644
index 63a5c7dfc4..0000000000
--- a/phpBB/includes/di/pass/collection_pass.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
-
-/**
-* Appends an add method call to the definition of each collection service for
-* the services tagged with the appropriate name defined in the collection's
-* service_collection tag.
-*/
-class phpbb_di_pass_collection_pass implements CompilerPassInterface
-{
- /**
- * Modify the container before it is passed to the rest of the code
- *
- * @param ContainerBuilder $container ContainerBuilder object
- * @return null
- */
- public function process(ContainerBuilder $container)
- {
- foreach ($container->findTaggedServiceIds('service_collection') as $id => $data)
- {
- $definition = $container->getDefinition($id);
-
- foreach ($container->findTaggedServiceIds($data[0]['tag']) as $service_id => $service_data)
- {
- $definition->addMethodCall('add', array($service_id));
- }
- }
- }
-}
diff --git a/phpBB/includes/di/pass/kernel_pass.php b/phpBB/includes/di/pass/kernel_pass.php
deleted file mode 100644
index a701ebcfa6..0000000000
--- a/phpBB/includes/di/pass/kernel_pass.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
-
-class phpbb_di_pass_kernel_pass implements CompilerPassInterface
-{
- /**
- * Modify the container before it is passed to the rest of the code
- *
- * @param ContainerBuilder $container ContainerBuilder object
- * @return null
- */
- public function process(ContainerBuilder $container)
- {
- $definition = $container->getDefinition('dispatcher');
-
- foreach ($container->findTaggedServiceIds('kernel.event_listener') as $id => $events)
- {
- foreach ($events as $event)
- {
- $priority = isset($event['priority']) ? $event['priority'] : 0;
-
- if (!isset($event['event']))
- {
- throw new InvalidArgumentException(sprintf('Service "%1$s" must define the "event" attribute on "kernel.event_listener" tags.', $id));
- }
-
- if (!isset($event['method']))
- {
- throw new InvalidArgumentException(sprintf('Service "%1$s" must define the "method" attribute on "kernel.event_listener" tags.', $id));
- }
-
- $definition->addMethodCall('addListenerService', array($event['event'], array($id, $event['method']), $priority));
- }
- }
-
- foreach ($container->findTaggedServiceIds('kernel.event_subscriber') as $id => $attributes)
- {
- // We must assume that the class value has been correctly filled, even if the service is created by a factory
- $class = $container->getDefinition($id)->getClass();
-
- $refClass = new ReflectionClass($class);
- $interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
- if (!$refClass->implementsInterface($interface))
- {
- throw new InvalidArgumentException(sprintf('Service "%1$s" must implement interface "%2$s".', $id, $interface));
- }
-
- $definition->addMethodCall('addSubscriberService', array($id, $class));
- }
- }
-}
diff --git a/phpBB/includes/di/service_collection.php b/phpBB/includes/di/service_collection.php
deleted file mode 100644
index 60323c8dba..0000000000
--- a/phpBB/includes/di/service_collection.php
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
-* Collection of services to be configured at container compile time.
-*
-* @package phpBB3
-*/
-class phpbb_di_service_collection extends ArrayObject
-{
- /**
- * Constructor
- *
- * @param ContainerInterface $container Container object
- */
- public function __construct(ContainerInterface $container)
- {
- $this->container = $container;
- }
-
- /**
- * Add a service to the collection
- *
- * @param string $name The service name
- * @return null
- */
- public function add($name)
- {
- $task = $this->container->get($name);
- $task->set_name($name);
- $this->offsetSet($name, $task);
- }
-}
diff --git a/phpBB/includes/error_collector.php b/phpBB/includes/error_collector.php
deleted file mode 100644
index 358da747b8..0000000000
--- a/phpBB/includes/error_collector.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-/**
-*
-* @package phpBB
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-class phpbb_error_collector
-{
- var $errors;
-
- function phpbb_error_collector()
- {
- $this->errors = array();
- }
-
- function install()
- {
- set_error_handler(array(&$this, 'error_handler'));
- }
-
- function uninstall()
- {
- restore_error_handler();
- }
-
- function error_handler($errno, $msg_text, $errfile, $errline)
- {
- $this->errors[] = array($errno, $msg_text, $errfile, $errline);
- }
-
- function format_errors()
- {
- $text = '';
- foreach ($this->errors as $error)
- {
- if (!empty($text))
- {
- $text .= "<br />\n";
- }
-
- list($errno, $msg_text, $errfile, $errline) = $error;
-
- // Prevent leakage of local path to phpBB install
- $errfile = phpbb_filter_root_path($errfile);
-
- $text .= "Errno $errno: $msg_text at $errfile line $errline";
- }
-
- return $text;
- }
-}
diff --git a/phpBB/includes/event/data.php b/phpBB/includes/event/data.php
deleted file mode 100644
index 70718ff0ae..0000000000
--- a/phpBB/includes/event/data.php
+++ /dev/null
@@ -1,68 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\EventDispatcher\Event;
-
-class phpbb_event_data extends Event implements ArrayAccess
-{
- private $data;
-
- public function __construct(array $data = array())
- {
- $this->set_data($data);
- }
-
- public function set_data(array $data = array())
- {
- $this->data = $data;
- }
-
- public function get_data()
- {
- return $this->data;
- }
-
- /**
- * Returns data filtered to only include specified keys.
- *
- * This effectively discards any keys added to data by hooks.
- */
- public function get_data_filtered($keys)
- {
- return array_intersect_key($this->data, array_flip($keys));
- }
-
- public function offsetExists($offset)
- {
- return isset($this->data[$offset]);
- }
-
- public function offsetGet($offset)
- {
- return isset($this->data[$offset]) ? $this->data[$offset] : null;
- }
-
- public function offsetSet($offset, $value)
- {
- $this->data[$offset] = $value;
- }
-
- public function offsetUnset($offset)
- {
- unset($this->data[$offset]);
- }
-}
diff --git a/phpBB/includes/event/dispatcher.php b/phpBB/includes/event/dispatcher.php
deleted file mode 100644
index 4f637ce3bb..0000000000
--- a/phpBB/includes/event/dispatcher.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
-
-/**
-* Extension of the Symfony2 EventDispatcher
-*
-* It provides an additional `trigger_event` method, which
-* gives some syntactic sugar for dispatching events. Instead
-* of creating the event object, the method will do that for
-* you.
-*
-* Example:
-*
-* $vars = array('page_title');
-* extract($phpbb_dispatcher->trigger_event('core.index', compact($vars)));
-*
-*/
-class phpbb_event_dispatcher extends ContainerAwareEventDispatcher
-{
- public function trigger_event($eventName, $data = array())
- {
- $event = new phpbb_event_data($data);
- $this->dispatch($eventName, $event);
- return $event->get_data_filtered(array_keys($data));
- }
-}
diff --git a/phpBB/includes/event/extension_subscriber_loader.php b/phpBB/includes/event/extension_subscriber_loader.php
deleted file mode 100644
index d933b943d7..0000000000
--- a/phpBB/includes/event/extension_subscriber_loader.php
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-
-class phpbb_event_extension_subscriber_loader
-{
- private $dispatcher;
- private $extension_manager;
-
- public function __construct(EventDispatcherInterface $dispatcher, phpbb_extension_manager $extension_manager)
- {
- $this->dispatcher = $dispatcher;
- $this->extension_manager = $extension_manager;
- }
-
- public function load()
- {
- $finder = $this->extension_manager->get_finder();
- $subscriber_classes = $finder
- ->extension_directory('/event')
- ->suffix('listener')
- ->core_path('event/')
- ->get_classes();
-
- foreach ($subscriber_classes as $class)
- {
- $subscriber = new $class();
- $this->dispatcher->addSubscriber($subscriber);
- }
- }
-}
diff --git a/phpBB/includes/event/kernel_exception_subscriber.php b/phpBB/includes/event/kernel_exception_subscriber.php
deleted file mode 100644
index f90989a74c..0000000000
--- a/phpBB/includes/event/kernel_exception_subscriber.php
+++ /dev/null
@@ -1,85 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
-use Symfony\Component\HttpKernel\Exception\HttpException;
-use Symfony\Component\HttpFoundation\Response;
-
-class phpbb_event_kernel_exception_subscriber implements EventSubscriberInterface
-{
- /**
- * Template object
- * @var phpbb_template
- */
- protected $template;
-
- /**
- * User object
- * @var phpbb_user
- */
- protected $user;
-
- /**
- * Construct method
- *
- * @param phpbb_template $template Template object
- * @param phpbb_user $user User object
- */
- public function __construct(phpbb_template $template, phpbb_user $user)
- {
- $this->template = $template;
- $this->user = $user;
- }
-
- /**
- * This listener is run when the KernelEvents::EXCEPTION event is triggered
- *
- * @param GetResponseForExceptionEvent $event
- * @return null
- */
- public function on_kernel_exception(GetResponseForExceptionEvent $event)
- {
- page_header($this->user->lang('INFORMATION'));
-
- $exception = $event->getException();
-
- $this->template->assign_vars(array(
- 'MESSAGE_TITLE' => $this->user->lang('INFORMATION'),
- 'MESSAGE_TEXT' => $exception->getMessage(),
- ));
-
- $this->template->set_filenames(array(
- 'body' => 'message_body.html',
- ));
-
- page_footer(true, false, false);
-
-
- $status_code = $exception instanceof HttpException ? $exception->getStatusCode() : 500;
- $response = new Response($this->template->assign_display('body'), $status_code);
- $event->setResponse($response);
- }
-
- public static function getSubscribedEvents()
- {
- return array(
- KernelEvents::EXCEPTION => 'on_kernel_exception',
- );
- }
-}
diff --git a/phpBB/includes/event/kernel_request_subscriber.php b/phpBB/includes/event/kernel_request_subscriber.php
deleted file mode 100644
index afb8464f80..0000000000
--- a/phpBB/includes/event/kernel_request_subscriber.php
+++ /dev/null
@@ -1,83 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\GetResponseEvent;
-use Symfony\Component\HttpKernel\EventListener\RouterListener;
-use Symfony\Component\Routing\RequestContext;
-
-class phpbb_event_kernel_request_subscriber implements EventSubscriberInterface
-{
- /**
- * Extension finder object
- * @var phpbb_extension_finder
- */
- protected $finder;
-
- /**
- * PHP extension
- * @var string
- */
- protected $php_ext;
-
- /**
- * Root path
- * @var string
- */
- protected $root_path;
-
- /**
- * Construct method
- *
- * @param phpbb_extension_finder $finder Extension finder object
- * @param string $root_path Root path
- * @param string $php_ext PHP extension
- */
- public function __construct(phpbb_extension_finder $finder, $root_path, $php_ext)
- {
- $this->finder = $finder;
- $this->root_path = $root_path;
- $this->php_ext = $php_ext;
- }
-
- /**
- * This listener is run when the KernelEvents::REQUEST event is triggered
- *
- * This is responsible for setting up the routing information
- *
- * @param GetResponseEvent $event
- * @return null
- */
- public function on_kernel_request(GetResponseEvent $event)
- {
- $request = $event->getRequest();
- $context = new RequestContext();
- $context->fromRequest($request);
-
- $matcher = phpbb_get_url_matcher($this->finder, $context, $this->root_path, $this->php_ext);
- $router_listener = new RouterListener($matcher, $context);
- $router_listener->onKernelRequest($event);
- }
-
- public static function getSubscribedEvents()
- {
- return array(
- KernelEvents::REQUEST => 'on_kernel_request',
- );
- }
-}
diff --git a/phpBB/includes/event/kernel_terminate_subscriber.php b/phpBB/includes/event/kernel_terminate_subscriber.php
deleted file mode 100644
index 1eaf890e42..0000000000
--- a/phpBB/includes/event/kernel_terminate_subscriber.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\PostResponseEvent;
-
-class phpbb_event_kernel_terminate_subscriber implements EventSubscriberInterface
-{
- /**
- * This listener is run when the KernelEvents::TERMINATE event is triggered
- * This comes after a Response has been sent to the server; this is
- * primarily cleanup stuff.
- *
- * @param PostResponseEvent $event
- * @return null
- */
- public function on_kernel_terminate(PostResponseEvent $event)
- {
- exit_handler();
- }
-
- public static function getSubscribedEvents()
- {
- return array(
- KernelEvents::TERMINATE => 'on_kernel_terminate',
- );
- }
-}
diff --git a/phpBB/includes/extension/base.php b/phpBB/includes/extension/base.php
deleted file mode 100644
index 9d076eb6c5..0000000000
--- a/phpBB/includes/extension/base.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-/**
-*
-* @package extension
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* A base class for extensions without custom enable/disable/purge code.
-*
-* @package extension
-*/
-class phpbb_extension_base implements phpbb_extension_interface
-{
- /**
- * Single enable step that does nothing
- *
- * @param mixed $old_state State returned by previous call of this method
- * @return false Indicates no further steps are required
- */
- public function enable_step($old_state)
- {
- return false;
- }
-
- /**
- * Single disable step that does nothing
- *
- * @param mixed $old_state State returned by previous call of this method
- * @return false Indicates no further steps are required
- */
- public function disable_step($old_state)
- {
- return false;
- }
-
- /**
- * Single purge step that does nothing
- *
- * @param mixed $old_state State returned by previous call of this method
- * @return false Indicates no further steps are required
- */
- public function purge_step($old_state)
- {
- return false;
- }
-}
diff --git a/phpBB/includes/extension/exception.php b/phpBB/includes/extension/exception.php
deleted file mode 100644
index e08a8912ea..0000000000
--- a/phpBB/includes/extension/exception.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-/**
-*
-* @package extension
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
- * Exception class for metadata
- */
-class phpbb_extension_exception extends UnexpectedValueException
-{
- public function __toString()
- {
- return $this->getMessage();
- }
-} \ No newline at end of file
diff --git a/phpBB/includes/extension/finder.php b/phpBB/includes/extension/finder.php
deleted file mode 100644
index fb19b98429..0000000000
--- a/phpBB/includes/extension/finder.php
+++ /dev/null
@@ -1,436 +0,0 @@
-<?php
-/**
-*
-* @package extension
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* The extension finder provides a simple way to locate files in active extensions
-*
-* @package extension
-*/
-class phpbb_extension_finder
-{
- protected $extension_manager;
- protected $phpbb_root_path;
- protected $cache;
- protected $php_ext;
-
- /**
- * The cache variable name used to store $this->cached_queries in $this->cache.
- *
- * Allows the use of multiple differently configured finders with the same cache.
- * @var string
- */
- protected $cache_name;
-
- /**
- * An associative array, containing all search parameters set in methods.
- * @var array
- */
- protected $query;
-
- /**
- * A map from md5 hashes of serialized queries to their previously retrieved
- * results.
- * @var array
- */
- protected $cached_queries;
-
- /**
- * Creates a new finder instance with its dependencies
- *
- * @param phpbb_extension_manager $extension_manager An extension manager
- * instance that provides the finder with a list of active
- * extensions and their locations
- * @param string $phpbb_root_path Path to the phpbb root directory
- * @param phpbb_cache_driver_interface $cache A cache instance or null
- * @param string $php_ext php file extension
- * @param string $cache_name The name of the cache variable, defaults to
- * _ext_finder
- */
- public function __construct(phpbb_extension_manager $extension_manager, $phpbb_root_path = '', phpbb_cache_driver_interface $cache = null, $php_ext = '.php', $cache_name = '_ext_finder')
- {
- $this->extension_manager = $extension_manager;
- $this->phpbb_root_path = $phpbb_root_path;
- $this->cache = $cache;
- $this->php_ext = $php_ext;
- $this->cache_name = $cache_name;
-
- $this->query = array(
- 'core_path' => false,
- 'core_suffix' => false,
- 'core_prefix' => false,
- 'core_directory' => false,
- 'extension_suffix' => false,
- 'extension_prefix' => false,
- 'extension_directory' => false,
- );
-
- $this->cached_queries = ($this->cache) ? $this->cache->get($this->cache_name) : false;
- }
-
- /**
- * Sets a core path to be searched in addition to extensions
- *
- * @param string $core_path The path relative to phpbb_root_path
- * @return phpbb_extension_finder This object for chaining calls
- */
- public function core_path($core_path)
- {
- $this->query['core_path'] = $core_path;
- return $this;
- }
-
- /**
- * Sets the suffix all files found in extensions and core must match.
- *
- * There is no default file extension, so to find PHP files only, you will
- * have to specify .php as a suffix. However when using get_classes, the .php
- * file extension is automatically added to suffixes.
- *
- * @param string $suffix A filename suffix
- * @return phpbb_extension_finder This object for chaining calls
- */
- public function suffix($suffix)
- {
- $this->core_suffix($suffix);
- $this->extension_suffix($suffix);
- return $this;
- }
-
- /**
- * Sets a suffix all files found in extensions must match
- *
- * There is no default file extension, so to find PHP files only, you will
- * have to specify .php as a suffix. However when using get_classes, the .php
- * file extension is automatically added to suffixes.
- *
- * @param string $extension_suffix A filename suffix
- * @return phpbb_extension_finder This object for chaining calls
- */
- public function extension_suffix($extension_suffix)
- {
- $this->query['extension_suffix'] = $extension_suffix;
- return $this;
- }
-
- /**
- * Sets a suffix all files found in the core path must match
- *
- * There is no default file extension, so to find PHP files only, you will
- * have to specify .php as a suffix. However when using get_classes, the .php
- * file extension is automatically added to suffixes.
- *
- * @param string $core_suffix A filename suffix
- * @return phpbb_extension_finder This object for chaining calls
- */
- public function core_suffix($core_suffix)
- {
- $this->query['core_suffix'] = $core_suffix;
- return $this;
- }
-
- /**
- * Sets the prefix all files found in extensions and core must match
- *
- * @param string $prefix A filename prefix
- * @return phpbb_extension_finder This object for chaining calls
- */
- public function prefix($prefix)
- {
- $this->core_prefix($prefix);
- $this->extension_prefix($prefix);
- return $this;
- }
-
- /**
- * Sets a prefix all files found in extensions must match
- *
- * @param string $extension_prefix A filename prefix
- * @return phpbb_extension_finder This object for chaining calls
- */
- public function extension_prefix($extension_prefix)
- {
- $this->query['extension_prefix'] = $extension_prefix;
- return $this;
- }
-
- /**
- * Sets a prefix all files found in the core path must match
- *
- * @param string $core_prefix A filename prefix
- * @return phpbb_extension_finder This object for chaining calls
- */
- public function core_prefix($core_prefix)
- {
- $this->query['core_prefix'] = $core_prefix;
- return $this;
- }
-
- /**
- * Sets a directory all files found in extensions and core must be contained in
- *
- * Automatically sets the core_directory if its value does not differ from
- * the current directory.
- *
- * @param string $directory
- * @return phpbb_extension_finder This object for chaining calls
- */
- public function directory($directory)
- {
- $this->core_directory($directory);
- $this->extension_directory($directory);
- return $this;
- }
-
- /**
- * Sets a directory all files found in extensions must be contained in
- *
- * @param string $extension_directory
- * @return phpbb_extension_finder This object for chaining calls
- */
- public function extension_directory($extension_directory)
- {
- $this->query['extension_directory'] = $this->sanitise_directory($extension_directory);
- return $this;
- }
-
- /**
- * Sets a directory all files found in the core path must be contained in
- *
- * @param string $core_directory
- * @return phpbb_extension_finder This object for chaining calls
- */
- public function core_directory($core_directory)
- {
- $this->query['core_directory'] = $this->sanitise_directory($core_directory);
- return $this;
- }
-
- /**
- * Removes occurances of /./ and makes sure path ends without trailing slash
- *
- * @param string $directory A directory pattern
- * @return string A cleaned up directory pattern
- */
- protected function sanitise_directory($directory)
- {
- $directory = preg_replace('#(?:^|/)\./#', '/', $directory);
- $dir_len = strlen($directory);
-
- if ($dir_len > 1 && $directory[$dir_len - 1] === '/')
- {
- $directory = substr($directory, 0, -1);
- }
-
- return $directory;
- }
-
- /**
- * Finds classes matching the configured options if they follow phpBB naming rules.
- *
- * The php file extension is automatically added to suffixes.
- *
- * Note: If a file is matched but contains a class name not following the
- * phpBB naming rules an incorrect class name will be returned.
- *
- * @param bool $cache Whether the result should be cached
- * @return array An array of found class names
- */
- public function get_classes($cache = true)
- {
- $this->query['extension_suffix'] .= $this->php_ext;
- $this->query['core_suffix'] .= $this->php_ext;
-
- $files = $this->find($cache, false);
-
- $classes = array();
- foreach ($files as $file => $ext_name)
- {
- $file = preg_replace('#^includes/#', '', $file);
-
- $classes[] = 'phpbb_' . str_replace('/', '_', substr($file, 0, -strlen($this->php_ext)));
- }
- return $classes;
- }
-
- /**
- * Finds all directories matching the configured options
- *
- * @param bool $cache Whether the result should be cached
- * @param bool $extension_keys Whether the result should have extension name as array key
- * @return array An array of paths to found directories
- */
- public function get_directories($cache = true, $extension_keys = false)
- {
- return $this->find_with_root_path($cache, true, $extension_keys);
- }
-
- /**
- * Finds all files matching the configured options.
- *
- * @param bool $cache Whether the result should be cached
- * @return array An array of paths to found files
- */
- public function get_files($cache = true)
- {
- return $this->find_with_root_path($cache, false);
- }
-
- /**
- * A wrapper around the general find which prepends a root path to results
- *
- * @param bool $cache Whether the result should be cached
- * @param bool $is_dir Directories will be returned when true, only files
- * otherwise
- * @param bool $extension_keys If true, result will be associative array
- * with extension name as key
- * @return array An array of paths to found items
- */
- protected function find_with_root_path($cache = true, $is_dir = false, $extension_keys = false)
- {
- $items = $this->find($cache, $is_dir);
-
- $result = array();
- foreach ($items as $item => $ext_name)
- {
- if ($extension_keys)
- {
- $result[$ext_name] = $this->phpbb_root_path . $item;
- }
- else
- {
- $result[] = $this->phpbb_root_path . $item;
- }
- }
-
- return $result;
- }
-
- /**
- * Finds all file system entries matching the configured options
- *
- * @param bool $cache Whether the result should be cached
- * @param bool $is_dir Directories will be returned when true, only files
- * otherwise
- * @return array An array of paths to found items
- */
- public function find($cache = true, $is_dir = false)
- {
- $this->query['is_dir'] = $is_dir;
- $query = md5(serialize($this->query));
-
- if (!defined('DEBUG') && $cache && isset($this->cached_queries[$query]))
- {
- return $this->cached_queries[$query];
- }
-
- $files = array();
-
- $extensions = $this->extension_manager->all_enabled();
-
- if ($this->query['core_path'])
- {
- $extensions['/'] = $this->phpbb_root_path . $this->query['core_path'];
- }
-
- foreach ($extensions as $name => $path)
- {
- $ext_name = $name;
-
- if (!file_exists($path))
- {
- continue;
- }
-
- if ($name === '/')
- {
- $location = $this->query['core_path'];
- $name = '';
- $suffix = $this->query['core_suffix'];
- $prefix = $this->query['core_prefix'];
- $directory = $this->query['core_directory'];
- }
- else
- {
- $location = 'ext/';
- $name .= '/';
- $suffix = $this->query['extension_suffix'];
- $prefix = $this->query['extension_prefix'];
- $directory = $this->query['extension_directory'];
- }
-
- // match only first directory if leading slash is given
- if ($directory === '/')
- {
- $directory_pattern = '^' . preg_quote(DIRECTORY_SEPARATOR, '#');
- }
- else if ($directory && $directory[0] === '/')
- {
- $directory_pattern = '^' . preg_quote(str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR, '#');
- }
- else
- {
- $directory_pattern = preg_quote(DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $directory) . DIRECTORY_SEPARATOR, '#');
- }
- if ($is_dir)
- {
- $directory_pattern .= '$';
- }
- $directory_pattern = '#' . $directory_pattern . '#';
-
- $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
- foreach ($iterator as $file_info)
- {
- $filename = $file_info->getFilename();
- if ($filename == '.' || $filename == '..')
- {
- continue;
- }
-
- if ($file_info->isDir() == $is_dir)
- {
- if ($is_dir)
- {
- $relative_path = $iterator->getInnerIterator()->getSubPath() . DIRECTORY_SEPARATOR . basename($filename) . DIRECTORY_SEPARATOR;
- if ($relative_path[0] !== DIRECTORY_SEPARATOR)
- {
- $relative_path = DIRECTORY_SEPARATOR . $relative_path;
- }
- }
- else
- {
- $relative_path = DIRECTORY_SEPARATOR . $iterator->getInnerIterator()->getSubPathname();
- }
-
- if ((!$suffix || substr($relative_path, -strlen($suffix)) === $suffix) &&
- (!$prefix || substr($filename, 0, strlen($prefix)) === $prefix) &&
- (!$directory || preg_match($directory_pattern, $relative_path)))
- {
- $files[str_replace(DIRECTORY_SEPARATOR, '/', $location . $name . substr($relative_path, 1))] = $ext_name;
- }
- }
- }
- }
-
- if ($cache && $this->cache)
- {
- $this->cached_queries[$query] = $files;
- $this->cache->put($this->cache_name, $this->cached_queries);
- }
-
- return $files;
- }
-}
diff --git a/phpBB/includes/extension/interface.php b/phpBB/includes/extension/interface.php
deleted file mode 100644
index 74ecb9b762..0000000000
--- a/phpBB/includes/extension/interface.php
+++ /dev/null
@@ -1,65 +0,0 @@
-<?php
-/**
-*
-* @package extension
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* The interface extension meta classes have to implement to run custom code
-* on enable/disable/purge.
-*
-* @package extension
-*/
-interface phpbb_extension_interface
-{
- /**
- * enable_step is executed on enabling an extension until it returns false.
- *
- * Calls to this function can be made in subsequent requests, when the
- * function is invoked through a webserver with a too low max_execution_time.
- *
- * @param mixed $old_state The return value of the previous call
- * of this method, or false on the first call
- * @return mixed Returns false after last step, otherwise
- * temporary state which is passed as an
- * argument to the next step
- */
- public function enable_step($old_state);
-
- /**
- * Disables the extension.
- *
- * Calls to this function can be made in subsequent requests, when the
- * function is invoked through a webserver with a too low max_execution_time.
- *
- * @param mixed $old_state The return value of the previous call
- * of this method, or false on the first call
- * @return null
- */
- public function disable_step($old_state);
-
- /**
- * purge_step is executed on purging an extension until it returns false.
- *
- * Calls to this function can be made in subsequent requests, when the
- * function is invoked through a webserver with a too low max_execution_time.
- *
- * @param mixed $old_state The return value of the previous call
- * of this method, or false on the first call
- * @return mixed Returns false after last step, otherwise
- * temporary state which is passed as an
- * argument to the next step
- */
- public function purge_step($old_state);
-}
diff --git a/phpBB/includes/extension/manager.php b/phpBB/includes/extension/manager.php
deleted file mode 100644
index bfd4edde93..0000000000
--- a/phpBB/includes/extension/manager.php
+++ /dev/null
@@ -1,493 +0,0 @@
-<?php
-/**
-*
-* @package extension
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* The extension manager provides means to activate/deactivate extensions.
-*
-* @package extension
-*/
-class phpbb_extension_manager
-{
- protected $db;
- protected $config;
- protected $cache;
- protected $php_ext;
- protected $extensions;
- protected $extension_table;
- protected $phpbb_root_path;
- protected $cache_name;
-
- /**
- * Creates a manager and loads information from database
- *
- * @param dbal $db A database connection
- * @param phpbb_config $config phpbb_config
- * @param string $extension_table The name of the table holding extensions
- * @param string $phpbb_root_path Path to the phpbb includes directory.
- * @param string $php_ext php file extension
- * @param phpbb_cache_driver_interface $cache A cache instance or null
- * @param string $cache_name The name of the cache variable, defaults to _ext
- */
- public function __construct(dbal $db, phpbb_config $config, $extension_table, $phpbb_root_path, $php_ext = '.php', phpbb_cache_driver_interface $cache = null, $cache_name = '_ext')
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->db = $db;
- $this->config = $config;
- $this->cache = $cache;
- $this->php_ext = $php_ext;
- $this->extension_table = $extension_table;
- $this->cache_name = $cache_name;
-
- $this->extensions = ($this->cache) ? $this->cache->get($this->cache_name) : false;
-
- if ($this->extensions === false)
- {
- $this->load_extensions();
- }
- }
-
- /**
- * Loads all extension information from the database
- *
- * @return null
- */
- public function load_extensions()
- {
- $this->extensions = array();
-
- // Do not try to load any extensions when installing or updating
- // Note: database updater invokes this code, and in 3.0
- // there is no extension table therefore the rest of this function
- // fails
- if (defined('IN_INSTALL'))
- {
- return;
- }
-
- $sql = 'SELECT *
- FROM ' . $this->extension_table;
-
- $result = $this->db->sql_query($sql);
- $extensions = $this->db->sql_fetchrowset($result);
- $this->db->sql_freeresult($result);
-
- foreach ($extensions as $extension)
- {
- $extension['ext_path'] = $this->get_extension_path($extension['ext_name']);
- $this->extensions[$extension['ext_name']] = $extension;
- }
-
- ksort($this->extensions);
-
- if ($this->cache)
- {
- $this->cache->put($this->cache_name, $this->extensions);
- }
- }
-
- /**
- * Generates the path to an extension
- *
- * @param string $name The name of the extension
- * @param bool $phpbb_relative Whether the path should be relative to phpbb root
- * @return string Path to an extension
- */
- public function get_extension_path($name, $phpbb_relative = false)
- {
- $name = str_replace('.', '', $name);
-
- return (($phpbb_relative) ? $this->phpbb_root_path : '') . 'ext/' . $name . '/';
- }
-
- /**
- * Instantiates the extension meta class for the extension with the given name
- *
- * @param string $name The extension name
- * @return phpbb_extension_interface Instance of the extension meta class or
- * phpbb_extension_base if the class does not exist
- */
- public function get_extension($name)
- {
- $extension_class_name = 'phpbb_ext_' . str_replace('/', '_', $name) . '_ext';
-
- if (class_exists($extension_class_name))
- {
- return new $extension_class_name;
- }
- else
- {
- return new phpbb_extension_base;
- }
- }
-
- /**
- * Instantiates the metadata manager for the extension with the given name
- *
- * @param string $name The extension name
- * @param string $template The template manager
- * @return phpbb_extension_metadata_manager Instance of the metadata manager
- */
- public function create_extension_metadata_manager($name, phpbb_template $template)
- {
- return new phpbb_extension_metadata_manager($name, $this->db, $this, $this->phpbb_root_path, $this->php_ext, $template, $this->config);
- }
-
- /**
- * Runs a step of the extension enabling process.
- *
- * Allows the exentension to enable in a long running script that works
- * in multiple steps across requests. State is kept for the extension
- * in the extensions table.
- *
- * @param string $name The extension's name
- * @return bool False if enabling is finished, true otherwise
- */
- public function enable_step($name)
- {
- // ignore extensions that are already enabled
- if (isset($this->extensions[$name]) && $this->extensions[$name]['ext_active'])
- {
- return false;
- }
-
- $old_state = (isset($this->extensions[$name]['ext_state'])) ? unserialize($this->extensions[$name]['ext_state']) : false;
-
- $extension = $this->get_extension($name);
- $state = $extension->enable_step($old_state);
-
- $active = ($state === false);
-
- $extension_data = array(
- 'ext_name' => $name,
- 'ext_active' => $active,
- 'ext_state' => serialize($state),
- );
-
- $this->extensions[$name] = $extension_data;
- $this->extensions[$name]['ext_path'] = $this->get_extension_path($extension_data['ext_name']);
- ksort($this->extensions);
-
- $sql = 'UPDATE ' . $this->extension_table . '
- SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
- WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
- $this->db->sql_query($sql);
-
- if (!$this->db->sql_affectedrows())
- {
- $sql = 'INSERT INTO ' . $this->extension_table . '
- ' . $this->db->sql_build_array('INSERT', $extension_data);
- $this->db->sql_query($sql);
- }
-
- if ($this->cache)
- {
- $this->cache->purge();
- }
-
- return !$active;
- }
-
- /**
- * Enables an extension
- *
- * This method completely enables an extension. But it could be long running
- * so never call this in a script that has a max_execution time.
- *
- * @param string $name The extension's name
- * @return null
- */
- public function enable($name)
- {
- while ($this->enable_step($name));
- }
-
- /**
- * Disables an extension
- *
- * Calls the disable method on the extension's meta class to allow it to
- * process the event.
- *
- * @param string $name The extension's name
- * @return bool False if disabling is finished, true otherwise
- */
- public function disable_step($name)
- {
- // ignore extensions that are already disabled
- if (!isset($this->extensions[$name]) || !$this->extensions[$name]['ext_active'])
- {
- return false;
- }
-
- $old_state = unserialize($this->extensions[$name]['ext_state']);
-
- $extension = $this->get_extension($name);
- $state = $extension->disable_step($old_state);
-
- // continue until the state is false
- if ($state !== false)
- {
- $extension_data = array(
- 'ext_state' => serialize($state),
- );
- $this->extensions[$name]['ext_state'] = serialize($state);
-
- $sql = 'UPDATE ' . $this->extension_table . '
- SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
- WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
- $this->db->sql_query($sql);
-
- if ($this->cache)
- {
- $this->cache->purge();
- }
-
- return true;
- }
-
- $extension_data = array(
- 'ext_active' => false,
- 'ext_state' => serialize(false),
- );
- $this->extensions[$name]['ext_active'] = false;
- $this->extensions[$name]['ext_state'] = serialize(false);
-
- $sql = 'UPDATE ' . $this->extension_table . '
- SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
- WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
- $this->db->sql_query($sql);
-
- if ($this->cache)
- {
- $this->cache->purge();
- }
-
- return false;
- }
-
- /**
- * Disables an extension
- *
- * Disables an extension completely at once. This process could run for a
- * while so never call this in a script that has a max_execution time.
- *
- * @param string $name The extension's name
- * @return null
- */
- public function disable($name)
- {
- while ($this->disable_step($name));
- }
-
- /**
- * Purge an extension
- *
- * Disables the extension first if active, and then calls purge on the
- * extension's meta class to delete the extension's database content.
- *
- * @param string $name The extension's name
- * @return bool False if purging is finished, true otherwise
- */
- public function purge_step($name)
- {
- // ignore extensions that do not exist
- if (!isset($this->extensions[$name]))
- {
- return false;
- }
-
- // disable first if necessary
- if ($this->extensions[$name]['ext_active'])
- {
- $this->disable($name);
- }
-
- $old_state = unserialize($this->extensions[$name]['ext_state']);
-
- $extension = $this->get_extension($name);
- $state = $extension->purge_step($old_state);
-
- // continue until the state is false
- if ($state !== false)
- {
- $extension_data = array(
- 'ext_state' => serialize($state),
- );
- $this->extensions[$name]['ext_state'] = serialize($state);
-
- $sql = 'UPDATE ' . $this->extension_table . '
- SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
- WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
- $this->db->sql_query($sql);
-
- if ($this->cache)
- {
- $this->cache->purge();
- }
-
- return true;
- }
-
- unset($this->extensions[$name]);
-
- $sql = 'DELETE FROM ' . $this->extension_table . "
- WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
- $this->db->sql_query($sql);
-
- if ($this->cache)
- {
- $this->cache->purge();
- }
-
- return false;
- }
-
- /**
- * Purge an extension
- *
- * Purges an extension completely at once. This process could run for a while
- * so never call this in a script that has a max_execution time.
- *
- * @param string $name The extension's name
- * @return null
- */
- public function purge($name)
- {
- while ($this->purge_step($name));
- }
-
- /**
- * Retrieves a list of all available extensions on the filesystem
- *
- * @return array An array with extension names as keys and paths to the
- * extension as values
- */
- public function all_available()
- {
- $available = array();
- if (!is_dir($this->phpbb_root_path . 'ext/'))
- {
- return $available;
- }
-
- $iterator = new RecursiveIteratorIterator(
- new RecursiveDirectoryIterator($this->phpbb_root_path . 'ext/'),
- RecursiveIteratorIterator::SELF_FIRST);
- foreach ($iterator as $file_info)
- {
- if ($file_info->isFile() && $file_info->getFilename() == 'ext' . $this->php_ext)
- {
- $ext_name = $iterator->getInnerIterator()->getSubPath();
-
- $ext_name = str_replace(DIRECTORY_SEPARATOR, '/', $ext_name);
-
- $available[$ext_name] = $this->phpbb_root_path . 'ext/' . $ext_name . '/';
- }
- }
- ksort($available);
- return $available;
- }
-
- /**
- * Retrieves all configured extensions.
- *
- * All enabled and disabled extensions are considered configured. A purged
- * extension that is no longer in the database is not configured.
- *
- * @return array An array with extension names as keys and and the
- * database stored extension information as values
- */
- public function all_configured()
- {
- $configured = array();
- foreach ($this->extensions as $name => $data)
- {
- $data['ext_path'] = $this->phpbb_root_path . $data['ext_path'];
- $configured[$name] = $data;
- }
- return $configured;
- }
-
- /**
- * Retrieves all enabled extensions.
- *
- * @return array An array with extension names as keys and and the
- * database stored extension information as values
- */
- public function all_enabled()
- {
- $enabled = array();
- foreach ($this->extensions as $name => $data)
- {
- if ($data['ext_active'])
- {
- $enabled[$name] = $this->phpbb_root_path . $data['ext_path'];
- }
- }
- return $enabled;
- }
-
- /**
- * Retrieves all disabled extensions.
- *
- * @return array An array with extension names as keys and and the
- * database stored extension information as values
- */
- public function all_disabled()
- {
- $disabled = array();
- foreach ($this->extensions as $name => $data)
- {
- if (!$data['ext_active'])
- {
- $disabled[$name] = $this->phpbb_root_path . $data['ext_path'];
- }
- }
- return $disabled;
- }
-
- /**
- * Check to see if a given extension is available on the filesystem
- *
- * @param string $name Extension name to check NOTE: Can be user input
- * @return bool Depending on whether or not the extension is available
- */
- public function available($name)
- {
- return file_exists($this->get_extension_path($name, true));
- }
-
- /**
- * Check to see if a given extension is enabled
- *
- * @param string $name Extension name to check
- * @return bool Depending on whether or not the extension is enabled
- */
- public function enabled($name)
- {
- return isset($this->extensions[$name]) && $this->extensions[$name]['ext_active'];
- }
-
- /**
- * Instantiates a phpbb_extension_finder.
- *
- * @return phpbb_extension_finder An extension finder instance
- */
- public function get_finder()
- {
- return new phpbb_extension_finder($this, $this->phpbb_root_path, $this->cache, $this->php_ext, $this->cache_name . '_finder');
- }
-}
diff --git a/phpBB/includes/extension/metadata_manager.php b/phpBB/includes/extension/metadata_manager.php
deleted file mode 100644
index ea85bd3c4e..0000000000
--- a/phpBB/includes/extension/metadata_manager.php
+++ /dev/null
@@ -1,338 +0,0 @@
-<?php
-/**
-*
-* @package extension
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* The extension metadata manager validates and gets meta-data for extensions
-*
-* @package extension
-*/
-class phpbb_extension_metadata_manager
-{
- protected $phpEx;
- protected $extension_manager;
- protected $db;
- protected $phpbb_root_path;
- protected $template;
- protected $ext_name;
- protected $metadata;
- protected $metadata_file;
-
- /**
- * Creates the metadata manager
- *
- * @param dbal $db A database connection
- * @param string $extension_manager An instance of the phpbb extension manager
- * @param string $phpbb_root_path Path to the phpbb includes directory.
- * @param string $phpEx php file extension
- */
- public function __construct($ext_name, dbal $db, phpbb_extension_manager $extension_manager, $phpbb_root_path, $phpEx = '.php', phpbb_template $template, phpbb_config $config)
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->db = $db;
- $this->config = $config;
- $this->phpEx = $phpEx;
- $this->template = $template;
- $this->extension_manager = $extension_manager;
- $this->ext_name = $ext_name;
- $this->metadata = array();
- $this->metadata_file = '';
- }
-
- /**
- * Processes and gets the metadata requested
- *
- * @param string $element All for all metadata that it has and is valid, otherwise specify which section you want by its shorthand term.
- * @return array Contains all of the requested metadata, throws an exception on failure
- */
- public function get_metadata($element = 'all')
- {
- $this->set_metadata_file();
-
- // Fetch the metadata
- $this->fetch_metadata();
-
- // Clean the metadata
- $this->clean_metadata_array();
-
- switch ($element)
- {
- case 'all':
- default:
- // Validate the metadata
- if (!$this->validate())
- {
- return false;
- }
-
- return $this->metadata;
- break;
-
- case 'name':
- return ($this->validate('name')) ? $this->metadata['name'] : false;
- break;
-
- case 'display-name':
- if (isset($this->metadata['extra']['display-name']))
- {
- return $this->metadata['extra']['display-name'];
- }
- else
- {
- return ($this->validate('name')) ? $this->metadata['name'] : false;
- }
- break;
- }
- }
-
- /**
- * Sets the filepath of the metadata file
- *
- * @return boolean Set to true if it exists, throws an exception on failure
- */
- private function set_metadata_file()
- {
- $ext_filepath = $this->extension_manager->get_extension_path($this->ext_name);
- $metadata_filepath = $this->phpbb_root_path . $ext_filepath . 'composer.json';
-
- $this->metadata_file = $metadata_filepath;
-
- if (!file_exists($this->metadata_file))
- {
- throw new phpbb_extension_exception('The required file does not exist: ' . $this->metadata_file);
- }
- }
-
- /**
- * Gets the contents of the composer.json file
- *
- * @return bool True if success, throws an exception on failure
- */
- private function fetch_metadata()
- {
- if (!file_exists($this->metadata_file))
- {
- throw new phpbb_extension_exception('The required file does not exist: ' . $this->metadata_file);
- }
- else
- {
- if (!($file_contents = file_get_contents($this->metadata_file)))
- {
- throw new phpbb_extension_exception('file_get_contents failed on ' . $this->metadata_file);
- }
-
- if (($metadata = json_decode($file_contents, true)) === NULL)
- {
- throw new phpbb_extension_exception('json_decode failed on ' . $this->metadata_file);
- }
-
- $this->metadata = $metadata;
-
- return true;
- }
- }
-
- /**
- * This array handles the cleaning of the array
- *
- * @return array Contains the cleaned metadata array
- */
- private function clean_metadata_array()
- {
- return $this->metadata;
- }
-
- /**
- * Validate fields
- *
- * @param string $name ("all" for display and enable validation
- * "display" for name, type, and authors
- * "name", "type")
- * @return Bool True if valid, throws an exception if invalid
- */
- public function validate($name = 'display')
- {
- // Basic fields
- $fields = array(
- 'name' => '#^[a-zA-Z0-9_\x7f-\xff]{2,}/[a-zA-Z0-9_\x7f-\xff]{2,}$#',
- 'type' => '#^phpbb3-extension$#',
- 'licence' => '#.+#',
- 'version' => '#.+#',
- );
-
- switch ($name)
- {
- case 'all':
- $this->validate('display');
-
- $this->validate_enable();
- break;
-
- case 'display':
- foreach ($fields as $field => $data)
- {
- $this->validate($field);
- }
-
- $this->validate_authors();
- break;
-
- default:
- if (isset($fields[$name]))
- {
- if (!isset($this->metadata[$name]))
- {
- throw new phpbb_extension_exception("Required meta field '$name' has not been set.");
- }
-
- if (!preg_match($fields[$name], $this->metadata[$name]))
- {
- throw new phpbb_extension_exception("Meta field '$name' is invalid.");
- }
- }
- break;
- }
-
- return true;
- }
-
- /**
- * Validates the contents of the authors field
- *
- * @return boolean True when passes validation, throws exception if invalid
- */
- public function validate_authors()
- {
- if (empty($this->metadata['authors']))
- {
- throw new phpbb_extension_exception("Required meta field 'authors' has not been set.");
- }
-
- foreach ($this->metadata['authors'] as $author)
- {
- if (!isset($author['name']))
- {
- throw new phpbb_extension_exception("Required meta field 'author name' has not been set.");
- }
- }
-
- return true;
- }
-
- /**
- * This array handles the verification that this extension can be enabled on this board
- *
- * @return bool True if validation succeeded, False if failed
- */
- public function validate_enable()
- {
- // Check for phpBB, PHP versions
- if (!$this->validate_require_phpbb() || !$this->validate_require_php())
- {
- return false;
- }
-
- return true;
- }
-
-
- /**
- * Validates the contents of the phpbb requirement field
- *
- * @return boolean True when passes validation
- */
- public function validate_require_phpbb()
- {
- if (!isset($this->metadata['require']['phpbb']))
- {
- return true;
- }
-
- return $this->_validate_version($this->metadata['require']['phpbb'], $this->config['version']);
- }
-
- /**
- * Validates the contents of the php requirement field
- *
- * @return boolean True when passes validation
- */
- public function validate_require_php()
- {
- if (!isset($this->metadata['require']['php']))
- {
- return true;
- }
-
- return $this->_validate_version($this->metadata['require']['php'], phpversion());
- }
-
- /**
- * Version validation helper
- *
- * @param string $string The string for comparing to a version
- * @param string $current_version The version to compare to
- * @return bool True/False if meets version requirements
- */
- private function _validate_version($string, $current_version)
- {
- // Allow them to specify their own comparison operator (ex: <3.1.2, >=3.1.0)
- $comparison_matches = false;
- preg_match('#[=<>]+#', $string, $comparison_matches);
-
- if (!empty($comparison_matches))
- {
- return version_compare($current_version, str_replace(array($comparison_matches[0], ' '), '', $string), $comparison_matches[0]);
- }
-
- return version_compare($current_version, $string, '>=');
- }
-
- /**
- * Outputs the metadata into the template
- *
- * @return null
- */
- public function output_template_data()
- {
- $this->template->assign_vars(array(
- 'META_NAME' => htmlspecialchars($this->metadata['name']),
- 'META_TYPE' => htmlspecialchars($this->metadata['type']),
- 'META_DESCRIPTION' => (isset($this->metadata['description'])) ? htmlspecialchars($this->metadata['description']) : '',
- 'META_HOMEPAGE' => (isset($this->metadata['homepage'])) ? $this->metadata['homepage'] : '',
- 'META_VERSION' => (isset($this->metadata['version'])) ? htmlspecialchars($this->metadata['version']) : '',
- 'META_TIME' => (isset($this->metadata['time'])) ? htmlspecialchars($this->metadata['time']) : '',
- 'META_LICENCE' => htmlspecialchars($this->metadata['licence']),
-
- 'META_REQUIRE_PHP' => (isset($this->metadata['require']['php'])) ? htmlspecialchars($this->metadata['require']['php']) : '',
- 'META_REQUIRE_PHP_FAIL' => !$this->validate_require_php(),
-
- 'META_REQUIRE_PHPBB' => (isset($this->metadata['require']['phpbb'])) ? htmlspecialchars($this->metadata['require']['phpbb']) : '',
- 'META_REQUIRE_PHPBB_FAIL' => !$this->validate_require_phpbb(),
-
- 'META_DISPLAY_NAME' => (isset($this->metadata['extra']['display-name'])) ? htmlspecialchars($this->metadata['extra']['display-name']) : '',
- ));
-
- foreach ($this->metadata['authors'] as $author)
- {
- $this->template->assign_block_vars('meta_authors', array(
- 'AUTHOR_NAME' => htmlspecialchars($author['name']),
- 'AUTHOR_EMAIL' => (isset($author['email'])) ? $author['email'] : '',
- 'AUTHOR_HOMEPAGE' => (isset($author['homepage'])) ? $author['homepage'] : '',
- 'AUTHOR_ROLE' => (isset($author['role'])) ? htmlspecialchars($author['role']) : '',
- ));
- }
- }
-}
diff --git a/phpBB/includes/extension/provider.php b/phpBB/includes/extension/provider.php
deleted file mode 100644
index 45b55e5cab..0000000000
--- a/phpBB/includes/extension/provider.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-/**
-*
-* @package extension
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Provides a set of items found in extensions.
-*
-* This abstract class is essentially a wrapper around item-specific
-* finding logic. It handles storing the extension manager via constructor
-* for the finding logic to use to find the items, and provides an
-* iterator interface over the items found by the finding logic.
-*
-* Items could be anything, for example template paths or cron task names.
-* Derived classes completely define what the items are.
-*
-* @package extension
-*/
-abstract class phpbb_extension_provider implements IteratorAggregate
-{
- /**
- * Array holding all found items
- * @var array|null
- */
- protected $items = null;
-
- /**
- * An extension manager to search for items in extensions
- * @var phpbb_extension_manager
- */
- protected $extension_manager;
-
- /**
- * Constructor. Loads all available items.
- *
- * @param phpbb_extension_manager $extension_manager phpBB extension manager
- */
- public function __construct(phpbb_extension_manager $extension_manager)
- {
- $this->extension_manager = $extension_manager;
- }
-
- /**
- * Finds items using the extension manager.
- *
- * @return array List of task names
- */
- abstract protected function find();
-
- /**
- * Retrieve an iterator over all items
- *
- * @return ArrayIterator An iterator for the array of template paths
- */
- public function getIterator()
- {
- if ($this->items === null)
- {
- $this->items = $this->find();
- }
-
- return new ArrayIterator($this->items);
- }
-}
diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php
index ebe9a9918d..4d2d704a43 100644
--- a/phpBB/includes/functions.php
+++ b/phpBB/includes/functions.php
@@ -97,7 +97,18 @@ function request_var($var_name, $default, $multibyte = false, $cookie = false, $
}
/**
-* Set config value. Creates missing config entry.
+* Sets a configuration option's value.
+*
+* Please note that this function does not update the is_dynamic value for
+* an already existing config option.
+*
+* @param string $config_name The configuration option's name
+* @param string $config_value New configuration value
+* @param bool $is_dynamic Whether this variable should be cached (false) or
+* if it changes too frequently (true) to be
+* efficiently cached.
+*
+* @return null
*
* @deprecated
*/
@@ -119,7 +130,15 @@ function set_config($config_name, $config_value, $is_dynamic = false, phpbb_conf
}
/**
-* Set dynamic config value with arithmetic operation.
+* Increments an integer config value directly in the database.
+*
+* @param string $config_name The configuration option's name
+* @param int $increment Amount to increment by
+* @param bool $is_dynamic Whether this variable should be cached (false) or
+* if it changes too frequently (true) to be
+* efficiently cached.
+*
+* @return null
*
* @deprecated
*/
@@ -827,7 +846,7 @@ function phpbb_is_writable($file)
*/
function phpbb_is_absolute($path)
{
- return ($path[0] == '/' || (DIRECTORY_SEPARATOR == '\\' && preg_match('#^[a-z]:[/\\\]#i', $path))) ? true : false;
+ return (isset($path[0]) && $path[0] == '/' || preg_match('#^[a-z]:[/\\\]#i', $path)) ? true : false;
}
/**
@@ -1030,31 +1049,33 @@ else
/**
* Eliminates useless . and .. components from specified path.
*
+* Deprecated, use filesystem class instead
+*
* @param string $path Path to clean
* @return string Cleaned path
+*
+* @deprecated
*/
function phpbb_clean_path($path)
{
- $exploded = explode('/', $path);
- $filtered = array();
- foreach ($exploded as $part)
- {
- if ($part === '.' && !empty($filtered))
- {
- continue;
- }
+ global $phpbb_container;
- if ($part === '..' && !empty($filtered) && $filtered[sizeof($filtered) - 1] !== '..')
- {
- array_pop($filtered);
- }
- else
+ if ($phpbb_container)
+ {
+ $phpbb_filesystem = $phpbb_container->get('filesystem');
+ }
+ else
+ {
+ // The container is not yet loaded, use a new instance
+ if (!class_exists('phpbb_filesystem'))
{
- $filtered[] = $part;
+ global $phpbb_root_path, $phpEx;
+ require($phpbb_root_path . 'includes/filesystem.' . $phpEx);
}
+ $phpbb_filesystem = new phpbb_filesystem();
}
- $path = implode('/', $filtered);
- return $path;
+
+ return $phpbb_filesystem->clean_path($path);
}
// functions used for building option fields
@@ -1328,7 +1349,7 @@ function phpbb_timezone_select($user, $default = '', $truncate = false)
function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $user_id = 0)
{
global $db, $user, $config;
- global $request;
+ global $request, $phpbb_container;
$post_time = ($post_time === 0 || $post_time > time()) ? time() : (int) $post_time;
@@ -1336,6 +1357,20 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
{
if ($forum_id === false || !sizeof($forum_id))
{
+ // Mark all forums read (index page)
+
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ // Mark all topic notifications read for this user
+ $phpbb_notifications->mark_notifications_read(array(
+ 'topic',
+ 'quote',
+ 'bookmark',
+ 'post',
+ 'approve_topic',
+ 'approve_post',
+ ), false, $user->data['user_id'], $post_time);
+
if ($config['load_db_lastread'] && $user->data['is_registered'])
{
// Mark all forums read (index page)
@@ -1390,6 +1425,32 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
$forum_id = array($forum_id);
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->mark_notifications_read_by_parent(array(
+ 'topic',
+ 'approve_topic',
+ ), $forum_id, $user->data['user_id'], $post_time);
+
+ // Mark all post/quote notifications read for this user in this forum
+ $topic_ids = array();
+ $sql = 'SELECT topic_id
+ FROM ' . TOPICS_TABLE . '
+ WHERE ' . $db->sql_in_set('forum_id', $forum_id);
+ $result = $db->sql_query($sql);
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $topic_ids[] = $row['topic_id'];
+ }
+ $db->sql_freeresult($result);
+
+ $phpbb_notifications->mark_notifications_read_by_parent(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ 'approve_post',
+ ), $topic_ids, $user->data['user_id'], $post_time);
+
// Add 0 to forums array to mark global announcements correctly
// $forum_id[] = 0;
@@ -1487,6 +1548,21 @@ function markread($mode, $forum_id = false, $topic_id = false, $post_time = 0, $
return;
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ // Mark post notifications read for this user in this topic
+ $phpbb_notifications->mark_notifications_read(array(
+ 'topic',
+ 'approve_topic',
+ ), $topic_id, $user->data['user_id'], $post_time);
+
+ $phpbb_notifications->mark_notifications_read_by_parent(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ 'approve_post',
+ ), $topic_id, $user->data['user_id'], $post_time);
+
if ($config['load_db_lastread'] && $user->data['is_registered'])
{
$sql = 'UPDATE ' . TOPICS_TRACK_TABLE . "
@@ -1898,7 +1974,7 @@ function get_unread_topics($user_id = false, $sql_extra = '', $sql_sort = '', $s
*/
function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_time = false, $mark_time_forum = false)
{
- global $db, $tracking_topics, $user, $config, $auth, $request;
+ global $db, $tracking_topics, $user, $config, $auth, $request, $phpbb_container;
// Determine the users last forum mark time if not given.
if ($mark_time_forum === false)
@@ -1923,7 +1999,7 @@ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_ti
// Handle update of unapproved topics info.
// Only update for moderators having m_approve permission for the forum.
- $sql_update_unapproved = ($auth->acl_get('m_approve', $forum_id)) ? '': 'AND t.topic_approved = 1';
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
// Check the forum for any left unread topics.
// If there are none, we mark the forum as read.
@@ -1943,8 +2019,8 @@ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_ti
AND tt.user_id = ' . $user->data['user_id'] . ')
WHERE t.forum_id = ' . $forum_id . '
AND t.topic_last_post_time > ' . $mark_time_forum . '
- AND t.topic_moved_id = 0 ' .
- $sql_update_unapproved . '
+ AND t.topic_moved_id = 0
+ AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.') . '
AND (tt.topic_id IS NULL
OR tt.mark_time < t.topic_last_post_time)';
$result = $db->sql_query_limit($sql, 1);
@@ -1968,8 +2044,8 @@ function update_forum_tracking_info($forum_id, $forum_last_post_time, $f_mark_ti
FROM ' . TOPICS_TABLE . ' t
WHERE t.forum_id = ' . $forum_id . '
AND t.topic_last_post_time > ' . $mark_time_forum . '
- AND t.topic_moved_id = 0 ' .
- $sql_update_unapproved;
+ AND t.topic_moved_id = 0
+ AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.');
$result = $db->sql_query($sql);
$check_forum = $tracking_topics['tf'][$forum_id];
@@ -2269,9 +2345,8 @@ function phpbb_generate_template_pagination($template, $base_url, $block_var_nam
$tpl_prefix . 'BASE_URL' => $base_url,
'A_' . $tpl_prefix . 'BASE_URL' => addslashes($base_url),
$tpl_prefix . 'PER_PAGE' => $per_page,
- $tpl_prefix . 'PREVIOUS_PAGE' => $previous_page,
- $tpl_prefix . 'PREV_PAGE' => $previous_page,
- $tpl_prefix . 'NEXT_PAGE' => ($on_page != $total_pages) ? $base_url . $url_delim . $start_name . '=' . ($on_page * $per_page) : '',
+ 'U_' . $tpl_prefix . 'PREVIOUS_PAGE' => $previous_page,
+ 'U_' . $tpl_prefix . 'NEXT_PAGE' => ($on_page != $total_pages) ? $base_url . $url_delim . $start_name . '=' . ($on_page * $per_page) : '',
$tpl_prefix . 'TOTAL_PAGES' => $total_pages,
$tpl_prefix . 'CURRENT_PAGE' => $on_page,
);
@@ -2338,6 +2413,7 @@ function append_sid($url, $params = false, $is_amp = true, $session_id = false)
{
global $_SID, $_EXTRA_URL, $phpbb_hook;
global $phpbb_dispatcher;
+ global $symfony_request, $phpbb_root_path;
if ($params === '' || (is_array($params) && empty($params)))
{
@@ -2345,6 +2421,12 @@ function append_sid($url, $params = false, $is_amp = true, $session_id = false)
$params = false;
}
+ $corrected_path = $symfony_request !== null ? phpbb_get_web_root_path($symfony_request, $phpbb_root_path) : '';
+ if ($corrected_path)
+ {
+ $url = substr($corrected_path . $url, strlen($phpbb_root_path));
+ }
+
$append_sid_overwrite = false;
/**
@@ -2657,7 +2739,7 @@ function redirect($url, $return = false, $disable_cd_check = false)
// Make sure no linebreaks are there... to prevent http response splitting for PHP < 4.4.2
if (strpos(urldecode($url), "\n") !== false || strpos(urldecode($url), "\r") !== false || strpos($url, ';') !== false)
{
- trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR);
+ trigger_error('INSECURE_REDIRECT', E_USER_ERROR);
}
// Now, also check the protocol and for a valid url the last time...
@@ -2666,7 +2748,7 @@ function redirect($url, $return = false, $disable_cd_check = false)
if ($url_parts === false || empty($url_parts['scheme']) || !in_array($url_parts['scheme'], $allowed_protocols))
{
- trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR);
+ trigger_error('INSECURE_REDIRECT', E_USER_ERROR);
}
if ($return)
@@ -2831,7 +2913,7 @@ function meta_refresh($time, $url, $disable_cd_check = false)
// For XHTML compatibility we change back & to &amp;
$template->assign_vars(array(
- 'META' => '<meta http-equiv="refresh" content="' . $time . ';url=' . $url . '" />')
+ 'META' => '<meta http-equiv="refresh" content="' . $time . '; url=' . $url . '" />')
);
}
@@ -3084,8 +3166,9 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo
'YES_VALUE' => $user->lang['YES'],
'S_CONFIRM_ACTION' => $u_action,
- 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields)
- );
+ 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields,
+ 'S_AJAX_REQUEST' => $request->is_ajax(),
+ ));
$sql = 'UPDATE ' . USERS_TABLE . " SET user_last_confirm_key = '" . $db->sql_escape($confirm_key) . "'
WHERE user_id = " . $user->data['user_id'];
@@ -3097,8 +3180,9 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo
$u_action .= '&confirm_uid=' . $user->data['user_id'] . '&sess=' . $user->session_id . '&sid=' . $user->session_id;
$json_response = new phpbb_json_response;
$json_response->send(array(
+ 'MESSAGE_BODY' => $template->assign_display('body'),
'MESSAGE_TITLE' => (!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title],
- 'MESSAGE_TEXT' => (!isset($user->lang[$title . '_CONFIRM'])) ? $title : $user->lang[$title . '_CONFIRM'],
+ 'MESSAGE_TEXT' => (!isset($user->lang[$title . '_CONFIRM'])) ? $title : $user->lang[$title . '_CONFIRM'],
'YES_VALUE' => $user->lang['YES'],
'S_CONFIRM_ACTION' => str_replace('&amp;', '&', $u_action), //inefficient, rewrite whole function
@@ -3224,8 +3308,7 @@ function login_box($redirect = '', $l_explain = '', $l_success = '', $admin = fa
return;
}
- $redirect = meta_refresh(3, $redirect);
- trigger_error($message . '<br /><br />' . sprintf($l_redirect, '<a href="' . $redirect . '">', '</a>'));
+ redirect($redirect);
}
// Something failed, determine what...
@@ -3389,6 +3472,7 @@ function login_forum_box($forum_data)
page_header($user->lang['LOGIN'], false);
$template->assign_vars(array(
+ 'FORUM_NAME' => isset($forum_data['forum_name']) ? $forum_data['forum_name'] : '',
'S_LOGIN_ACTION' => build_url(array('f')),
'S_HIDDEN_FIELDS' => build_hidden_fields(array('f' => $forum_data['forum_id'])))
);
@@ -3508,69 +3592,49 @@ function parse_cfg_file($filename, $lines = false)
}
/**
-* Add log event
+* Add log entry
+*
+* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
+* @param int $forum_id Mode 'mod' ONLY: forum id of the related item, NOT INCLUDED otherwise
+* @param int $topic_id Mode 'mod' ONLY: topic id of the related item, NOT INCLUDED otherwise
+* @param int $reportee_id Mode 'user' ONLY: user id of the reportee, NOT INCLUDED otherwise
+* @param string $log_operation Name of the operation
+* @param array $additional_data More arguments can be added, depending on the log_type
+*
+* @return int|bool Returns the log_id, if the entry was added to the database, false otherwise.
+*
+* @deprecated Use $phpbb_log->add() instead
*/
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;
- }
+ global $phpbb_log, $user;
$args = func_get_args();
+ $mode = array_shift($args);
- $mode = array_shift($args);
- $reportee_id = ($mode == 'user') ? intval(array_shift($args)) : '';
- $forum_id = ($mode == 'mod') ? intval(array_shift($args)) : '';
- $topic_id = ($mode == 'mod') ? intval(array_shift($args)) : '';
- $action = array_shift($args);
- $data = (!sizeof($args)) ? '' : serialize($args);
-
- $sql_ary = array(
- 'user_id' => (empty($user->data)) ? ANONYMOUS : $user->data['user_id'],
- 'log_ip' => $user->ip,
- 'log_time' => time(),
- 'log_operation' => $action,
- 'log_data' => $data,
- );
-
+ // This looks kind of dirty, but add_log has some additional data before the log_operation
+ $additional_data = array();
switch ($mode)
{
case 'admin':
- $sql_ary['log_type'] = LOG_ADMIN;
+ case 'critical':
break;
-
case 'mod':
- $sql_ary += array(
- 'log_type' => LOG_MOD,
- 'forum_id' => $forum_id,
- 'topic_id' => $topic_id
- );
+ $additional_data['forum_id'] = array_shift($args);
+ $additional_data['topic_id'] = array_shift($args);
break;
-
case 'user':
- $sql_ary += array(
- 'log_type' => LOG_USERS,
- 'reportee_id' => $reportee_id
- );
- break;
-
- case 'critical':
- $sql_ary['log_type'] = LOG_CRITICAL;
+ $additional_data['reportee_id'] = array_shift($args);
break;
-
- default:
- return false;
}
- $db->sql_query('INSERT INTO ' . LOG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
+ $log_operation = array_shift($args);
+ $additional_data = array_merge($additional_data, $args);
+
+ $user_id = (empty($user->data)) ? ANONYMOUS : $user->data['user_id'];
+ $user_ip = (empty($user->ip)) ? '' : $user->ip;
- return $db->sql_nextid();
+ return $phpbb_log->add($mode, $user_id, $user_ip, $log_operation, time(), $additional_data);
}
/**
@@ -4126,7 +4190,7 @@ function phpbb_checkdnsrr($host, $type = 'MX')
// Handler, header and footer
/**
-* Error and message handler, call with trigger_error if reqd
+* Error and message handler, call with trigger_error if read
*/
function msg_handler($errno, $msg_text, $errfile, $errline)
{
@@ -4894,12 +4958,107 @@ function phpbb_http_login($param)
}
/**
+* Escapes and quotes a string for use as an HTML/XML attribute value.
+*
+* This is a port of Python xml.sax.saxutils quoteattr.
+*
+* The function will attempt to choose a quote character in such a way as to
+* avoid escaping quotes in the string. If this is not possible the string will
+* be wrapped in double quotes and double quotes will be escaped.
+*
+* @param string $data The string to be escaped
+* @param array $entities Associative array of additional entities to be escaped
+* @return string Escaped and quoted string
+*/
+function phpbb_quoteattr($data, $entities = null)
+{
+ $data = str_replace('&', '&amp;', $data);
+ $data = str_replace('>', '&gt;', $data);
+ $data = str_replace('<', '&lt;', $data);
+
+ $data = str_replace("\n", '&#10;', $data);
+ $data = str_replace("\r", '&#13;', $data);
+ $data = str_replace("\t", '&#9;', $data);
+
+ if (!empty($entities))
+ {
+ $data = str_replace(array_keys($entities), array_values($entities), $data);
+ }
+
+ if (strpos($data, '"') !== false)
+ {
+ if (strpos($data, "'") !== false)
+ {
+ $data = '"' . str_replace('"', '&quot;', $data) . '"';
+ }
+ else
+ {
+ $data = "'" . $data . "'";
+ }
+ }
+ else
+ {
+ $data = '"' . $data . '"';
+ }
+
+ return $data;
+}
+
+/**
+* Converts query string (GET) parameters in request into hidden fields.
+*
+* Useful for forwarding GET parameters when submitting forms with GET method.
+*
+* It is possible to omit some of the GET parameters, which is useful if
+* they are specified in the form being submitted.
+*
+* sid is always omitted.
+*
+* @param phpbb_request $request Request object
+* @param array $exclude A list of variable names that should not be forwarded
+* @return string HTML with hidden fields
+*/
+function phpbb_build_hidden_fields_for_query_params($request, $exclude = null)
+{
+ $names = $request->variable_names(phpbb_request_interface::GET);
+ $hidden = '';
+ foreach ($names as $name)
+ {
+ // Sessions are dealt with elsewhere, omit sid always
+ if ($name == 'sid')
+ {
+ continue;
+ }
+
+ // Omit any additional parameters requested
+ if (!empty($exclude) && in_array($name, $exclude))
+ {
+ continue;
+ }
+
+ $escaped_name = phpbb_quoteattr($name);
+
+ // Note: we might retrieve the variable from POST or cookies
+ // here. To avoid exposing cookies, skip variables that are
+ // overwritten somewhere other than GET entirely.
+ $value = $request->variable($name, '', true);
+ $get_value = $request->variable($name, '', true, phpbb_request_interface::GET);
+ if ($value === $get_value)
+ {
+ $escaped_value = phpbb_quoteattr($value);
+ $hidden .= "<input type='hidden' name=$escaped_name value=$escaped_value />";
+ }
+ }
+ return $hidden;
+}
+
+/**
* Generate page header
*/
function page_header($page_title = '', $display_online_list = true, $item_id = 0, $item = 'forum')
{
global $db, $config, $template, $SID, $_SID, $_EXTRA_URL, $user, $auth, $phpEx, $phpbb_root_path;
- global $phpbb_dispatcher;
+ global $phpbb_dispatcher, $request, $phpbb_container, $symfony_request;
if (defined('HEADER_INC'))
{
@@ -5056,7 +5215,11 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
// 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;
+ // This path is sent with the base template paths in the assign_vars()
+ // call below. We need to correct it in case we are accessing from a
+ // controller because the web paths will be incorrect otherwise.
+ $corrected_path = $symfony_request !== null ? phpbb_get_web_root_path($symfony_request, $phpbb_root_path) : '';
+ $web_path = (defined('PHPBB_USE_BOARD_URL_PATH') && PHPBB_USE_BOARD_URL_PATH) ? $board_url : $corrected_path;
// Send a proper content-language to the output
$user_lang = $user->lang['USER_LANG'];
@@ -5088,6 +5251,26 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
$timezone_name = $user->lang['timezones'][$timezone_name];
}
+ // Output the notifications
+ $notifications = false;
+ if ($config['load_notifications'] && $user->data['user_id'] != ANONYMOUS && $user->data['user_type'] != USER_IGNORE)
+ {
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $notifications = $phpbb_notifications->load_notifications(array(
+ 'all_unread' => true,
+ 'limit' => 5,
+ ));
+
+ foreach ($notifications['notifications'] as $notification)
+ {
+ $template->assign_block_vars('notifications', $notification->prepare_for_display());
+ }
+ }
+
+ $hidden_fields_for_jumpbox = phpbb_build_hidden_fields_for_query_params($request, array('f'));
+
+
// The following assigns all _common_ variables that may be used at any point in a template.
$template->assign_vars(array(
'SITENAME' => $config['sitename'],
@@ -5102,6 +5285,13 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
'RECORD_USERS' => $l_online_record,
'PRIVATE_MESSAGE_INFO' => $l_privmsgs_text,
'PRIVATE_MESSAGE_INFO_UNREAD' => $l_privmsgs_text_unread,
+ 'HIDDEN_FIELDS_FOR_JUMPBOX' => $hidden_fields_for_jumpbox,
+
+ 'UNREAD_NOTIFICATIONS_COUNT' => ($notifications !== false) ? $notifications['unread_count'] : '',
+ 'NOTIFICATIONS_COUNT' => ($notifications !== false) ? $user->lang('NOTIFICATIONS_COUNT', $notifications['unread_count']) : '',
+ 'U_VIEW_ALL_NOTIFICATIONS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_notifications'),
+ 'U_NOTIFICATION_SETTINGS' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=ucp_notifications&amp;mode=notification_options'),
+ 'S_NOTIFICATIONS_DISPLAY' => $config['load_notifications'],
'S_USER_NEW_PRIVMSG' => $user->data['user_new_privmsg'],
'S_USER_UNREAD_PRIVMSG' => $user->data['user_unread_privmsg'],
@@ -5114,7 +5304,7 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
'BOARD_URL' => $board_url,
'L_LOGIN_LOGOUT' => $l_login_logout,
- 'L_INDEX' => $user->lang['FORUM_INDEX'],
+ 'L_INDEX' => ($config['board_index_text'] !== '') ? $config['board_index_text'] : $user->lang['FORUM_INDEX'],
'L_SITE_HOME' => ($config['site_home_text'] !== '') ? $config['site_home_text'] : $user->lang['HOME'],
'L_ONLINE_EXPLAIN' => $l_online_time,
@@ -5211,8 +5401,6 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
'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')),
));
// application/xhtml+xml not used because of IE
@@ -5241,7 +5429,7 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
function page_footer($run_cron = true, $display_template = true, $exit_handler = true)
{
global $db, $config, $template, $user, $auth, $cache, $starttime, $phpbb_root_path, $phpEx;
- global $request, $phpbb_dispatcher;
+ global $request, $phpbb_dispatcher, $phpbb_admin_path;
// A listener can set this variable to `true` when it overrides this function
$page_footer_override = false;
@@ -5297,7 +5485,7 @@ function page_footer($run_cron = true, $display_template = true, $exit_handler =
'TRANSLATION_INFO' => (!empty($user->lang['TRANSLATION_INFO'])) ? $user->lang['TRANSLATION_INFO'] : '',
'CREDIT_LINE' => $user->lang('POWERED_BY', '<a href="https://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Group'),
- 'U_ACP' => ($auth->acl_get('a_') && !empty($user->data['is_registered'])) ? append_sid("{$phpbb_root_path}adm/index.$phpEx", false, true, $user->session_id) : '')
+ 'U_ACP' => ($auth->acl_get('a_') && !empty($user->data['is_registered'])) ? append_sid("{$phpbb_admin_path}index.$phpEx", false, true, $user->session_id) : '')
);
// Call cron-type script
@@ -5452,6 +5640,52 @@ function phpbb_to_numeric($input)
}
/**
+* Convert either 3.0 dbms or 3.1 db driver class name to 3.1 db driver class name.
+*
+* If $dbms is a valid 3.1 db driver class name, returns it unchanged.
+* Otherwise prepends phpbb_db_driver_ to the dbms to convert a 3.0 dbms
+* to 3.1 db driver class name.
+*
+* @param string $dbms dbms parameter
+* @return db driver class
+*/
+function phpbb_convert_30_dbms_to_31($dbms)
+{
+ // Note: this check is done first because mysqli extension
+ // supplies a mysqli class, and class_exists($dbms) would return
+ // true for mysqli class.
+ // However, per the docblock any valid 3.1 driver name should be
+ // recognized by this function, and have priority over 3.0 dbms.
+ if (class_exists('phpbb_db_driver_' . $dbms))
+ {
+ return 'phpbb_db_driver_' . $dbms;
+ }
+
+ if (class_exists($dbms))
+ {
+ // Additionally we could check that $dbms extends phpbb_db_driver.
+ // http://php.net/manual/en/class.reflectionclass.php
+ // Beware of possible performance issues:
+ // http://stackoverflow.com/questions/294582/php-5-reflection-api-performance
+ // We could check for interface implementation in all paths or
+ // only when we do not prepend phpbb_db_driver_.
+
+ /*
+ $reflection = new \ReflectionClass($dbms);
+
+ if ($reflection->isSubclassOf('phpbb_db_driver'))
+ {
+ return $dbms;
+ }
+ */
+
+ return $dbms;
+ }
+
+ throw new \RuntimeException("You have specified an invalid dbms driver: $dbms");
+}
+
+/**
* Create a Symfony Request object from phpbb_request object
*
* @param phpbb_request $request Request object
@@ -5459,6 +5693,16 @@ function phpbb_to_numeric($input)
*/
function phpbb_create_symfony_request(phpbb_request $request)
{
+ // If we have already gotten it, don't go back through all the trouble of
+ // creating it again; instead, just return it. This allows multiple calls
+ // of this method so we don't have to globalize $symfony_request in other
+ // functions.
+ static $symfony_request;
+ if (null !== $symfony_request)
+ {
+ return $symfony_request;
+ }
+
// This function is meant to sanitize the global input arrays
$sanitizer = function(&$value, $key) {
$type_cast_helper = new phpbb_request_type_cast_helper();
@@ -5478,21 +5722,39 @@ function phpbb_create_symfony_request(phpbb_request $request)
array_walk_recursive($get_parameters, $sanitizer);
array_walk_recursive($post_parameters, $sanitizer);
- // Until we fix the issue with relative paths, we have to fake path info
- // to allow urls like app.php?controller=foo/bar
- $controller = $request->variable('controller', '');
- $path_info = '/' . $controller;
- $request_uri = $server_parameters['REQUEST_URI'];
+ $symfony_request = new Request($get_parameters, $post_parameters, array(), $cookie_parameters, $files_parameters, $server_parameters);
+ return $symfony_request;
+}
+
+/**
+* Get a relative root path from the current URL
+*
+* @param Request $symfony_request Symfony Request object
+*/
+function phpbb_get_web_root_path(Request $symfony_request, $phpbb_root_path = '')
+{
+ static $path;
+ if (null !== $path)
+ {
+ return $path;
+ }
- // Remove the query string from REQUEST_URI
- if ($pos = strpos($request_uri, '?'))
+ $path_info = $symfony_request->getPathInfo();
+ if ($path_info === '/')
{
- $request_uri = substr($request_uri, 0, $pos);
+ $path = $phpbb_root_path;
+ return $path;
}
- // Add the path info (i.e. controller route) to the REQUEST_URI
- $server_parameters['REQUEST_URI'] = $request_uri . $path_info;
- $server_parameters['SCRIPT_NAME'] = '';
+ $corrections = substr_count($path_info, '/');
- return new Request($get_parameters, $post_parameters, array(), $cookie_parameters, $files_parameters, $server_parameters);
+ // When URL Rewriting is enabled, app.php is optional. We have to
+ // correct for it not being there
+ if (strpos($symfony_request->getRequestUri(), $symfony_request->getScriptName()) === false)
+ {
+ $corrections -= 1;
+ }
+
+ $path = $phpbb_root_path . str_repeat('../', $corrections);
+ return $path;
}
diff --git a/phpBB/includes/functions_acp.php b/phpBB/includes/functions_acp.php
index 2f3fd7bac0..60c44e90e1 100644
--- a/phpBB/includes/functions_acp.php
+++ b/phpBB/includes/functions_acp.php
@@ -82,16 +82,18 @@ function adm_page_header($page_title)
'T_RANKS_PATH' => "{$phpbb_root_path}{$config['ranks_path']}/",
'T_UPLOAD_PATH' => "{$phpbb_root_path}{$config['upload_path']}/",
- 'ICON_MOVE_UP' => '<img src="' . $phpbb_admin_path . 'images/icon_up.gif" alt="' . $user->lang['MOVE_UP'] . '" title="' . $user->lang['MOVE_UP'] . '" />',
- 'ICON_MOVE_UP_DISABLED' => '<img src="' . $phpbb_admin_path . 'images/icon_up_disabled.gif" alt="' . $user->lang['MOVE_UP'] . '" title="' . $user->lang['MOVE_UP'] . '" />',
- 'ICON_MOVE_DOWN' => '<img src="' . $phpbb_admin_path . 'images/icon_down.gif" alt="' . $user->lang['MOVE_DOWN'] . '" title="' . $user->lang['MOVE_DOWN'] . '" />',
- 'ICON_MOVE_DOWN_DISABLED' => '<img src="' . $phpbb_admin_path . 'images/icon_down_disabled.gif" alt="' . $user->lang['MOVE_DOWN'] . '" title="' . $user->lang['MOVE_DOWN'] . '" />',
- 'ICON_EDIT' => '<img src="' . $phpbb_admin_path . 'images/icon_edit.gif" alt="' . $user->lang['EDIT'] . '" title="' . $user->lang['EDIT'] . '" />',
- 'ICON_EDIT_DISABLED' => '<img src="' . $phpbb_admin_path . 'images/icon_edit_disabled.gif" alt="' . $user->lang['EDIT'] . '" title="' . $user->lang['EDIT'] . '" />',
- 'ICON_DELETE' => '<img src="' . $phpbb_admin_path . 'images/icon_delete.gif" alt="' . $user->lang['DELETE'] . '" title="' . $user->lang['DELETE'] . '" />',
- 'ICON_DELETE_DISABLED' => '<img src="' . $phpbb_admin_path . 'images/icon_delete_disabled.gif" alt="' . $user->lang['DELETE'] . '" title="' . $user->lang['DELETE'] . '" />',
- 'ICON_SYNC' => '<img src="' . $phpbb_admin_path . 'images/icon_sync.gif" alt="' . $user->lang['RESYNC'] . '" title="' . $user->lang['RESYNC'] . '" />',
- 'ICON_SYNC_DISABLED' => '<img src="' . $phpbb_admin_path . 'images/icon_sync_disabled.gif" alt="' . $user->lang['RESYNC'] . '" title="' . $user->lang['RESYNC'] . '" />',
+ 'T_ASSETS_VERSION' => $config['assets_version'],
+
+ 'ICON_MOVE_UP' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_up.gif" alt="' . $user->lang['MOVE_UP'] . '" title="' . $user->lang['MOVE_UP'] . '" />',
+ 'ICON_MOVE_UP_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_up_disabled.gif" alt="' . $user->lang['MOVE_UP'] . '" title="' . $user->lang['MOVE_UP'] . '" />',
+ 'ICON_MOVE_DOWN' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_down.gif" alt="' . $user->lang['MOVE_DOWN'] . '" title="' . $user->lang['MOVE_DOWN'] . '" />',
+ 'ICON_MOVE_DOWN_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_down_disabled.gif" alt="' . $user->lang['MOVE_DOWN'] . '" title="' . $user->lang['MOVE_DOWN'] . '" />',
+ 'ICON_EDIT' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_edit.gif" alt="' . $user->lang['EDIT'] . '" title="' . $user->lang['EDIT'] . '" />',
+ 'ICON_EDIT_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_edit_disabled.gif" alt="' . $user->lang['EDIT'] . '" title="' . $user->lang['EDIT'] . '" />',
+ 'ICON_DELETE' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_delete.gif" alt="' . $user->lang['DELETE'] . '" title="' . $user->lang['DELETE'] . '" />',
+ 'ICON_DELETE_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_delete_disabled.gif" alt="' . $user->lang['DELETE'] . '" title="' . $user->lang['DELETE'] . '" />',
+ 'ICON_SYNC' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_sync.gif" alt="' . $user->lang['RESYNC'] . '" title="' . $user->lang['RESYNC'] . '" />',
+ 'ICON_SYNC_DISABLED' => '<img src="' . htmlspecialchars($phpbb_admin_path) . 'images/icon_sync_disabled.gif" alt="' . $user->lang['RESYNC'] . '" title="' . $user->lang['RESYNC'] . '" />',
'S_USER_LANG' => $user->lang['USER_LANG'],
'S_CONTENT_DIRECTION' => $user->lang['DIRECTION'],
@@ -249,17 +251,49 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
{
case 'text':
case 'password':
+ case 'url':
+ case 'email':
+ case 'color':
+ case 'date':
+ case 'time':
+ case 'datetime':
+ case 'datetime-local':
+ case 'month':
+ case 'range':
+ case 'search':
+ case 'tel':
+ case 'url':
+ case 'week':
$size = (int) $tpl_type[1];
$maxlength = (int) $tpl_type[2];
$tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="' . $name . '" value="' . $new[$config_key] . '"' . (($tpl_type[0] === 'password') ? ' autocomplete="off"' : '') . ' />';
break;
+ case 'number':
+ $min = $max = $maxlength = '';
+ $min = ( isset($tpl_type[1]) ) ? (int) $tpl_type[1] : false;
+ if ( isset($tpl_type[2]) )
+ {
+ $max = (int) $tpl_type[2];
+ $maxlength = strlen( (string) $max );
+ }
+
+ $tpl = '<input id="' . $key . '" type="number" maxlength="' . (( $maxlength != '' ) ? $maxlength : 255) . '"' . (( $min != '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="' . $name . '" value="' . $new[$config_key] . '" />';
+ break;
+
case 'dimension':
- $size = (int) $tpl_type[1];
- $maxlength = (int) $tpl_type[2];
+ $min = $max = $maxlength = $size = '';
+
+ $min = (int) $tpl_type[1];
- $tpl = '<input id="' . $key . '" type="text"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="config[' . $config_key . '_width]" value="' . $new[$config_key . '_width'] . '" /> x <input type="text"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="config[' . $config_key . '_height]" value="' . $new[$config_key . '_height'] . '" />';
+ if ( isset($tpl_type[2]) )
+ {
+ $max = (int) $tpl_type[2];
+ $size = $maxlength = strlen( (string) $max );
+ }
+
+ $tpl = '<input id="' . $key . '" type="number"' . (( $size != '' ) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength != '') ? $maxlength : 255) . '"' . (( $min !== '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="config[' . $config_key . '_width]" value="' . $new[$config_key . '_width'] . '" /> x <input type="number"' . (( $size != '' ) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength != '') ? $maxlength : 255) . '"' . (( $min !== '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="config[' . $config_key . '_height]" value="' . $new[$config_key . '_height'] . '" />';
break;
case 'textarea':
@@ -443,6 +477,13 @@ function validate_config_vars($config_vars, &$cfg_array, &$error)
}
break;
+ case 'email':
+ if (!preg_match('/^' . get_preg_expression('email') . '$/i', $cfg_array[$config_name]))
+ {
+ $error[] = $user->lang['EMAIL_INVALID_EMAIL'];
+ }
+ break;
+
// Absolute path
case 'script_path':
if (!$cfg_array[$config_name])
diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php
index 15930f9a2c..fc29492ac1 100644
--- a/phpBB/includes/functions_admin.php
+++ b/phpBB/includes/functions_admin.php
@@ -618,7 +618,7 @@ function move_posts($post_ids, $topic_id, $auto_sync = true)
*/
function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_sync = true, $call_delete_posts = true)
{
- global $db, $config;
+ global $db, $config, $phpbb_container;
$approved_topics = 0;
$forum_ids = $topic_ids = array();
@@ -644,7 +644,7 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s
'posts' => ($call_delete_posts) ? delete_posts($where_type, $where_ids, false, true, $post_count_sync, false) : 0,
);
- $sql = 'SELECT topic_id, forum_id, topic_approved, topic_moved_id
+ $sql = 'SELECT topic_id, forum_id, topic_visibility, topic_moved_id
FROM ' . TOPICS_TABLE . '
WHERE ' . $where_clause;
$result = $db->sql_query($sql);
@@ -654,7 +654,7 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s
$forum_ids[] = $row['forum_id'];
$topic_ids[] = $row['topic_id'];
- if ($row['topic_approved'] && !$row['topic_moved_id'])
+ if ($row['topic_visibility'] == ITEM_APPROVED && !$row['topic_moved_id'])
{
$approved_topics++;
}
@@ -715,6 +715,14 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s
set_config_count('num_topics', $approved_topics * (-1), true);
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->delete_notifications(array(
+ 'topic',
+ 'approve_topic',
+ 'topic_in_queue',
+ ), $topic_ids);
+
return $return;
}
@@ -723,7 +731,7 @@ function delete_topics($where_type, $where_ids, $auto_sync = true, $post_count_s
*/
function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync = true, $post_count_sync = true, $call_delete_topics = true)
{
- global $db, $config, $phpbb_root_path, $phpEx, $auth, $user;
+ global $db, $config, $phpbb_root_path, $phpEx, $auth, $user, $phpbb_container;
if ($where_type === 'range')
{
@@ -767,7 +775,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
$approved_posts = 0;
$post_ids = $topic_ids = $forum_ids = $post_counts = $remove_topics = array();
- $sql = 'SELECT post_id, poster_id, post_approved, post_postcount, topic_id, forum_id
+ $sql = 'SELECT post_id, poster_id, post_visibility, post_postcount, topic_id, forum_id
FROM ' . POSTS_TABLE . '
WHERE ' . $where_clause;
$result = $db->sql_query($sql);
@@ -779,12 +787,12 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
$topic_ids[] = (int) $row['topic_id'];
$forum_ids[] = (int) $row['forum_id'];
- if ($row['post_postcount'] && $post_count_sync && $row['post_approved'])
+ if ($row['post_postcount'] && $post_count_sync && $row['post_visibility'] == ITEM_APPROVED)
{
$post_counts[$row['poster_id']] = (!empty($post_counts[$row['poster_id']])) ? $post_counts[$row['poster_id']] + 1 : 1;
}
- if ($row['post_approved'])
+ if ($row['post_visibility'] == ITEM_APPROVED)
{
$approved_posts++;
}
@@ -881,7 +889,7 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
sync('forum', 'forum_id', $forum_ids, true, true);
}
- if ($approved_posts)
+ if ($approved_posts && $post_count_sync)
{
set_config_count('num_posts', $approved_posts * (-1), true);
}
@@ -892,6 +900,16 @@ function delete_posts($where_type, $where_ids, $auto_sync = true, $posted_sync =
delete_topics('topic_id', $remove_topics, $auto_sync, $post_count_sync, false);
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->delete_notifications(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ 'approve_post',
+ 'post_in_queue',
+ ), $post_ids);
+
return sizeof($post_ids);
}
@@ -1274,7 +1292,7 @@ function phpbb_unlink($filename, $mode = 'file', $entry_removed = false)
* - forum Resync complete forum
* - topic Resync topics
* - topic_moved Removes topic shadows that would be in the same forum as the topic they link to
-* - topic_approved Resyncs the topic_approved flag according to the status of the first post
+* - topic_visibility Resyncs the topic_visibility flag according to the status of the first post
* - post_reported Resyncs the post_reported flag, relying on actual reports
* - topic_reported Resyncs the topic_reported flag, relying on post_reported flags
* - post_attachement Same as post_reported, but with attachment flags
@@ -1294,7 +1312,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$where_ids = ($where_ids) ? array((int) $where_ids) : array();
}
- if ($mode == 'forum' || $mode == 'topic' || $mode == 'topic_approved' || $mode == 'topic_reported' || $mode == 'post_reported')
+ if ($mode == 'forum' || $mode == 'topic' || $mode == 'topic_visibility' || $mode == 'topic_reported' || $mode == 'post_reported')
{
if (!$where_type)
{
@@ -1380,43 +1398,55 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$db->sql_transaction('commit');
break;
- case 'topic_approved':
+ case 'topic_visibility':
$db->sql_transaction('begin');
- switch ($db->sql_layer)
+
+ $sql = 'SELECT t.topic_id, p.post_visibility
+ FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
+ $where_sql_and p.topic_id = t.topic_id
+ AND p.post_visibility = " . ITEM_APPROVED;
+ $result = $db->sql_query($sql);
+
+ $topics_approved = array();
+ while ($row = $db->sql_fetchrow($result))
{
- case 'mysql4':
- case 'mysqli':
- $sql = 'UPDATE ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
- SET t.topic_approved = p.post_approved
- $where_sql_and t.topic_first_post_id = p.post_id";
- $db->sql_query($sql);
- break;
+ $topics_approved[] = (int) $row['topic_id'];
+ }
+ $db->sql_freeresult($result);
- default:
- $sql = 'SELECT t.topic_id, p.post_approved
- FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
- $where_sql_and p.post_id = t.topic_first_post_id
- AND p.post_approved <> t.topic_approved";
- $result = $db->sql_query($sql);
+ $sql = 'SELECT t.topic_id, p.post_visibility
+ FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
+ $where_sql_and " . $db->sql_in_set('t.topic_id', $topics_approved, true, true) . '
+ AND p.topic_id = t.topic_id
+ AND p.post_visibility = ' . ITEM_DELETED;
+ $result = $db->sql_query($sql);
- $topic_ids = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $topic_ids[] = $row['topic_id'];
- }
- $db->sql_freeresult($result);
+ $topics_softdeleted = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $topics_softdeleted[] = (int) $row['topic_id'];
+ }
+ $db->sql_freeresult($result);
- if (!sizeof($topic_ids))
- {
- return;
- }
+ $topics_softdeleted = array_diff($topics_softdeleted, $topics_approved);
+ $topics_not_unapproved = array_merge($topics_softdeleted, $topics_approved);
+
+ $update_ary = array(
+ ITEM_UNAPPROVED => (!empty($topics_not_unapproved)) ? $where_sql_and . ' ' . $db->sql_in_set('topic_id', $topics_not_unapproved, true) : '',
+ ITEM_APPROVED => (!empty($topics_approved)) ? ' WHERE ' . $db->sql_in_set('topic_id', $topics_approved) : '',
+ ITEM_DELETED => (!empty($topics_softdeleted)) ? ' WHERE ' . $db->sql_in_set('topic_id', $topics_softdeleted) : '',
+ );
+ foreach ($topic_visiblities as $visibility => $sql_where)
+ {
+ if ($sql_where)
+ {
$sql = 'UPDATE ' . TOPICS_TABLE . '
- SET topic_approved = 1 - topic_approved
- WHERE ' . $db->sql_in_set('topic_id', $topic_ids);
+ SET topic_visibility = ' . $visibility . '
+ ' . $sql_where;
$db->sql_query($sql);
- break;
+ }
}
$db->sql_transaction('commit');
@@ -1657,9 +1687,12 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$forum_data[$forum_id] = $row;
if ($sync_extra)
{
- $forum_data[$forum_id]['posts'] = 0;
- $forum_data[$forum_id]['topics'] = 0;
- $forum_data[$forum_id]['topics_real'] = 0;
+ $forum_data[$forum_id]['posts_approved'] = 0;
+ $forum_data[$forum_id]['posts_unapproved'] = 0;
+ $forum_data[$forum_id]['posts_softdeleted'] = 0;
+ $forum_data[$forum_id]['topics_approved'] = 0;
+ $forum_data[$forum_id]['topics_unapproved'] = 0;
+ $forum_data[$forum_id]['topics_softdeleted'] = 0;
}
$forum_data[$forum_id]['last_post_id'] = 0;
$forum_data[$forum_id]['last_post_subject'] = '';
@@ -1680,20 +1713,27 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
// 2: Get topic counts for each forum (optional)
if ($sync_extra)
{
- $sql = 'SELECT forum_id, topic_approved, COUNT(topic_id) AS forum_topics
+ $sql = 'SELECT forum_id, topic_visibility, COUNT(topic_id) AS total_topics
FROM ' . TOPICS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $forum_ids) . '
- GROUP BY forum_id, topic_approved';
+ GROUP BY forum_id, topic_visibility';
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
{
$forum_id = (int) $row['forum_id'];
- $forum_data[$forum_id]['topics_real'] += $row['forum_topics'];
- if ($row['topic_approved'])
+ if ($row['topic_visibility'] == ITEM_APPROVED)
{
- $forum_data[$forum_id]['topics'] = $row['forum_topics'];
+ $forum_data[$forum_id]['topics_approved'] = $row['total_topics'];
+ }
+ else if ($row['topic_visibility'] == ITEM_UNAPPROVED)
+ {
+ $forum_data[$forum_id]['topics_unapproved'] = $row['total_topics'];
+ }
+ else if ($row['topic_visibility'] == ITEM_DELETED)
+ {
+ $forum_data[$forum_id]['topics_softdeleted'] = $row['total_topics'];
}
}
$db->sql_freeresult($result);
@@ -1704,18 +1744,16 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
{
if (sizeof($forum_ids) == 1)
{
- $sql = 'SELECT SUM(t.topic_replies + 1) AS forum_posts
+ $sql = 'SELECT SUM(t.topic_posts_approved) AS forum_posts_approved, SUM(t.topic_posts_unapproved) AS forum_posts_unapproved, SUM(t.topic_posts_softdeleted) AS forum_posts_softdeleted
FROM ' . TOPICS_TABLE . ' t
WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
- AND t.topic_approved = 1
AND t.topic_status <> ' . ITEM_MOVED;
}
else
{
- $sql = 'SELECT t.forum_id, SUM(t.topic_replies + 1) AS forum_posts
+ $sql = 'SELECT t.forum_id, SUM(t.topic_posts_approved) AS forum_posts_approved, SUM(t.topic_posts_unapproved) AS forum_posts_unapproved, SUM(t.topic_posts_softdeleted) AS forum_posts_softdeleted
FROM ' . TOPICS_TABLE . ' t
WHERE ' . $db->sql_in_set('t.forum_id', $forum_ids) . '
- AND t.topic_approved = 1
AND t.topic_status <> ' . ITEM_MOVED . '
GROUP BY t.forum_id';
}
@@ -1726,7 +1764,9 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
{
$forum_id = (sizeof($forum_ids) == 1) ? (int) $forum_ids[0] : (int) $row['forum_id'];
- $forum_data[$forum_id]['posts'] = (int) $row['forum_posts'];
+ $forum_data[$forum_id]['posts_approved'] = (int) $row['forum_posts_approved'];
+ $forum_data[$forum_id]['posts_unapproved'] = (int) $row['forum_posts_unapproved'];
+ $forum_data[$forum_id]['posts_softdeleted'] = (int) $row['forum_posts_softdeleted'];
}
$db->sql_freeresult($result);
}
@@ -1737,14 +1777,14 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$sql = 'SELECT MAX(t.topic_last_post_id) as 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_visibility = ' . ITEM_APPROVED;
}
else
{
$sql = 'SELECT t.forum_id, MAX(t.topic_last_post_id) as 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_visibility = ' . ITEM_APPROVED . '
GROUP BY t.forum_id';
}
@@ -1807,7 +1847,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
if ($sync_extra)
{
- array_push($fieldnames, 'posts', 'topics', 'topics_real');
+ array_push($fieldnames, 'posts_approved', 'posts_unapproved', 'posts_softdeleted', 'topics_approved', 'topics_unapproved', 'topics_softdeleted');
}
foreach ($forum_data as $forum_id => $row)
@@ -1842,11 +1882,11 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
break;
case 'topic':
- $topic_data = $post_ids = $approved_unapproved_ids = $resync_forums = $delete_topics = $delete_posts = $moved_topics = array();
+ $topic_data = $post_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
+ $sql = 'SELECT t.topic_id, t.forum_id, t.topic_moved_id, t.topic_visibility, ' . (($sync_extra) ? 't.topic_attachment, t.topic_reported, ' : '') . 't.topic_poster, t.topic_time, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, 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";
$result = $db->sql_query($sql);
@@ -1861,8 +1901,10 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$topic_id = (int) $row['topic_id'];
$topic_data[$topic_id] = $row;
- $topic_data[$topic_id]['replies_real'] = -1;
- $topic_data[$topic_id]['replies'] = 0;
+ $topic_data[$topic_id]['visibility'] = ITEM_UNAPPROVED;
+ $topic_data[$topic_id]['posts_approved'] = 0;
+ $topic_data[$topic_id]['posts_unapproved'] = 0;
+ $topic_data[$topic_id]['posts_softdeleted'] = 0;
$topic_data[$topic_id]['first_post_id'] = 0;
$topic_data[$topic_id]['last_post_id'] = 0;
unset($topic_data[$topic_id]['topic_id']);
@@ -1879,11 +1921,11 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$db->sql_freeresult($result);
// Use "t" as table alias because of the $where_sql clause
- // NOTE: 't.post_approved' in the GROUP BY is causing a major slowdown.
- $sql = 'SELECT t.topic_id, t.post_approved, COUNT(t.post_id) AS total_posts, MIN(t.post_id) AS first_post_id, MAX(t.post_id) AS last_post_id
+ // NOTE: 't.post_visibility' in the GROUP BY is causing a major slowdown.
+ $sql = 'SELECT t.topic_id, t.post_visibility, COUNT(t.post_id) AS total_posts, MIN(t.post_id) AS first_post_id, MAX(t.post_id) AS last_post_id
FROM ' . POSTS_TABLE . " t
$where_sql
- GROUP BY t.topic_id, t.post_approved";
+ GROUP BY t.topic_id, t.post_visibility";
$result = $db->sql_query($sql);
while ($row = $db->sql_fetchrow($result))
@@ -1904,14 +1946,38 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
// When we'll be done, only topics with no posts will remain
unset($delete_topics[$topic_id]);
- $topic_data[$topic_id]['replies_real'] += $row['total_posts'];
- $topic_data[$topic_id]['first_post_id'] = (!$topic_data[$topic_id]['first_post_id']) ? $row['first_post_id'] : min($topic_data[$topic_id]['first_post_id'], $row['first_post_id']);
+ if ($row['post_visibility'] == ITEM_APPROVED)
+ {
+ $topic_data[$topic_id]['posts_approved'] = $row['total_posts'];
+ }
+ else if ($row['post_visibility'] == ITEM_UNAPPROVED)
+ {
+ $topic_data[$topic_id]['posts_unapproved'] = $row['total_posts'];
+ }
+ else if ($row['post_visibility'] == ITEM_DELETED)
+ {
+ $topic_data[$topic_id]['posts_softdeleted'] = $row['total_posts'];
+ }
- if ($row['post_approved'] || !$topic_data[$topic_id]['last_post_id'])
+ if ($row['post_visibility'] == ITEM_APPROVED)
{
- $topic_data[$topic_id]['replies'] = $row['total_posts'] - 1;
+ $topic_data[$topic_id]['visibility'] = ITEM_APPROVED;
+ $topic_data[$topic_id]['first_post_id'] = $row['first_post_id'];
$topic_data[$topic_id]['last_post_id'] = $row['last_post_id'];
}
+ else if ($topic_data[$topic_id]['visibility'] != ITEM_APPROVED)
+ {
+ // If there is no approved post, we take the min/max of the other visibilities
+ // for the last and first post info, because it is only visible to moderators anyway
+ $topic_data[$topic_id]['first_post_id'] = (!empty($topic_data[$topic_id]['first_post_id'])) ? min($topic_data[$topic_id]['first_post_id'], $row['first_post_id']) : $row['first_post_id'];
+ $topic_data[$topic_id]['last_post_id'] = max($topic_data[$topic_id]['last_post_id'], $row['last_post_id']);
+
+ if ($topic_data[$topic_id]['visibility'] == ITEM_UNAPPROVED)
+ {
+ // Soft delete status is stronger than unapproved.
+ $topic_data[$topic_id]['visibility'] = $row['post_visibility'];
+ }
+ }
}
}
$db->sql_freeresult($result);
@@ -1952,7 +2018,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
unset($delete_topics, $delete_topic_ids);
}
- $sql = 'SELECT p.post_id, p.topic_id, p.post_approved, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour
+ $sql = 'SELECT p.post_id, p.topic_id, p.post_visibility, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour
FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
AND u.user_id = p.poster_id';
@@ -1965,10 +2031,6 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
if ($row['post_id'] == $topic_data[$topic_id]['first_post_id'])
{
- if ($topic_data[$topic_id]['topic_approved'] != $row['post_approved'])
- {
- $approved_unapproved_ids[] = $topic_id;
- }
$topic_data[$topic_id]['time'] = $row['post_time'];
$topic_data[$topic_id]['poster'] = $row['poster_id'];
$topic_data[$topic_id]['first_poster_name'] = ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'];
@@ -2029,7 +2091,7 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
$sync_shadow_topics = array();
if (sizeof($post_ids))
{
- $sql = 'SELECT p.post_id, p.topic_id, p.post_approved, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour
+ $sql = 'SELECT p.post_id, p.topic_id, p.post_visibility, p.poster_id, p.post_subject, p.post_username, p.post_time, u.username, u.user_colour
FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
WHERE ' . $db->sql_in_set('p.post_id', $post_ids) . '
AND u.user_id = p.poster_id';
@@ -2096,18 +2158,8 @@ function sync($mode, $where_type = '', $where_ids = '', $resync_parents = false,
unset($sync_shadow_topics, $shadow_topic_data);
}
- // approved becomes unapproved, and vice-versa
- if (sizeof($approved_unapproved_ids))
- {
- $sql = 'UPDATE ' . TOPICS_TABLE . '
- SET topic_approved = 1 - topic_approved
- WHERE ' . $db->sql_in_set('topic_id', $approved_unapproved_ids);
- $db->sql_query($sql);
- }
- unset($approved_unapproved_ids);
-
// These are fields that will be synchronised
- $fieldnames = array('time', 'replies', 'replies_real', 'poster', 'first_post_id', 'first_poster_name', 'first_poster_colour', 'last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour');
+ $fieldnames = array('time', 'visibility', 'posts_approved', 'posts_unapproved', 'posts_softdeleted', 'poster', 'first_post_id', 'first_poster_name', 'first_poster_colour', 'last_post_id', 'last_post_subject', 'last_post_time', 'last_poster_id', 'last_poster_name', 'last_poster_colour');
if ($sync_extra)
{
@@ -2292,13 +2344,17 @@ function auto_prune($forum_id, $prune_mode, $prune_flags, $prune_days, $prune_fr
}
/**
-* Cache moderators, called whenever permissions are changed via admin_permissions. Changes of username
-* and group names must be carried through for the moderators table
+* Cache moderators. Called whenever permissions are changed
+* via admin_permissions. Changes of usernames and group names
+* must be carried through for the moderators table.
+*
+* @param phpbb_db_driver $db Database connection
+* @param phpbb_cache_driver_interface Cache driver
+* @param phpbb_auth $auth Authentication object
+* @return null
*/
-function cache_moderators()
+function phpbb_cache_moderators($db, $cache, $auth)
{
- global $db, $cache, $auth, $phpbb_root_path, $phpEx;
-
// Remove cached sql results
$cache->destroy('sql', MODERATOR_CACHE_TABLE);
@@ -2469,283 +2525,60 @@ function cache_moderators()
}
/**
+* Cache moderators. Called whenever permissions are changed
+* via admin_permissions. Changes of usernames and group names
+* must be carried through for the moderators table.
+*
+* @deprecated 3.1
+* @return null
+*/
+function cache_moderators()
+{
+ global $db, $cache, $auth;
+ return phpbb_cache_moderators($db, $cache, $auth);
+}
+
+/**
* View log
-* If $log_count is set to false, we will skip counting all entries in the database.
+*
+* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
+* @param array &$log The result array with the logs
+* @param mixed &$log_count If $log_count is set to false, we will skip counting all entries in the database.
+* Otherwise an integer with the number of total matching entries is returned.
+* @param int $limit Limit the number of entries that are returned
+* @param int $offset Offset when fetching the log entries, f.e. when paginating
+* @param mixed $forum_id Restrict the log entries to the given forum_id (can also be an array of forum_ids)
+* @param int $topic_id Restrict the log entries to the given topic_id
+* @param int $user_id Restrict the log entries to the given user_id
+* @param int $log_time Only get log entries newer than the given timestamp
+* @param string $sort_by SQL order option, e.g. 'l.log_time DESC'
+* @param string $keywords Will only return log entries that have the keywords in log_operation or log_data
+*
+* @return int Returns the offset of the last valid page, if the specified offset was invalid (too high)
*/
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;
-
- $topic_id_list = $reportee_id_list = $is_auth = $is_mod = array();
-
- $profile_url = (defined('IN_ADMIN')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&amp;mode=overview') : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile');
-
- switch ($mode)
- {
- case 'admin':
- $log_type = LOG_ADMIN;
- $sql_forum = '';
- break;
-
- case 'mod':
- $log_type = LOG_MOD;
- $sql_forum = '';
-
- if ($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 if ($forum_id)
- {
- $sql_forum = 'AND l.forum_id = ' . (int) $forum_id;
- }
- break;
+ global $phpbb_log;
- case 'user':
- $log_type = LOG_USERS;
- $sql_forum = 'AND l.reportee_id = ' . (int) $user_id;
- break;
-
- case 'users':
- $log_type = LOG_USERS;
- $sql_forum = '';
- break;
-
- case 'critical':
- $log_type = LOG_CRITICAL;
- $sql_forum = '';
- break;
-
- default:
- return;
- }
-
- // Use no preg_quote for $keywords because this would lead to sole backslashes being added
- // We also use an OR connection here for spaces and the | string. Currently, regex is not supported for searching (but may come later).
- $keywords = preg_split('#[\s|]+#u', utf8_strtolower($keywords), 0, PREG_SPLIT_NO_EMPTY);
- $sql_keywords = '';
-
- if (!empty($keywords))
- {
- $keywords_pattern = array();
-
- // Build pattern and keywords...
- for ($i = 0, $num_keywords = sizeof($keywords); $i < $num_keywords; $i++)
- {
- $keywords_pattern[] = preg_quote($keywords[$i], '#');
- $keywords[$i] = $db->sql_like_expression($db->any_char . $keywords[$i] . $db->any_char);
- }
-
- $keywords_pattern = '#' . implode('|', $keywords_pattern) . '#ui';
-
- $operations = array();
- foreach ($user->lang as $key => $value)
- {
- if (substr($key, 0, 4) == 'LOG_' && preg_match($keywords_pattern, $value))
- {
- $operations[] = $key;
- }
- }
+ $count_logs = ($log_count !== false);
- $sql_keywords = 'AND (';
- if (!empty($operations))
- {
- $sql_keywords .= $db->sql_in_set('l.log_operation', $operations) . ' OR ';
- }
- $sql_lower = $db->sql_lower_text('l.log_data');
- $sql_keywords .= "$sql_lower " . implode(" OR $sql_lower ", $keywords) . ')';
- }
+ $log = $phpbb_log->get_logs($mode, $count_logs, $limit, $offset, $forum_id, $topic_id, $user_id, $limit_days, $sort_by, $keywords);
+ $log_count = $phpbb_log->get_log_count();
- if ($log_count !== false)
- {
- $sql = 'SELECT COUNT(l.log_id) AS total_entries
- 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');
- $db->sql_freeresult($result);
- }
-
- // $log_count may be false here if false was passed in for it,
- // because in this case we did not run the COUNT() query above.
- // If we ran the COUNT() query and it returned zero rows, return;
- // otherwise query for logs below.
- if ($log_count === 0)
- {
- // Save the queries, because there are no logs to display
- return 0;
- }
-
- if ($offset >= $log_count)
- {
- $offset = ($offset - $limit < 0) ? 0 : $offset - $limit;
- }
-
- $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);
-
- $i = 0;
- $log = array();
- while ($row = $db->sql_fetchrow($result))
- {
- if ($row['topic_id'])
- {
- $topic_id_list[] = $row['topic_id'];
- }
-
- if ($row['reportee_id'])
- {
- $reportee_id_list[] = $row['reportee_id'];
- }
-
- $log[$i] = array(
- 'id' => $row['log_id'],
-
- 'reportee_id' => $row['reportee_id'],
- 'reportee_username' => '',
- 'reportee_username_full'=> '',
-
- 'user_id' => $row['user_id'],
- 'username' => $row['username'],
- 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url),
-
- 'ip' => $row['log_ip'],
- 'time' => $row['log_time'],
- 'forum_id' => $row['forum_id'],
- 'topic_id' => $row['topic_id'],
-
- 'viewforum' => ($row['forum_id'] && $auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : false,
- '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($log[$i]['action'], '%') - sizeof($log_data_ary)) > 0)
- {
- $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($log[$i]['action'], '%') - sizeof($log_data_ary), ''));
- }
-
- $log[$i]['action'] = vsprintf($log[$i]['action'], $log_data_ary);
-
- // If within the admin panel we do not censor text out
- if (defined('IN_ADMIN'))
- {
- $log[$i]['action'] = bbcode_nl2br($log[$i]['action']);
- }
- else
- {
- $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action']));
- }
- }
- else if (!empty($log_data_ary))
- {
- $log[$i]['action'] .= '<br />' . implode('', $log_data_ary);
- }
-
- /* Apply make_clickable... has to be seen if it is for good. :/
- // Seems to be not for the moment, reconsider later...
- $log[$i]['action'] = make_clickable($log[$i]['action']);
- */
- }
-
- $i++;
- }
- $db->sql_freeresult($result);
-
- if (sizeof($topic_id_list))
- {
- $topic_id_list = array_unique($topic_id_list);
-
- // This query is not really needed if move_topics() updates the forum_id field,
- // although it's also used to determine if the topic still exists in the database
- $sql = 'SELECT topic_id, forum_id
- FROM ' . TOPICS_TABLE . '
- WHERE ' . $db->sql_in_set('topic_id', array_map('intval', $topic_id_list));
- $result = $db->sql_query($sql);
-
- $default_forum_id = 0;
-
- while ($row = $db->sql_fetchrow($result))
- {
- if ($auth->acl_get('f_read', $row['forum_id']))
- {
- $is_auth[$row['topic_id']] = $row['forum_id'];
- }
-
- if ($auth->acl_gets('a_', 'm_', $row['forum_id']))
- {
- $is_mod[$row['topic_id']] = $row['forum_id'];
- }
- }
- $db->sql_freeresult($result);
-
- foreach ($log as $key => $row)
- {
- $log[$key]['viewtopic'] = (isset($is_auth[$row['topic_id']])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $is_auth[$row['topic_id']] . '&amp;t=' . $row['topic_id']) : false;
- $log[$key]['viewlogs'] = (isset($is_mod[$row['topic_id']])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=logs&amp;mode=topic_logs&amp;t=' . $row['topic_id'], true, $user->session_id) : false;
- }
- }
-
- if (sizeof($reportee_id_list))
- {
- $reportee_id_list = array_unique($reportee_id_list);
- $reportee_names_list = array();
-
- $sql = 'SELECT user_id, username, user_colour
- FROM ' . USERS_TABLE . '
- WHERE ' . $db->sql_in_set('user_id', $reportee_id_list);
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $reportee_names_list[$row['user_id']] = $row;
- }
- $db->sql_freeresult($result);
-
- foreach ($log as $key => $row)
- {
- if (!isset($reportee_names_list[$row['reportee_id']]))
- {
- continue;
- }
-
- $log[$key]['reportee_username'] = $reportee_names_list[$row['reportee_id']]['username'];
- $log[$key]['reportee_username_full'] = get_username_string('full', $row['reportee_id'], $reportee_names_list[$row['reportee_id']]['username'], $reportee_names_list[$row['reportee_id']]['user_colour'], false, $profile_url);
- }
- }
-
- return $offset;
+ return $phpbb_log->get_valid_offset();
}
/**
-* Update foes - remove moderators and administrators from foe lists...
+* Removes moderators and administrators from foe lists.
+*
+* @param phpbb_db_driver $db Database connection
+* @param phpbb_auth $auth Authentication object
+* @param array|bool $group_id If an array, remove all members of this group from foe lists, or false to ignore
+* @param array|bool $user_id If an array, remove this user from foe lists, or false to ignore
+* @return null
*/
-function update_foes($group_id = false, $user_id = false)
+function phpbb_update_foes($db, $auth, $group_id = false, $user_id = false)
{
- global $db, $auth;
-
// update foes for some user
if (is_array($user_id) && sizeof($user_id))
{
@@ -2855,6 +2688,20 @@ function update_foes($group_id = false, $user_id = false)
}
/**
+* Removes moderators and administrators from foe lists.
+*
+* @deprecated 3.1
+* @param array|bool $group_id If an array, remove all members of this group from foe lists, or false to ignore
+* @param array|bool $user_id If an array, remove this user from foe lists, or false to ignore
+* @return null
+*/
+function update_foes($group_id = false, $user_id = false)
+{
+ global $db, $auth;
+ return phpbb_update_foes($db, $auth, $group_id, $user_id);
+}
+
+/**
* Lists inactive users
*/
function view_inactive_users(&$users, &$user_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'user_inactive_time DESC')
@@ -3086,7 +2933,7 @@ function get_remote_file($host, $directory, $filename, &$errstr, &$errno, $port
if ($fsock = @fsockopen($host, $port, $errno, $errstr, $timeout))
{
- @fputs($fsock, "GET $directory/$filename HTTP/1.1\r\n");
+ @fputs($fsock, "GET $directory/$filename HTTP/1.0\r\n");
@fputs($fsock, "HOST: $host\r\n");
@fputs($fsock, "Connection: close\r\n\r\n");
@@ -3227,38 +3074,29 @@ function tidy_database()
*/
function add_permission_language()
{
- global $user, $phpEx;
+ global $user, $phpEx, $phpbb_extension_manager;
- // First of all, our own file. We need to include it as the first file because it presets all relevant variables.
- $user->add_lang('acp/permissions_phpbb');
+ // add permission language files from extensions
+ $finder = $phpbb_extension_manager->get_finder();
- $files_to_add = array();
+ $lang_files = $finder
+ ->prefix('permissions_')
+ ->suffix(".$phpEx")
+ ->core_path('language/' . $user->lang_name . '/')
+ ->extension_directory('/language/' . $user->lang_name)
+ ->find();
- // Now search in acp and mods folder for permissions_ files.
- foreach (array('acp/', 'mods/') as $path)
+ foreach ($lang_files as $lang_file => $ext_name)
{
- $dh = @opendir($user->lang_path . $user->lang_name . '/' . $path);
-
- if ($dh)
+ if ($ext_name === '/')
{
- while (($file = readdir($dh)) !== false)
- {
- if ($file !== 'permissions_phpbb.' . $phpEx && strpos($file, 'permissions_') === 0 && substr($file, -(strlen($phpEx) + 1)) === '.' . $phpEx)
- {
- $files_to_add[] = $path . substr($file, 0, -(strlen($phpEx) + 1));
- }
- }
- closedir($dh);
+ $user->add_lang($lang_file);
+ }
+ else
+ {
+ $user->add_lang_ext($ext_name, $lang_file);
}
}
-
- if (!sizeof($files_to_add))
- {
- return false;
- }
-
- $user->add_lang($files_to_add);
- return true;
}
/**
@@ -3284,7 +3122,7 @@ function obtain_latest_version_info($force_update = false, $warn_fail = false, $
$info = get_remote_file('version.phpbb.com', '/phpbb',
((defined('PHPBB_QA')) ? '30x_qa.txt' : '30x.txt'), $errstr, $errno);
- if ($info === false)
+ if (empty($info))
{
$cache->destroy('versioncheck');
if ($warn_fail)
diff --git a/phpBB/includes/functions_compatibility.php b/phpBB/includes/functions_compatibility.php
new file mode 100644
index 0000000000..2197815087
--- /dev/null
+++ b/phpBB/includes/functions_compatibility.php
@@ -0,0 +1,50 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Get user avatar
+*
+* @deprecated 3.1.0-a1 (To be removed: 3.3.0)
+*
+* @param string $avatar Users assigned avatar name
+* @param int $avatar_type Type of avatar
+* @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', $ignore_config = false)
+{
+ // map arguments to new function phpbb_get_avatar()
+ $row = array(
+ 'avatar' => $avatar,
+ 'avatar_type' => $avatar_type,
+ 'avatar_width' => $avatar_width,
+ 'avatar_height' => $avatar_height,
+ );
+
+ if (!function_exists('phpbb_get_avatar'))
+ {
+ global $phpbb_root_path, $phpEx;
+
+ include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ }
+
+ return phpbb_get_avatar($row, $alt, $ignore_config);
+}
diff --git a/phpBB/includes/functions_container.php b/phpBB/includes/functions_container.php
index 8014574443..7cbfa17a0e 100644
--- a/phpBB/includes/functions_container.php
+++ b/phpBB/includes/functions_container.php
@@ -21,6 +21,71 @@ if (!defined('IN_PHPBB'))
}
/**
+* Get DB connection from config.php.
+*
+* Used to bootstrap the container.
+*
+* @param string $config_file
+* @return phpbb_db_driver
+*/
+function phpbb_bootstrap_db_connection($config_file)
+{
+ require($config_file);
+ $dbal_driver_class = phpbb_convert_30_dbms_to_31($dbms);
+
+ $db = new $dbal_driver_class();
+ $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, defined('PHPBB_DB_NEW_LINK'));
+
+ return $db;
+}
+
+/**
+* Get table prefix from config.php.
+*
+* Used to bootstrap the container.
+*
+* @param string $config_file
+* @return string table prefix
+*/
+function phpbb_bootstrap_table_prefix($config_file)
+{
+ require($config_file);
+ return $table_prefix;
+}
+
+/**
+* Get enabled extensions.
+*
+* Used to bootstrap the container.
+*
+* @param string $config_file
+* @param string $phpbb_root_path
+* @return array enabled extensions
+*/
+function phpbb_bootstrap_enabled_exts($config_file, $phpbb_root_path)
+{
+ $db = phpbb_bootstrap_db_connection($config_file);
+ $table_prefix = phpbb_bootstrap_table_prefix($config_file);
+ $extension_table = $table_prefix.'ext';
+
+ $sql = 'SELECT *
+ FROM ' . $extension_table . '
+ WHERE ext_active = 1';
+
+ $result = $db->sql_query($sql);
+ $rows = $db->sql_fetchrowset($result);
+ $db->sql_freeresult($result);
+
+ $exts = array();
+ foreach ($rows as $row)
+ {
+ $exts[$row['ext_name']] = $phpbb_root_path . 'ext/' . $row['ext_name'] . '/';
+ }
+
+ return $exts;
+}
+
+/**
* Create the ContainerBuilder object
*
* @param array $extensions Array of Container extension objects
@@ -53,10 +118,14 @@ function phpbb_create_container(array $extensions, $phpbb_root_path, $php_ext)
*/
function phpbb_create_install_container($phpbb_root_path, $php_ext)
{
- $core = new phpbb_di_extension_core($phpbb_root_path);
+ $other_config_path = $phpbb_root_path . 'install/update/new/config/';
+ $config_path = file_exists($other_config_path . 'services.yml') ? $other_config_path : $phpbb_root_path . 'config/';
+
+ $core = new phpbb_di_extension_core($config_path);
$container = phpbb_create_container(array($core), $phpbb_root_path, $php_ext);
$container->setParameter('core.root_path', $phpbb_root_path);
+ $container->setParameter('core.adm_relative_path', $phpbb_adm_relative_path);
$container->setParameter('core.php_ext', $php_ext);
$container->setParameter('core.table_prefix', '');
@@ -70,6 +139,32 @@ function phpbb_create_install_container($phpbb_root_path, $php_ext)
}
/**
+* Create updater container
+*
+* @param string $phpbb_root_path Root path
+* @param string $php_ext PHP Extension
+* @param array $config_path Path to config directory
+* @return ContainerBuilder object (compiled)
+*/
+function phpbb_create_update_container($phpbb_root_path, $php_ext, $config_path)
+{
+ $config_file = $phpbb_root_path . 'config.' . $php_ext;
+ return phpbb_create_compiled_container(
+ $config_file,
+ array(
+ new phpbb_di_extension_config($config_file),
+ new phpbb_di_extension_core($config_path),
+ ),
+ array(
+ new phpbb_di_pass_collection_pass(),
+ new phpbb_di_pass_kernel_pass(),
+ ),
+ $phpbb_root_path,
+ $php_ext
+ );
+}
+
+/**
* Create a compiled ContainerBuilder object
*
* @param array $extensions Array of Container extension objects
@@ -78,20 +173,8 @@ function phpbb_create_install_container($phpbb_root_path, $php_ext)
* @param string $php_ext PHP Extension
* @return ContainerBuilder object (compiled)
*/
-function phpbb_create_compiled_container(array $extensions, array $passes, $phpbb_root_path, $php_ext)
+function phpbb_create_compiled_container($config_file, array $extensions, array $passes, $phpbb_root_path, $php_ext)
{
- // Create a temporary container for access to the ext.manager service
- $tmp_container = phpbb_create_container($extensions, $phpbb_root_path, $php_ext);
- $tmp_container->compile();
-
- // XXX stop writing to global $cache when
- // http://tracker.phpbb.com/browse/PHPBB3-11203 is fixed
- $GLOBALS['cache'] = $tmp_container->get('cache');
- $installed_exts = $tmp_container->get('ext.manager')->all_enabled();
-
- // Now pass the enabled extension paths into the ext compiler extension
- $extensions[] = new phpbb_di_extension_ext($installed_exts);
-
// Create the final container to be compiled and cached
$container = phpbb_create_container($extensions, $phpbb_root_path, $php_ext);
@@ -105,7 +188,16 @@ function phpbb_create_compiled_container(array $extensions, array $passes, $phpb
return $container;
}
-function phpbb_create_dumped_container(array $extensions, array $passes, $phpbb_root_path, $php_ext)
+/**
+* Create a compiled and dumped ContainerBuilder object
+*
+* @param array $extensions Array of Container extension objects
+* @param array $passes Array of Compiler Pass objects
+* @param string $phpbb_root_path Root path
+* @param string $php_ext PHP Extension
+* @return ContainerBuilder object (compiled)
+*/
+function phpbb_create_dumped_container($config_file, array $extensions, array $passes, $phpbb_root_path, $php_ext)
{
// Check for our cached container; if it exists, use it
$container_filename = phpbb_container_filename($phpbb_root_path, $php_ext);
@@ -115,7 +207,7 @@ function phpbb_create_dumped_container(array $extensions, array $passes, $phpbb_
return new phpbb_cache_container();
}
- $container = phpbb_create_compiled_container($extensions, $passes, $phpbb_root_path, $php_ext);
+ $container = phpbb_create_compiled_container($config_file, $extensions, $passes, $phpbb_root_path, $php_ext);
// Lastly, we create our cached container class
$dumper = new PhpDumper($container);
@@ -129,12 +221,65 @@ function phpbb_create_dumped_container(array $extensions, array $passes, $phpbb_
return $container;
}
-function phpbb_create_dumped_container_unless_debug(array $extensions, array $passes, $phpbb_root_path, $php_ext)
+/**
+* Create an environment-specific ContainerBuilder object
+*
+* If debug is enabled, the container is re-compiled every time.
+* This ensures that the latest changes will always be reflected
+* during development.
+*
+* Otherwise it will get the existing dumped container and use
+* that one instead.
+*
+* @param array $extensions Array of Container extension objects
+* @param array $passes Array of Compiler Pass objects
+* @param string $phpbb_root_path Root path
+* @param string $php_ext PHP Extension
+* @return ContainerBuilder object (compiled)
+*/
+function phpbb_create_dumped_container_unless_debug($config_file, array $extensions, array $passes, $phpbb_root_path, $php_ext)
{
$container_factory = defined('DEBUG') ? 'phpbb_create_compiled_container' : 'phpbb_create_dumped_container';
- return $container_factory($extensions, $passes, $phpbb_root_path, $php_ext);
+ return $container_factory($config_file, $extensions, $passes, $phpbb_root_path, $php_ext);
}
+/**
+* Create a default ContainerBuilder object
+*
+* Contains the default configuration of the phpBB container.
+*
+* @param array $extensions Array of Container extension objects
+* @param array $passes Array of Compiler Pass objects
+* @return ContainerBuilder object (compiled)
+*/
+function phpbb_create_default_container($phpbb_root_path, $php_ext)
+{
+ $config_file = $phpbb_root_path . 'config.' . $php_ext;
+ $installed_exts = phpbb_bootstrap_enabled_exts($config_file, $phpbb_root_path);
+
+ return phpbb_create_dumped_container_unless_debug(
+ $config_file,
+ array(
+ new phpbb_di_extension_config($config_file),
+ new phpbb_di_extension_core($phpbb_root_path . 'config'),
+ new phpbb_di_extension_ext($installed_exts),
+ ),
+ array(
+ new phpbb_di_pass_collection_pass(),
+ new phpbb_di_pass_kernel_pass(),
+ ),
+ $phpbb_root_path,
+ $php_ext
+ );
+}
+
+/**
+* Get the filename under which the dumped container will be stored.
+*
+* @param string $phpbb_root_path Root path
+* @param string $php_ext PHP Extension
+* @return Path for dumped container
+*/
function phpbb_container_filename($phpbb_root_path, $php_ext)
{
$filename = str_replace(array('/', '.'), array('slash', 'dot'), $phpbb_root_path);
diff --git a/phpBB/includes/functions_content.php b/phpBB/includes/functions_content.php
index c54cc25f34..05d3c5fde2 100644
--- a/phpBB/includes/functions_content.php
+++ b/phpBB/includes/functions_content.php
@@ -413,7 +413,7 @@ function generate_text_for_display($text, $uid, $bitfield, $flags, $censor_text
static $bbcode;
global $phpbb_dispatcher;
- if (!$text)
+ if ($text === '')
{
return '';
}
@@ -505,7 +505,7 @@ function generate_text_for_storage(&$text, &$uid, &$bitfield, &$flags, $allow_bb
$uid = $bitfield = '';
$flags = (($allow_bbcode) ? OPTION_FLAG_BBCODE : 0) + (($allow_smilies) ? OPTION_FLAG_SMILIES : 0) + (($allow_urls) ? OPTION_FLAG_LINKS : 0);
- if (!$text)
+ if ($text === '')
{
return;
}
diff --git a/phpBB/includes/functions_convert.php b/phpBB/includes/functions_convert.php
index ac791e0d9b..a34a193f60 100644
--- a/phpBB/includes/functions_convert.php
+++ b/phpBB/includes/functions_convert.php
@@ -1768,7 +1768,7 @@ function sync_post_count($offset, $limit)
$sql = 'SELECT COUNT(post_id) AS num_posts, poster_id
FROM ' . POSTS_TABLE . '
WHERE post_postcount = 1
- AND post_approved = 1
+ AND post_visibility = ' . ITEM_APPROVED . '
GROUP BY poster_id
ORDER BY poster_id';
$result = $db->sql_query_limit($sql, $limit, $offset);
@@ -1941,7 +1941,7 @@ function update_dynamic_config()
$sql = 'SELECT COUNT(post_id) AS stat
FROM ' . POSTS_TABLE . '
- WHERE post_approved = 1';
+ WHERE post_visibility = ' . ITEM_APPROVED;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
@@ -1950,7 +1950,7 @@ function update_dynamic_config()
$sql = 'SELECT COUNT(topic_id) AS stat
FROM ' . TOPICS_TABLE . '
- WHERE topic_approved = 1';
+ WHERE topic_visibility = ' . ITEM_APPROVED;
$result = $db->sql_query($sql);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
diff --git a/phpBB/includes/functions_database_helper.php b/phpBB/includes/functions_database_helper.php
new file mode 100644
index 0000000000..1b508e6a02
--- /dev/null
+++ b/phpBB/includes/functions_database_helper.php
@@ -0,0 +1,206 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Updates rows in given table from a set of values to a new value.
+* If this results in rows violating uniqueness constraints, the duplicate
+* rows are eliminated.
+*
+* The only supported table is bookmarks.
+*
+* @param phpbb_db_driver $db Database object
+* @param string $table Table on which to perform the update
+* @param string $column Column whose values to change
+* @param array $from_values An array of values that should be changed
+* @param int $to_value The new value
+* @return null
+*/
+function phpbb_update_rows_avoiding_duplicates(phpbb_db_driver $db, $table, $column, $from_values, $to_value)
+{
+ $sql = "SELECT $column, user_id
+ FROM $table
+ WHERE " . $db->sql_in_set($column, $from_values);
+ $result = $db->sql_query($sql);
+
+ $old_user_ids = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $old_user_ids[$row[$column]][] = (int) $row['user_id'];
+ }
+ $db->sql_freeresult($result);
+
+ $sql = "SELECT $column, user_id
+ FROM $table
+ WHERE $column = " . (int) $to_value;
+ $result = $db->sql_query($sql);
+
+ $new_user_ids = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $new_user_ids[$row[$column]][] = (int) $row['user_id'];
+ }
+ $db->sql_freeresult($result);
+
+ $queries = array();
+ foreach ($from_values as $from_value)
+ {
+ if (!isset($old_user_ids[$from_value]))
+ {
+ continue;
+ }
+ if (empty($new_user_ids))
+ {
+ $sql = "UPDATE $table
+ SET $column = " . (int) $to_value . "
+ WHERE $column = '" . $db->sql_escape($from_value) . "'";
+ $queries[] = $sql;
+ }
+ else
+ {
+ $different_user_ids = array_diff($old_user_ids[$from_value], $new_user_ids[$to_value]);
+ if (!empty($different_user_ids))
+ {
+ $sql = "UPDATE $table
+ SET $column = " . (int) $to_value . "
+ WHERE $column = '" . $db->sql_escape($from_value) . "'
+ AND " . $db->sql_in_set('user_id', $different_user_ids);
+ $queries[] = $sql;
+ }
+ }
+ }
+
+ if (!empty($queries))
+ {
+ $db->sql_transaction('begin');
+
+ foreach ($queries as $sql)
+ {
+ $db->sql_query($sql);
+ }
+
+ $sql = "DELETE FROM $table
+ WHERE " . $db->sql_in_set($column, $from_values);
+ $db->sql_query($sql);
+
+ $db->sql_transaction('commit');
+ }
+}
+
+/**
+* Updates rows in given table from a set of values to a new value.
+* If this results in rows violating uniqueness constraints, the duplicate
+* rows are merged respecting notify_status (0 takes precedence over 1).
+*
+* The only supported table is topics_watch.
+*
+* @param phpbb_db_driver $db Database object
+* @param string $table Table on which to perform the update
+* @param string $column Column whose values to change
+* @param array $from_values An array of values that should be changed
+* @param int $to_value The new value
+* @return null
+*/
+function phpbb_update_rows_avoiding_duplicates_notify_status(phpbb_db_driver $db, $table, $column, $from_values, $to_value)
+{
+ $sql = "SELECT $column, user_id, notify_status
+ FROM $table
+ WHERE " . $db->sql_in_set($column, $from_values);
+ $result = $db->sql_query($sql);
+
+ $old_user_ids = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $old_user_ids[(int) $row['notify_status']][$row[$column]][] = (int) $row['user_id'];
+ }
+ $db->sql_freeresult($result);
+
+ $sql = "SELECT $column, user_id
+ FROM $table
+ WHERE $column = " . (int) $to_value;
+ $result = $db->sql_query($sql);
+
+ $new_user_ids = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $new_user_ids[$row[$column]][] = (int) $row['user_id'];
+ }
+ $db->sql_freeresult($result);
+
+ $queries = array();
+ $extra_updates = array(
+ 0 => 'notify_status = 0',
+ 1 => '',
+ );
+ foreach ($from_values as $from_value)
+ {
+ foreach ($extra_updates as $notify_status => $extra_update)
+ {
+ if (!isset($old_user_ids[$notify_status][$from_value]))
+ {
+ continue;
+ }
+ if (empty($new_user_ids))
+ {
+ $sql = "UPDATE $table
+ SET $column = " . (int) $to_value . "
+ WHERE $column = '" . $db->sql_escape($from_value) . "'";
+ $queries[] = $sql;
+ }
+ else
+ {
+ $different_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $new_user_ids[$to_value]);
+ if (!empty($different_user_ids))
+ {
+ $sql = "UPDATE $table
+ SET $column = " . (int) $to_value . "
+ WHERE $column = '" . $db->sql_escape($from_value) . "'
+ AND " . $db->sql_in_set('user_id', $different_user_ids);
+ $queries[] = $sql;
+ }
+
+ if ($extra_update)
+ {
+ $same_user_ids = array_diff($old_user_ids[$notify_status][$from_value], $different_user_ids);
+ if (!empty($same_user_ids))
+ {
+ $sql = "UPDATE $table
+ SET $extra_update
+ WHERE $column = '" . (int) $to_value . "'
+ AND " . $db->sql_in_set('user_id', $same_user_ids);
+ $queries[] = $sql;
+ }
+ }
+ }
+ }
+ }
+
+ if (!empty($queries))
+ {
+ $db->sql_transaction('begin');
+
+ foreach ($queries as $sql)
+ {
+ $db->sql_query($sql);
+ }
+
+ $sql = "DELETE FROM $table
+ WHERE " . $db->sql_in_set($column, $from_values);
+ $db->sql_query($sql);
+
+ $db->sql_transaction('commit');
+ }
+}
diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php
index 73129803ee..b1dac64bec 100644
--- a/phpBB/includes/functions_display.php
+++ b/phpBB/includes/functions_display.php
@@ -22,7 +22,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
{
global $db, $auth, $user, $template;
global $phpbb_root_path, $phpEx, $config;
- global $request, $phpbb_dispatcher;
+ global $request, $phpbb_dispatcher, $phpbb_container;
$forum_rows = $subforums = $forum_ids = $forum_ids_moderator = $forum_moderators = $active_forum_ary = array();
$parent_id = $visible_forums = 0;
@@ -61,6 +61,20 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
{
markread('all', false, false, request_var('mark_time', 0));
+ if ($request->is_ajax())
+ {
+ // Tell the ajax script what language vars and URL need to be replaced
+ $data = array(
+ 'NO_UNREAD_POSTS' => $user->lang['NO_UNREAD_POSTS'],
+ 'UNREAD_POSTS' => $user->lang['UNREAD_POSTS'],
+ 'U_MARK_FORUMS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}index.$phpEx", 'hash=' . generate_link_hash('global') . '&mark=forums&mark_time=' . time()) : '',
+ 'MESSAGE_TITLE' => $user->lang['INFORMATION'],
+ 'MESSAGE_TEXT' => $user->lang['FORUMS_MARKED']
+ );
+ $json_response = new phpbb_json_response();
+ $json_response->send($data);
+ }
+
trigger_error(
$user->lang['FORUMS_MARKED'] . '<br /><br />' .
sprintf($user->lang['RETURN_INDEX'], '<a href="' . $redirect . '">', '</a>')
@@ -135,6 +149,8 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
$forum_tracking_info = array();
$branch_root_id = $root_data['forum_id'];
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+
while ($row = $db->sql_fetchrow($result))
{
/**
@@ -199,9 +215,11 @@ 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'];
+ // Lets check whether there are unapproved topics/posts, so we can display an information to moderators
+ $row['forum_id_unapproved_topics'] = ($auth->acl_get('m_approve', $forum_id) && $row['forum_topics_unapproved']) ? $forum_id : 0;
+ $row['forum_id_unapproved_posts'] = ($auth->acl_get('m_approve', $forum_id) && $row['forum_posts_unapproved']) ? $forum_id : 0;
+ $row['forum_posts'] = $phpbb_content_visibility->get_count('forum_posts', $row, $forum_id);
+ $row['forum_topics'] = $phpbb_content_visibility->get_count('forum_topics', $row, $forum_id);
// Display active topics from this forum?
if ($show_active && $row['forum_type'] == FORUM_POST && $auth->acl_get('f_read', $forum_id) && ($row['forum_flags'] & FORUM_FLAG_ACTIVE_TOPICS))
@@ -264,6 +282,11 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
$forum_rows[$parent_id]['forum_id_unapproved_topics'] = $forum_id;
}
+ if (!$forum_rows[$parent_id]['forum_id_unapproved_posts'] && $row['forum_id_unapproved_posts'])
+ {
+ $forum_rows[$parent_id]['forum_id_unapproved_posts'] = $forum_id;
+ }
+
$forum_rows[$parent_id]['forum_topics'] += $row['forum_topics'];
// Do not list redirects in LINK Forums as Posts.
@@ -313,6 +336,20 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
$message = sprintf($user->lang['RETURN_FORUM'], '<a href="' . $redirect . '">', '</a>');
meta_refresh(3, $redirect);
+ if ($request->is_ajax())
+ {
+ // Tell the ajax script what language vars and URL need to be replaced
+ $data = array(
+ 'NO_UNREAD_POSTS' => $user->lang['NO_UNREAD_POSTS'],
+ 'UNREAD_POSTS' => $user->lang['UNREAD_POSTS'],
+ '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&mark_time=' . time()) : '',
+ 'MESSAGE_TITLE' => $user->lang['INFORMATION'],
+ 'MESSAGE_TEXT' => $user->lang['FORUMS_MARKED']
+ );
+ $json_response = new phpbb_json_response();
+ $json_response->send($data);
+ }
+
trigger_error($user->lang['FORUMS_MARKED'] . '<br /><br />' . $message);
}
else
@@ -517,6 +554,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
'L_MODERATOR_STR' => $l_moderator,
'U_UNAPPROVED_TOPICS' => ($row['forum_id_unapproved_topics']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&amp;mode=unapproved_topics&amp;f=' . $row['forum_id_unapproved_topics']) : '',
+ 'U_UNAPPROVED_POSTS' => ($row['forum_id_unapproved_posts']) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&amp;mode=unapproved_posts&amp;f=' . $row['forum_id_unapproved_posts']) : '',
'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,
@@ -556,6 +594,7 @@ function display_forums($root_data = '', $display_moderators = true, $return_mod
'L_SUBFORUM' => ($visible_forums == 1) ? $user->lang['SUBFORUM'] : $user->lang['SUBFORUMS'],
'LAST_POST_IMG' => $user->img('icon_topic_latest', 'VIEW_LATEST_POST'),
'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'TOPICS_UNAPPROVED'),
+ 'UNAPPROVED_POST_IMG' => $user->img('icon_topic_unapproved', 'POSTS_UNAPPROVED'),
));
if ($return_moderators)
@@ -787,7 +826,7 @@ function gen_forum_auth_level($mode, $forum_id, $forum_status)
($auth->acl_get('f_post', $forum_id) && !$locked) ? $user->lang['RULES_POST_CAN'] : $user->lang['RULES_POST_CANNOT'],
($auth->acl_get('f_reply', $forum_id) && !$locked) ? $user->lang['RULES_REPLY_CAN'] : $user->lang['RULES_REPLY_CANNOT'],
($user->data['is_registered'] && $auth->acl_gets('f_edit', 'm_edit', $forum_id) && !$locked) ? $user->lang['RULES_EDIT_CAN'] : $user->lang['RULES_EDIT_CANNOT'],
- ($user->data['is_registered'] && $auth->acl_gets('f_delete', 'm_delete', $forum_id) && !$locked) ? $user->lang['RULES_DELETE_CAN'] : $user->lang['RULES_DELETE_CANNOT'],
+ ($user->data['is_registered'] && ($auth->acl_gets('f_delete', 'm_delete', $forum_id) || $auth->acl_gets('f_softdelete', 'm_softdelete', $forum_id)) && !$locked) ? $user->lang['RULES_DELETE_CAN'] : $user->lang['RULES_DELETE_CANNOT'],
);
if ($config['allow_attachments'])
@@ -977,7 +1016,7 @@ function display_reasons($reason_id = 0)
function display_user_activity(&$userdata)
{
global $auth, $template, $db, $user;
- global $phpbb_root_path, $phpEx;
+ global $phpbb_root_path, $phpEx, $phpbb_container;
// Do not display user activity for users having more than 5000 posts...
if ($userdata['user_posts'] > 5000)
@@ -987,73 +1026,65 @@ function display_user_activity(&$userdata)
$forum_ary = array();
- // Do not include those forums the user is not having read access to...
- $forum_read_ary = $auth->acl_getf('!f_read');
-
- foreach ($forum_read_ary as $forum_id => $not_allowed)
+ $forum_read_ary = $auth->acl_getf('f_read');
+ foreach ($forum_read_ary as $forum_id => $allowed)
{
- if ($not_allowed['f_read'])
+ if ($allowed['f_read'])
{
$forum_ary[] = (int) $forum_id;
}
}
- $forum_ary = array_unique($forum_ary);
- $forum_sql = (sizeof($forum_ary)) ? 'AND ' . $db->sql_in_set('forum_id', $forum_ary, true) : '';
-
- $fid_m_approve = $auth->acl_getf('m_approve', true);
- $sql_m_approve = (!empty($fid_m_approve)) ? 'OR ' . $db->sql_in_set('forum_id', array_keys($fid_m_approve)) : '';
-
- // Obtain active forum
- $sql = 'SELECT forum_id, COUNT(post_id) AS num_posts
- FROM ' . POSTS_TABLE . '
- WHERE poster_id = ' . $userdata['user_id'] . "
- AND post_postcount = 1
- AND (post_approved = 1
- $sql_m_approve)
- $forum_sql
- GROUP BY forum_id
- ORDER BY num_posts DESC";
- $result = $db->sql_query_limit($sql, 1);
- $active_f_row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
+ $forum_ary = array_diff($forum_ary, $user->get_passworded_forums());
- if (!empty($active_f_row))
+ $active_f_row = $active_t_row = array();
+ if (!empty($forum_ary))
{
- $sql = 'SELECT forum_name
- FROM ' . FORUMS_TABLE . '
- WHERE forum_id = ' . $active_f_row['forum_id'];
- $result = $db->sql_query($sql, 3600);
- $active_f_row['forum_name'] = (string) $db->sql_fetchfield('forum_name');
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+
+ // Obtain active forum
+ $sql = 'SELECT forum_id, COUNT(post_id) AS num_posts
+ FROM ' . POSTS_TABLE . '
+ WHERE poster_id = ' . $userdata['user_id'] . '
+ AND post_postcount = 1
+ AND ' . $phpbb_content_visibility->get_forums_visibility_sql('post', $forum_ary) . '
+ GROUP BY forum_id
+ ORDER BY num_posts DESC';
+ $result = $db->sql_query_limit($sql, 1);
+ $active_f_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- }
- // Obtain active topic
- // We need to exclude passworded forums here so we do not leak the topic title
- $forum_ary_topic = array_unique(array_merge($forum_ary, $user->get_passworded_forums()));
- $forum_sql_topic = (!empty($forum_ary_topic)) ? 'AND ' . $db->sql_in_set('forum_id', $forum_ary_topic, true) : '';
-
- $sql = 'SELECT topic_id, COUNT(post_id) AS num_posts
- FROM ' . POSTS_TABLE . '
- WHERE poster_id = ' . $userdata['user_id'] . "
- AND post_postcount = 1
- AND (post_approved = 1
- $sql_m_approve)
- $forum_sql_topic
- GROUP BY topic_id
- ORDER BY num_posts DESC";
- $result = $db->sql_query_limit($sql, 1);
- $active_t_row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
+ if (!empty($active_f_row))
+ {
+ $sql = 'SELECT forum_name
+ FROM ' . FORUMS_TABLE . '
+ WHERE forum_id = ' . $active_f_row['forum_id'];
+ $result = $db->sql_query($sql, 3600);
+ $active_f_row['forum_name'] = (string) $db->sql_fetchfield('forum_name');
+ $db->sql_freeresult($result);
+ }
- if (!empty($active_t_row))
- {
- $sql = 'SELECT topic_title
- FROM ' . TOPICS_TABLE . '
- WHERE topic_id = ' . $active_t_row['topic_id'];
- $result = $db->sql_query($sql);
- $active_t_row['topic_title'] = (string) $db->sql_fetchfield('topic_title');
+ // Obtain active topic
+ $sql = 'SELECT topic_id, COUNT(post_id) AS num_posts
+ FROM ' . POSTS_TABLE . '
+ WHERE poster_id = ' . $userdata['user_id'] . '
+ AND post_postcount = 1
+ AND ' . $phpbb_content_visibility->get_forums_visibility_sql('post', $forum_ary) . '
+ GROUP BY topic_id
+ ORDER BY num_posts DESC';
+ $result = $db->sql_query_limit($sql, 1);
+ $active_t_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
+
+ if (!empty($active_t_row))
+ {
+ $sql = 'SELECT topic_title
+ FROM ' . TOPICS_TABLE . '
+ WHERE topic_id = ' . $active_t_row['topic_id'];
+ $result = $db->sql_query($sql);
+ $active_t_row['topic_title'] = (string) $db->sql_fetchfield('topic_title');
+ $db->sql_freeresult($result);
+ }
}
$userdata['active_t_row'] = $active_t_row;
@@ -1313,79 +1344,87 @@ function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank
/**
* Get user avatar
*
-* @param string $avatar Users assigned avatar name
-* @param int $avatar_type Type of avatar
-* @param string $avatar_width Width of users avatar
-* @param string $avatar_height Height of users avatar
+* @param array $user_row Row from the users table
* @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
+* @return string Avatar html
*/
-function get_user_avatar($avatar, $avatar_type, $avatar_width, $avatar_height, $alt = 'USER_AVATAR', $ignore_config = false)
+function phpbb_get_user_avatar($user_row, $alt = 'USER_AVATAR', $ignore_config = false)
{
- global $user, $config, $phpbb_root_path, $phpEx;
- global $phpbb_dispatcher;
-
- $overwrite_avatar = '';
+ $row = phpbb_avatar_manager::clean_row($user_row);
+ return phpbb_get_avatar($row, $alt, $ignore_config);
+}
- /**
- * Overwrite users avatar
- *
- * @event core.display_custom_bbcodes_modify_row
- * @var string avatar Users assigned avatar name
- * @var int avatar_type Type of avatar
- * @var string avatar_width Width of users avatar
- * @var string avatar_height Height of users avatar
- * @var string alt Language string for alt tag within image
- * Can be a language key or text
- * @var bool ignore_config Ignores config and force displaying avatar
- * @var string overwrite_avatar If set, this string will be the avatar
- * @since 3.1-A1
- */
- $vars = array('avatar', 'avatar_type', 'avatar_width', 'avatar_height', 'alt', 'ignore_config', 'overwrite_avatar');
- extract($phpbb_dispatcher->trigger_event('core.user_get_avatar', compact($vars)));
+/**
+* Get group avatar
+*
+* @param array $group_row Row from the groups table
+* @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 html
+*/
+function phpbb_get_group_avatar($user_row, $alt = 'GROUP_AVATAR', $ignore_config = false)
+{
+ $row = phpbb_avatar_manager::clean_row($user_row);
+ return phpbb_get_avatar($row, $alt, $ignore_config);
+}
- if ($overwrite_avatar)
- {
- return $overwrite_avatar;
- }
+/**
+* Get avatar
+*
+* @param array $row Row cleaned by phpbb_avatar_driver::clean_row
+* @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 html
+*/
+function phpbb_get_avatar($row, $alt, $ignore_config = false)
+{
+ global $user, $config, $cache, $phpbb_root_path, $phpEx;
+ global $request;
+ global $phpbb_container;
- if (empty($avatar) || !$avatar_type || (!$config['allow_avatar'] && !$ignore_config))
+ if (!$config['allow_avatar'] && !$ignore_config)
{
return '';
}
- $avatar_img = '';
+ $avatar_data = array(
+ 'src' => $row['avatar'],
+ 'width' => $row['avatar_width'],
+ 'height' => $row['avatar_height'],
+ );
+
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $driver = $phpbb_avatar_manager->get_driver($row['avatar_type'], $ignore_config);
+ $html = '';
- switch ($avatar_type)
+ if ($driver)
{
- case AVATAR_UPLOAD:
- if (!$config['allow_avatar_upload'] && !$ignore_config)
- {
- return '';
- }
- $avatar_img = $phpbb_root_path . "download/file.$phpEx?avatar=";
- break;
+ $html = $driver->get_custom_html($user, $row, $alt);
+ if (!empty($html))
+ {
+ return $html;
+ }
- case AVATAR_GALLERY:
- if (!$config['allow_avatar_local'] && !$ignore_config)
- {
- return '';
- }
- $avatar_img = $phpbb_root_path . $config['avatar_gallery_path'] . '/';
- break;
+ $avatar_data = $driver->get_data($row, $ignore_config);
+ }
+ else
+ {
+ $avatar_data['src'] = '';
+ }
- case AVATAR_REMOTE:
- if (!$config['allow_avatar_remote'] && !$ignore_config)
- {
- return '';
- }
- break;
+ if (!empty($avatar_data['src']))
+ {
+ $html = '<img src="' . $avatar_data['src'] . '" ' .
+ ($avatar_data['width'] ? ('width="' . $avatar_data['width'] . '" ') : '') .
+ ($avatar_data['height'] ? ('height="' . $avatar_data['height'] . '" ') : '') .
+ 'alt="' . ((!empty($user->lang[$alt])) ? $user->lang[$alt] : $alt) . '" />';
}
- $avatar_img .= $avatar;
- return '<img src="' . (str_replace(' ', '%20', $avatar_img)) . '" width="' . $avatar_width . '" height="' . $avatar_height . '" alt="' . ((!empty($user->lang[$alt])) ? $user->lang[$alt] : $alt) . '" />';
+ return $html;
}
/**
diff --git a/phpBB/includes/functions_download.php b/phpBB/includes/functions_download.php
index fc6f1cc762..0a8000ea3d 100644
--- a/phpBB/includes/functions_download.php
+++ b/phpBB/includes/functions_download.php
@@ -46,7 +46,7 @@ function send_avatar_to_browser($file, $browser)
$image_data = @getimagesize($file_path);
header('Content-Type: ' . image_type_to_mime_type($image_data[2]));
- if (strpos(strtolower($browser), 'msie') !== false && strpos(strtolower($browser), 'msie 8.0') === false)
+ if ((strpos(strtolower($user->browser), 'msie') !== false) && !phpbb_is_greater_ie_version($browser, 7))
{
header('Content-Disposition: attachment; ' . header_filename($file));
@@ -174,10 +174,9 @@ function send_file_to_browser($attachment, $upload_dir, $category)
header('Pragma: public');
// Send out the Headers. Do not set Content-Disposition to inline please, it is a security measure for users using the Internet Explorer.
- $is_ie8 = (strpos(strtolower($user->browser), 'msie 8.0') !== false);
header('Content-Type: ' . $attachment['mimetype']);
- if ($is_ie8)
+ if (phpbb_is_greater_ie_version($user->browser, 7))
{
header('X-Content-Type-Options: nosniff');
}
@@ -189,7 +188,7 @@ function send_file_to_browser($attachment, $upload_dir, $category)
}
else
{
- if (empty($user->browser) || (!$is_ie8 && (strpos(strtolower($user->browser), 'msie') !== false)))
+ if (empty($user->browser) || ((strpos(strtolower($user->browser), 'msie') !== false) && !phpbb_is_greater_ie_version($user->browser, 7)))
{
header('Content-Disposition: attachment; ' . header_filename(htmlspecialchars_decode($attachment['real_filename'])));
if (empty($user->browser) || (strpos(strtolower($user->browser), 'msie 6.0') !== false))
@@ -200,7 +199,7 @@ function send_file_to_browser($attachment, $upload_dir, $category)
else
{
header('Content-Disposition: ' . ((strpos($attachment['mimetype'], 'image') === 0) ? 'inline' : 'attachment') . '; ' . header_filename(htmlspecialchars_decode($attachment['real_filename'])));
- if ($is_ie8 && (strpos($attachment['mimetype'], 'image') !== 0))
+ if (phpbb_is_greater_ie_version($user->browser, 7) && (strpos($attachment['mimetype'], 'image') !== 0))
{
header('X-Download-Options: noopen');
}
@@ -410,7 +409,8 @@ function set_modified_headers($stamp, $browser)
// let's see if we have to send the file at all
$last_load = $request->header('Modified-Since') ? strtotime(trim($request->header('Modified-Since'))) : false;
- if ((strpos(strtolower($browser), 'msie 6.0') === false) && (strpos(strtolower($browser), 'msie 8.0') === false))
+
+ if (strpos(strtolower($browser), 'msie 6.0') === false && !phpbb_is_greater_ie_version($browser, 7))
{
if ($last_load !== false && $last_load >= $stamp)
{
@@ -596,7 +596,7 @@ function phpbb_parse_range_request($request_array, $filesize)
/**
* Increments the download count of all provided attachments
*
-* @param dbal $db The database object
+* @param phpbb_db_driver $db The database object
* @param array|int $ids The attach_id of each attachment
*
* @return null
@@ -617,7 +617,7 @@ function phpbb_increment_downloads($db, $ids)
/**
* Handles authentication when downloading attachments from a post or topic
*
-* @param dbal $db The database object
+* @param phpbb_db_driver $db The database object
* @param phpbb_auth $auth The authentication object
* @param int $topic_id The id of the topic that we are downloading from
*
@@ -625,7 +625,7 @@ function phpbb_increment_downloads($db, $ids)
*/
function phpbb_download_handle_forum_auth($db, $auth, $topic_id)
{
- $sql = 'SELECT t.forum_id, f.forum_password, f.parent_id
+ $sql = 'SELECT t.forum_id, f.forum_name, f.forum_password, f.parent_id
FROM ' . TOPICS_TABLE . ' t, ' . FORUMS_TABLE . " f
WHERE t.topic_id = " . (int) $topic_id . "
AND t.forum_id = f.forum_id";
@@ -651,7 +651,7 @@ function phpbb_download_handle_forum_auth($db, $auth, $topic_id)
/**
* Handles authentication when downloading attachments from PMs
*
-* @param dbal $db The database object
+* @param phpbb_db_driver $db The database object
* @param phpbb_auth $auth The authentication object
* @param int $user_id The user id
* @param int $msg_id The id of the PM that we are downloading from
@@ -678,7 +678,7 @@ function phpbb_download_handle_pm_auth($db, $auth, $user_id, $msg_id)
/**
* Checks whether a user can download from a particular PM
*
-* @param dbal $db The database object
+* @param phpbb_db_driver $db The database object
* @param int $user_id The user id
* @param int $msg_id The id of the PM that we are downloading from
*
@@ -721,3 +721,24 @@ function phpbb_download_clean_filename($filename)
return $filename;
}
+
+/**
+* Check if the browser is internet explorer version 7+
+*
+* @param string $user_agent User agent HTTP header
+* @param int $version IE version to check against
+*
+* @return bool true if internet explorer version is greater than $version
+*/
+function phpbb_is_greater_ie_version($user_agent, $version)
+{
+ if (preg_match('/msie (\d+)/', strtolower($user_agent), $matches))
+ {
+ $ie_version = (int) $matches[1];
+ return ($ie_version > $version);
+ }
+ else
+ {
+ return false;
+ }
+}
diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php
index ab6b3ea009..bd0ffaaf00 100644
--- a/phpBB/includes/functions_install.php
+++ b/phpBB/includes/functions_install.php
@@ -28,16 +28,18 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20
'SCHEMA' => 'firebird',
'MODULE' => 'interbase',
'DELIM' => ';;',
- 'DRIVER' => 'firebird',
+ 'DRIVER' => 'phpbb_db_driver_firebird',
'AVAILABLE' => true,
'2.0.x' => false,
),
+ // Note: php 5.5 alpha 2 deprecated mysql.
+ // Keep mysqli before mysql in this list.
'mysqli' => array(
'LABEL' => 'MySQL with MySQLi Extension',
'SCHEMA' => 'mysql_41',
'MODULE' => 'mysqli',
'DELIM' => ';',
- 'DRIVER' => 'mysqli',
+ 'DRIVER' => 'phpbb_db_driver_mysqli',
'AVAILABLE' => true,
'2.0.x' => true,
),
@@ -46,7 +48,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20
'SCHEMA' => 'mysql',
'MODULE' => 'mysql',
'DELIM' => ';',
- 'DRIVER' => 'mysql',
+ 'DRIVER' => 'phpbb_db_driver_mysql',
'AVAILABLE' => true,
'2.0.x' => true,
),
@@ -55,7 +57,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20
'SCHEMA' => 'mssql',
'MODULE' => 'mssql',
'DELIM' => 'GO',
- 'DRIVER' => 'mssql',
+ 'DRIVER' => 'phpbb_db_driver_mssql',
'AVAILABLE' => true,
'2.0.x' => true,
),
@@ -64,7 +66,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20
'SCHEMA' => 'mssql',
'MODULE' => 'odbc',
'DELIM' => 'GO',
- 'DRIVER' => 'mssql_odbc',
+ 'DRIVER' => 'phpbb_db_driver_mssql_odbc',
'AVAILABLE' => true,
'2.0.x' => true,
),
@@ -73,7 +75,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20
'SCHEMA' => 'mssql',
'MODULE' => 'sqlsrv',
'DELIM' => 'GO',
- 'DRIVER' => 'mssqlnative',
+ 'DRIVER' => 'phpbb_db_driver_mssqlnative',
'AVAILABLE' => true,
'2.0.x' => false,
),
@@ -82,7 +84,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20
'SCHEMA' => 'oracle',
'MODULE' => 'oci8',
'DELIM' => '/',
- 'DRIVER' => 'oracle',
+ 'DRIVER' => 'phpbb_db_driver_oracle',
'AVAILABLE' => true,
'2.0.x' => false,
),
@@ -91,7 +93,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20
'SCHEMA' => 'postgres',
'MODULE' => 'pgsql',
'DELIM' => ';',
- 'DRIVER' => 'postgres',
+ 'DRIVER' => 'phpbb_db_driver_postgres',
'AVAILABLE' => true,
'2.0.x' => true,
),
@@ -100,7 +102,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20
'SCHEMA' => 'sqlite',
'MODULE' => 'sqlite',
'DELIM' => ';',
- 'DRIVER' => 'sqlite',
+ 'DRIVER' => 'phpbb_db_driver_sqlite',
'AVAILABLE' => true,
'2.0.x' => false,
),
@@ -182,12 +184,6 @@ function dbms_select($default = '', $only_20x_options = false)
*/
function get_tables(&$db)
{
- if (!class_exists('phpbb_db_tools'))
- {
- global $phpbb_root_path, $phpEx;
- require($phpbb_root_path . 'includes/db/db_tools.' . $phpEx);
- }
-
$db_tools = new phpbb_db_tools($db);
return $db_tools->sql_list_tables();
@@ -205,26 +201,19 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix,
$dbms = $dbms_details['DRIVER'];
- if ($load_dbal)
- {
- // Include the DB layer
- include($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx);
- }
-
// Instantiate it and set return on error true
- $sql_db = 'dbal_' . $dbms;
- $db = new $sql_db();
+ $db = new $dbms();
$db->sql_return_on_error(true);
// Check that we actually have a database name before going any further.....
- if ($dbms_details['DRIVER'] != 'sqlite' && $dbms_details['DRIVER'] != 'oracle' && $dbname === '')
+ if ($dbms_details['DRIVER'] != 'phpbb_db_driver_sqlite' && $dbms_details['DRIVER'] != 'phpbb_db_driver_oracle' && $dbname === '')
{
$error[] = $lang['INST_ERR_DB_NO_NAME'];
return false;
}
// Make sure we don't have a daft user who thinks having the SQLite database in the forum directory is a good idea
- if ($dbms_details['DRIVER'] == 'sqlite' && stripos(phpbb_realpath($dbhost), phpbb_realpath('../')) === 0)
+ if ($dbms_details['DRIVER'] == 'phpbb_db_driver_sqlite' && stripos(phpbb_realpath($dbhost), phpbb_realpath('../')) === 0)
{
$error[] = $lang['INST_ERR_DB_FORUM_PATH'];
return false;
@@ -233,8 +222,8 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix,
// Check the prefix length to ensure that index names are not too long and does not contain invalid characters
switch ($dbms_details['DRIVER'])
{
- case 'mysql':
- case 'mysqli':
+ case 'phpbb_db_driver_mysql':
+ case 'phpbb_db_driver_mysqli':
if (strspn($table_prefix, '-./\\') !== 0)
{
$error[] = $lang['INST_ERR_PREFIX_INVALID'];
@@ -243,22 +232,22 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix,
// no break;
- case 'postgres':
+ case 'phpbb_db_driver_postgres':
$prefix_length = 36;
break;
- case 'mssql':
- case 'mssql_odbc':
- case 'mssqlnative':
+ case 'phpbb_db_driver_mssql':
+ case 'phpbb_db_driver_mssql_odbc':
+ case 'phpbb_db_driver_mssqlnative':
$prefix_length = 90;
break;
- case 'sqlite':
+ case 'phpbb_db_driver_sqlite':
$prefix_length = 200;
break;
- case 'firebird':
- case 'oracle':
+ case 'phpbb_db_driver_firebird':
+ case 'phpbb_db_driver_oracle':
$prefix_length = 6;
break;
}
@@ -296,21 +285,21 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix,
// Make sure that the user has selected a sensible DBAL for the DBMS actually installed
switch ($dbms_details['DRIVER'])
{
- case 'mysqli':
+ case 'phpbb_db_driver_mysqli':
if (version_compare(mysqli_get_server_info($db->db_connect_id), '4.1.3', '<'))
{
$error[] = $lang['INST_ERR_DB_NO_MYSQLI'];
}
break;
- case 'sqlite':
+ case 'phpbb_db_driver_sqlite':
if (version_compare(sqlite_libversion(), '2.8.2', '<'))
{
$error[] = $lang['INST_ERR_DB_NO_SQLITE'];
}
break;
- case 'firebird':
+ case 'phpbb_db_driver_firebird':
// check the version of FB, use some hackery if we can't get access to the server info
if ($db->service_handle !== false && function_exists('ibase_server_info'))
{
@@ -391,7 +380,7 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix,
}
break;
- case 'oracle':
+ case 'phpbb_db_driver_oracle':
if ($unicode_check)
{
$sql = "SELECT *
@@ -413,7 +402,7 @@ function connect_check_db($error_connect, &$error, $dbms_details, $table_prefix,
}
break;
- case 'postgres':
+ case 'phpbb_db_driver_postgres':
if ($unicode_check)
{
$sql = "SHOW server_encoding;";
@@ -515,6 +504,9 @@ function phpbb_create_config_file_data($data, $dbms, $debug = false, $debug_test
'dbuser' => $data['dbuser'],
'dbpasswd' => htmlspecialchars_decode($data['dbpasswd']),
'table_prefix' => $data['table_prefix'],
+
+ 'adm_relative_path' => 'adm/',
+
'acm_type' => 'phpbb_cache_driver_file',
);
diff --git a/phpBB/includes/functions_jabber.php b/phpBB/includes/functions_jabber.php
index 3d8e403f4b..b260ffad6e 100644
--- a/phpBB/includes/functions_jabber.php
+++ b/phpBB/includes/functions_jabber.php
@@ -249,7 +249,7 @@ class jabber
return true;
}
- // Apparently an error occured...
+ // Apparently an error occurred...
$this->add_to_log('Error: open_socket() - ' . $errorstr);
return false;
}
diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php
index a18aeddabd..3bfc1a44f0 100644
--- a/phpBB/includes/functions_messenger.php
+++ b/phpBB/includes/functions_messenger.php
@@ -21,14 +21,15 @@ if (!defined('IN_PHPBB'))
*/
class messenger
{
- var $vars, $msg, $extra_headers, $replyto, $from, $subject;
+ var $msg, $extra_headers, $replyto, $from, $subject;
var $addresses = array();
var $mail_priority = MAIL_NORMAL_PRIORITY;
var $use_queue = true;
- var $tpl_obj = NULL;
- var $tpl_msg = array();
+ /** @var phpbb_template */
+ protected $template;
+
var $eol = "\n";
/**
@@ -52,11 +53,29 @@ class messenger
function reset()
{
$this->addresses = $this->extra_headers = array();
- $this->vars = $this->msg = $this->replyto = $this->from = '';
+ $this->msg = $this->replyto = $this->from = '';
$this->mail_priority = MAIL_NORMAL_PRIORITY;
}
/**
+ * Set addresses for to/im as available
+ *
+ * @param array $user User row
+ */
+ function set_addresses($user)
+ {
+ if (isset($user['user_email']) && $user['user_email'])
+ {
+ $this->to($user['user_email'], (isset($user['username']) ? $user['username'] : ''));
+ }
+
+ if (isset($user['user_jabber']) && $user['user_jabber'])
+ {
+ $this->im($user['user_jabber'], (isset($user['username']) ? $user['username'] : ''));
+ }
+ }
+
+ /**
* Sets an email address to send to
*/
function to($address, $realname = '')
@@ -192,6 +211,8 @@ class messenger
{
global $config, $phpbb_root_path, $phpEx, $user, $phpbb_extension_manager;
+ $this->setup_template();
+
if (!trim($template_file))
{
trigger_error('No template file for emailing set.', E_USER_ERROR);
@@ -201,46 +222,41 @@ class messenger
{
// fall back to board default language if the user's language is
// missing $template_file. If this does not exist either,
- // $tpl->set_filenames will do a trigger_error
+ // $this->template->set_filenames will do a trigger_error
$template_lang = basename($config['default_lang']);
}
- // tpl_msg now holds a template object we can use to parse the template file
- if (!isset($this->tpl_msg[$template_lang . $template_file]))
+ if ($template_path)
{
- $style_resource_locator = new phpbb_style_resource_locator();
- $style_path_provider = new phpbb_style_extension_path_provider($phpbb_extension_manager, new phpbb_style_path_provider());
- $tpl = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, new phpbb_template_context());
- $style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, $style_path_provider, $tpl);
-
- $this->tpl_msg[$template_lang . $template_file] = $tpl;
+ $template_paths = array(
+ $template_path,
+ );
+ }
+ else
+ {
+ $template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/';
+ $template_path .= $template_lang . '/email';
- $fallback_template_path = false;
+ $template_paths = array(
+ $template_path,
+ );
- if (!$template_path)
+ // we can only specify default language fallback when the path is not a custom one for which we
+ // do not know the default language alternative
+ if ($template_lang !== basename($config['default_lang']))
{
- $template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/';
- $template_path .= $template_lang . '/email';
+ $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/';
+ $fallback_template_path .= basename($config['default_lang']) . '/email';
- // we can only specify default language fallback when the path is not a custom one for which we
- // do not know the default language alternative
- if ($template_lang !== basename($config['default_lang']))
- {
- $fallback_template_path = (!empty($user->lang_path)) ? $user->lang_path : $phpbb_root_path . 'language/';
- $fallback_template_path .= basename($config['default_lang']) . '/email';
- }
+ $template_paths[] = $fallback_template_path;
}
-
- $style->set_custom_style($template_lang . '_email', array($template_path, $fallback_template_path), '');
-
- $tpl->set_filenames(array(
- 'body' => $template_file . '.txt',
- ));
}
- $this->tpl_obj = &$this->tpl_msg[$template_lang . $template_file];
- $this->vars = &$this->tpl_obj->_rootref;
- $this->tpl_msg = '';
+ $this->set_template_paths($template_lang . '_email', $template_paths);
+
+ $this->template->set_filenames(array(
+ 'body' => $template_file . '.txt',
+ ));
return true;
}
@@ -250,22 +266,16 @@ class messenger
*/
function assign_vars($vars)
{
- if (!is_object($this->tpl_obj))
- {
- return;
- }
+ $this->setup_template();
- $this->tpl_obj->assign_vars($vars);
+ $this->template->assign_vars($vars);
}
function assign_block_vars($blockname, $vars)
{
- if (!is_object($this->tpl_obj))
- {
- return;
- }
+ $this->setup_template();
- $this->tpl_obj->assign_block_vars($blockname, $vars);
+ $this->template->assign_block_vars($blockname, $vars);
}
/**
@@ -276,29 +286,14 @@ class messenger
global $config, $user;
// We add some standard variables we always use, no need to specify them always
- if (!isset($this->vars['U_BOARD']))
- {
- $this->assign_vars(array(
- 'U_BOARD' => generate_board_url(),
- ));
- }
-
- if (!isset($this->vars['EMAIL_SIG']))
- {
- $this->assign_vars(array(
- 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])),
- ));
- }
-
- if (!isset($this->vars['SITENAME']))
- {
- $this->assign_vars(array(
- 'SITENAME' => htmlspecialchars_decode($config['sitename']),
- ));
- }
+ $this->assign_vars(array(
+ 'U_BOARD' => generate_board_url(),
+ 'EMAIL_SIG' => str_replace('<br />', "\n", "-- \n" . htmlspecialchars_decode($config['board_email_sig'])),
+ 'SITENAME' => htmlspecialchars_decode($config['sitename']),
+ ));
// Parse message through template
- $this->msg = trim($this->tpl_obj->assign_display('body'));
+ $this->msg = trim($this->template->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);
@@ -393,6 +388,28 @@ class messenger
}
/**
+ * Generates a valid message id to be used in emails
+ *
+ * @return string message id
+ */
+ function generate_message_id()
+ {
+ global $config;
+
+ $domain = 'phpbb.generated';
+ if ($config['server_name'])
+ {
+ $domain = $config['server_name'];
+ }
+ else if (!empty($_SERVER['SERVER_NAME']))
+ {
+ $domain = $_SERVER['SERVER_NAME'];
+ }
+
+ return md5(unique_id(time())) . '@' . $domain;
+ }
+
+ /**
* Return email header
*/
function build_header($to, $cc, $bcc)
@@ -418,7 +435,7 @@ class messenger
$headers[] = 'Return-Path: <' . $config['board_email'] . '>';
$headers[] = 'Sender: <' . $config['board_email'] . '>';
$headers[] = 'MIME-Version: 1.0';
- $headers[] = 'Message-ID: <' . md5(unique_id(time())) . '@' . $config['server_name'] . '>';
+ $headers[] = 'Message-ID: <' . $this->generate_message_id() . '>';
$headers[] = 'Date: ' . date('r', time());
$headers[] = 'Content-Type: text/plain; charset=UTF-8'; // format=flowed
$headers[] = 'Content-Transfer-Encoding: 8bit'; // 7bit
@@ -603,6 +620,31 @@ class messenger
unset($addresses);
return true;
}
+
+ /**
+ * Setup template engine
+ */
+ protected function setup_template()
+ {
+ global $config, $phpbb_root_path, $phpEx, $user, $phpbb_extension_manager;
+
+ if ($this->template instanceof phpbb_template)
+ {
+ return;
+ }
+
+ $this->template = new phpbb_template_twig($phpbb_root_path, $phpEx, $config, $user, new phpbb_template_context(), $phpbb_extension_manager);
+ }
+
+ /**
+ * Set template paths to load
+ */
+ protected function set_template_paths($path_name, $paths)
+ {
+ $this->setup_template();
+
+ $this->template->set_custom_style($path_name, $paths);
+ }
}
/**
diff --git a/phpBB/includes/functions_module.php b/phpBB/includes/functions_module.php
index 0d387ace6d..80477684a8 100644
--- a/phpBB/includes/functions_module.php
+++ b/phpBB/includes/functions_module.php
@@ -455,7 +455,7 @@ class p_master
*/
function load_active($mode = false, $module_url = false, $execute_module = true)
{
- global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user;
+ global $phpbb_root_path, $phpbb_admin_path, $phpEx, $user, $template;
$module_path = $this->include_path . $this->p_class;
$icat = request_var('icat', '');
@@ -494,6 +494,24 @@ class p_master
// We pre-define the action parameter we are using all over the place
if (defined('IN_ADMIN'))
{
+ /*
+ * If this is an extension module, we'll try to automatically set
+ * the style paths for the extension (the ext author can change them
+ * if necessary).
+ */
+ $module_dir = explode('_', get_class($this->module));
+
+ // 0 phpbb, 1 ext, 2 vendor, 3 extension name, ...
+ if (isset($module_dir[3]) && $module_dir[1] === 'ext')
+ {
+ $module_style_dir = $phpbb_root_path . 'ext/' . $module_dir[2] . '/' . $module_dir[3] . '/adm/style';
+
+ if (is_dir($module_style_dir))
+ {
+ $template->set_custom_style('adm', array($module_style_dir, $phpbb_admin_path . 'style'));
+ }
+ }
+
// Is first module automatically enabled a duplicate and the category not passed yet?
if (!$icat && $this->module_ary[$this->active_module_row_id]['is_duplicate'])
{
@@ -505,6 +523,24 @@ class p_master
}
else
{
+ /*
+ * If this is an extension module, we'll try to automatically set
+ * the style paths for the extension (the ext author can change them
+ * if necessary).
+ */
+ $module_dir = explode('_', get_class($this->module));
+
+ // 0 phpbb, 1 ext, 2 vendor, 3 extension name, ...
+ if (isset($module_dir[3]) && $module_dir[1] === 'ext')
+ {
+ $module_style_dir = 'ext/' . $module_dir[2] . '/' . $module_dir[3] . '/styles';
+
+ if (is_dir($phpbb_root_path . $module_style_dir))
+ {
+ $template->set_style(array($module_style_dir, 'styles'));
+ }
+ }
+
// If user specified the module url we will use it...
if ($module_url !== false)
{
diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php
index 171cf988ce..ce1238d8e0 100644
--- a/phpBB/includes/functions_posting.php
+++ b/phpBB/includes/functions_posting.php
@@ -61,7 +61,7 @@ function generate_smilies($mode, $forum_id)
'body' => 'posting_smilies.html')
);
- generate_pagination(append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&amp;f=' . $forum_id), $smiley_count, $config['smilies_per_page'], $start);
+ generate_pagination(append_sid("{$phpbb_root_path}posting.$phpEx", 'mode=smilies&amp;f=' . $forum_id), $smiley_count, $config['smilies_per_page'], $start);
}
$display_link = false;
@@ -176,7 +176,7 @@ function update_post_information($type, $ids, $return_update_sql = false)
if ($type != 'topic')
{
$topic_join = ', ' . TOPICS_TABLE . ' t';
- $topic_condition = 'AND t.topic_id = p.topic_id AND t.topic_approved = 1';
+ $topic_condition = 'AND t.topic_id = p.topic_id AND t.topic_visibility = ' . ITEM_APPROVED;
}
else
{
@@ -190,7 +190,7 @@ function update_post_information($type, $ids, $return_update_sql = false)
FROM ' . POSTS_TABLE . " p $topic_join
WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . "
$topic_condition
- AND p.post_approved = 1";
+ AND p.post_visibility = " . ITEM_APPROVED;
}
else
{
@@ -198,7 +198,7 @@ function update_post_information($type, $ids, $return_update_sql = false)
FROM ' . POSTS_TABLE . " p $topic_join
WHERE " . $db->sql_in_set('p.' . $type . '_id', $ids) . "
$topic_condition
- AND p.post_approved = 1
+ AND p.post_visibility = " . ITEM_APPROVED . "
GROUP BY p.{$type}_id";
}
$result = $db->sql_query($sql);
@@ -403,14 +403,7 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage
$upload->set_disallowed_content(explode('|', $config['mime_triggers']));
}
- if (!$local)
- {
- $filedata['post_attach'] = ($upload->is_valid($form_name)) ? true : false;
- }
- else
- {
- $filedata['post_attach'] = true;
- }
+ $filedata['post_attach'] = $local || $upload->is_valid($form_name);
if (!$filedata['post_attach'])
{
@@ -429,30 +422,18 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage
return $filedata;
}
- $cat_id = (isset($extensions[$file->get('extension')]['display_cat'])) ? $extensions[$file->get('extension')]['display_cat'] : ATTACHMENT_CATEGORY_NONE;
+ // Whether the uploaded file is in the image category
+ $is_image = (isset($extensions[$file->get('extension')]['display_cat'])) ? $extensions[$file->get('extension')]['display_cat'] == ATTACHMENT_CATEGORY_IMAGE : false;
- // Make sure the image category only holds valid images...
- if ($cat_id == ATTACHMENT_CATEGORY_IMAGE && !$file->is_image())
- {
- $file->remove();
-
- // If this error occurs a user tried to exploit an IE Bug by renaming extensions
- // Since the image category is displaying content inline we need to catch this.
- trigger_error($user->lang['ATTACHED_IMAGE_NOT_IMAGE']);
- }
-
- // Do we have to create a thumbnail?
- $filedata['thumbnail'] = ($cat_id == ATTACHMENT_CATEGORY_IMAGE && $config['img_create_thumbnail']) ? 1 : 0;
-
- // Check Image Size, if it is an image
- if (!$auth->acl_get('a_') && !$auth->acl_get('m_', $forum_id) && $cat_id == ATTACHMENT_CATEGORY_IMAGE)
- {
- $file->upload->set_allowed_dimensions(0, 0, $config['img_max_width'], $config['img_max_height']);
- }
-
- // Admins and mods are allowed to exceed the allowed filesize
if (!$auth->acl_get('a_') && !$auth->acl_get('m_', $forum_id))
{
+ // Check Image Size, if it is an image
+ if ($is_image)
+ {
+ $file->upload->set_allowed_dimensions(0, 0, $config['img_max_width'], $config['img_max_height']);
+ }
+
+ // Admins and mods are allowed to exceed the allowed filesize
if (!empty($extensions[$file->get('extension')]['max_filesize']))
{
$allowed_filesize = $extensions[$file->get('extension')]['max_filesize'];
@@ -467,10 +448,12 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage
$file->clean_filename('unique', $user->data['user_id'] . '_');
- // Are we uploading an image *and* this image being within the image category? Only then perform additional image checks.
- $no_image = ($cat_id == ATTACHMENT_CATEGORY_IMAGE) ? false : true;
+ // Are we uploading an image *and* this image being within the image category?
+ // Only then perform additional image checks.
+ $file->move_file($config['upload_path'], false, !$is_image);
- $file->move_file($config['upload_path'], false, $no_image);
+ // Do we have to create a thumbnail?
+ $filedata['thumbnail'] = ($is_image && $config['img_create_thumbnail']) ? 1 : 0;
if (sizeof($file->error))
{
@@ -481,6 +464,16 @@ function upload_attachment($form_name, $forum_id, $local = false, $local_storage
return $filedata;
}
+ // Make sure the image category only holds valid images...
+ if ($is_image && !$file->is_image())
+ {
+ $file->remove();
+
+ // If this error occurs a user tried to exploit an IE Bug by renaming extensions
+ // Since the image category is displaying content inline we need to catch this.
+ trigger_error($user->lang['ATTACHED_IMAGE_NOT_IMAGE']);
+ }
+
$filedata['filesize'] = $file->get('filesize');
$filedata['mimetype'] = $file->get('mimetype');
$filedata['extension'] = $file->get('extension');
@@ -989,13 +982,15 @@ function load_drafts($topic_id = 0, $forum_id = 0, $id = 0, $pm_action = '', $ms
function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id = 0, $show_quote_button = true)
{
global $user, $auth, $db, $template, $bbcode, $cache;
- global $config, $phpbb_root_path, $phpEx;
+ global $config, $phpbb_root_path, $phpEx, $phpbb_container;
+
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
// Go ahead and pull all data for this topic
$sql = 'SELECT p.post_id
FROM ' . POSTS_TABLE . ' p' . "
WHERE p.topic_id = $topic_id
- " . ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND p.post_approved = 1' : '') . '
+ AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id, 'p.') . '
' . (($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 ';
@@ -1100,25 +1095,20 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id
$poster_id = $row['user_id'];
$post_subject = $row['post_subject'];
- $message = censor_text($row['post_text']);
$decoded_message = false;
if ($show_quote_button && $auth->acl_get('f_reply', $forum_id))
{
- $decoded_message = $message;
+ $decoded_message = censor_text($row['post_text']);
decode_message($decoded_message, $row['bbcode_uid']);
$decoded_message = bbcode_nl2br($decoded_message);
}
- if ($row['bbcode_bitfield'])
- {
- $bbcode->bbcode_second_pass($message, $row['bbcode_uid'], $row['bbcode_bitfield']);
- }
-
- $message = bbcode_nl2br($message);
- $message = smiley_text($message, !$row['enable_smilies']);
+ $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0);
+ $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0);
+ $message = generate_text_for_display($row['post_text'], $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, true);
if (!empty($attachments[$row['post_id']]))
{
@@ -1175,238 +1165,6 @@ function topic_review($topic_id, $forum_id, $mode = 'topic_review', $cur_post_id
return true;
}
-/**
-* User Notification
-*/
-function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id, $topic_id, $post_id, $author_name = '')
-{
- global $db, $user, $config, $phpbb_root_path, $phpEx, $auth;
-
- $topic_notification = ($mode == 'reply' || $mode == 'quote') ? true : false;
- $forum_notification = ($mode == 'post') ? true : false;
-
- if (!$topic_notification && !$forum_notification)
- {
- trigger_error('NO_MODE');
- }
-
- if (($topic_notification && !$config['allow_topic_notify']) || ($forum_notification && !$config['allow_forum_notify']))
- {
- return;
- }
-
- $topic_title = ($topic_notification) ? $topic_title : $subject;
- $topic_title = censor_text($topic_title);
-
- // Exclude guests, current user and banned users from notifications
- if (!function_exists('phpbb_get_banned_user_ids'))
- {
- include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
- }
- $sql_ignore_users = phpbb_get_banned_user_ids();
- $sql_ignore_users[ANONYMOUS] = ANONYMOUS;
- $sql_ignore_users[$user->data['user_id']] = $user->data['user_id'];
-
- $notify_rows = array();
-
- // -- get forum_userids || topic_userids
- $sql = 'SELECT u.user_id, u.username, u.user_email, u.user_lang, u.user_notify_type, u.user_jabber
- FROM ' . (($topic_notification) ? TOPICS_WATCH_TABLE : FORUMS_WATCH_TABLE) . ' w, ' . USERS_TABLE . ' u
- WHERE w.' . (($topic_notification) ? 'topic_id' : 'forum_id') . ' = ' . (($topic_notification) ? $topic_id : $forum_id) . '
- AND ' . $db->sql_in_set('w.user_id', $sql_ignore_users, true) . '
- AND w.notify_status = ' . NOTIFY_YES . '
- AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')
- AND u.user_id = w.user_id';
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $notify_user_id = (int) $row['user_id'];
- $notify_rows[$notify_user_id] = array(
- 'user_id' => $notify_user_id,
- 'username' => $row['username'],
- 'user_email' => $row['user_email'],
- 'user_jabber' => $row['user_jabber'],
- 'user_lang' => $row['user_lang'],
- 'notify_type' => ($topic_notification) ? 'topic' : 'forum',
- 'template' => ($topic_notification) ? 'topic_notify' : 'newtopic_notify',
- 'method' => $row['user_notify_type'],
- 'allowed' => false
- );
-
- // Add users who have been already notified to ignore list
- $sql_ignore_users[$notify_user_id] = $notify_user_id;
- }
- $db->sql_freeresult($result);
-
- // forum notification is sent to those not already receiving topic notifications
- if ($topic_notification)
- {
- $sql = 'SELECT u.user_id, u.username, u.user_email, u.user_lang, u.user_notify_type, u.user_jabber
- FROM ' . FORUMS_WATCH_TABLE . ' fw, ' . USERS_TABLE . " u
- WHERE fw.forum_id = $forum_id
- AND " . $db->sql_in_set('fw.user_id', $sql_ignore_users, true) . '
- AND fw.notify_status = ' . NOTIFY_YES . '
- AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')
- AND u.user_id = fw.user_id';
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $notify_user_id = (int) $row['user_id'];
- $notify_rows[$notify_user_id] = array(
- 'user_id' => $notify_user_id,
- 'username' => $row['username'],
- 'user_email' => $row['user_email'],
- 'user_jabber' => $row['user_jabber'],
- 'user_lang' => $row['user_lang'],
- 'notify_type' => 'forum',
- 'template' => 'forum_notify',
- 'method' => $row['user_notify_type'],
- 'allowed' => false
- );
- }
- $db->sql_freeresult($result);
- }
-
- if (!sizeof($notify_rows))
- {
- return;
- }
-
- // Make sure users are allowed to read the forum
- foreach ($auth->acl_get_list(array_keys($notify_rows), 'f_read', $forum_id) as $forum_id => $forum_ary)
- {
- foreach ($forum_ary as $auth_option => $user_ary)
- {
- foreach ($user_ary as $user_id)
- {
- $notify_rows[$user_id]['allowed'] = true;
- }
- }
- }
-
- // Now, we have to do a little step before really sending, we need to distinguish our users a little bit. ;)
- $msg_users = $delete_ids = $update_notification = array();
- foreach ($notify_rows as $user_id => $row)
- {
- if (!$row['allowed'] || !trim($row['user_email']))
- {
- $delete_ids[$row['notify_type']][] = $row['user_id'];
- }
- else
- {
- $msg_users[] = $row;
- $update_notification[$row['notify_type']][] = $row['user_id'];
-
- /*
- * We also update the forums watch table for this user when we are
- * sending out a topic notification to prevent sending out another
- * notification in case this user is also subscribed to the forum
- * this topic was posted in.
- * Since an UPDATE query is used, this has no effect on users only
- * subscribed to the topic (i.e. no row is created) and should not
- * be a performance issue.
- */
- if ($row['notify_type'] === 'topic')
- {
- $update_notification['forum'][] = $row['user_id'];
- }
- }
- }
- unset($notify_rows);
-
- // Now, we are able to really send out notifications
- if (sizeof($msg_users))
- {
- include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
- $messenger = new messenger();
-
- $msg_list_ary = array();
- foreach ($msg_users as $row)
- {
- $pos = (!isset($msg_list_ary[$row['template']])) ? 0 : sizeof($msg_list_ary[$row['template']]);
-
- $msg_list_ary[$row['template']][$pos]['method'] = $row['method'];
- $msg_list_ary[$row['template']][$pos]['email'] = $row['user_email'];
- $msg_list_ary[$row['template']][$pos]['jabber'] = $row['user_jabber'];
- $msg_list_ary[$row['template']][$pos]['name'] = $row['username'];
- $msg_list_ary[$row['template']][$pos]['lang'] = $row['user_lang'];
- $msg_list_ary[$row['template']][$pos]['user_id']= $row['user_id'];
- }
- unset($msg_users);
-
- foreach ($msg_list_ary as $email_template => $email_list)
- {
- foreach ($email_list as $addr)
- {
- $messenger->template($email_template, $addr['lang']);
-
- $messenger->to($addr['email'], $addr['name']);
- $messenger->im($addr['jabber'], $addr['name']);
-
- $messenger->assign_vars(array(
- 'USERNAME' => htmlspecialchars_decode($addr['name']),
- 'TOPIC_TITLE' => htmlspecialchars_decode($topic_title),
- 'FORUM_NAME' => htmlspecialchars_decode($forum_name),
- 'AUTHOR_NAME' => htmlspecialchars_decode($author_name),
-
- 'U_FORUM' => generate_board_url() . "/viewforum.$phpEx?f=$forum_id",
- 'U_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&t=$topic_id",
- 'U_NEWEST_POST' => generate_board_url() . "/viewtopic.$phpEx?f=$forum_id&t=$topic_id&p=$post_id&e=$post_id",
- 'U_STOP_WATCHING_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?uid={$addr['user_id']}&f=$forum_id&t=$topic_id&unwatch=topic",
- 'U_STOP_WATCHING_FORUM' => generate_board_url() . "/viewforum.$phpEx?uid={$addr['user_id']}&f=$forum_id&unwatch=forum",
- ));
-
- $messenger->send($addr['method']);
- }
- }
- unset($msg_list_ary);
-
- $messenger->save_queue();
- }
-
- // Handle the DB updates
- $db->sql_transaction('begin');
-
- if (!empty($update_notification['topic']))
- {
- $sql = 'UPDATE ' . TOPICS_WATCH_TABLE . '
- SET notify_status = ' . NOTIFY_NO . "
- WHERE topic_id = $topic_id
- AND " . $db->sql_in_set('user_id', $update_notification['topic']);
- $db->sql_query($sql);
- }
-
- if (!empty($update_notification['forum']))
- {
- $sql = 'UPDATE ' . FORUMS_WATCH_TABLE . '
- SET notify_status = ' . NOTIFY_NO . "
- WHERE forum_id = $forum_id
- AND " . $db->sql_in_set('user_id', $update_notification['forum']);
- $db->sql_query($sql);
- }
-
- // Now delete the user_ids not authorised to receive notifications on this topic/forum
- if (!empty($delete_ids['topic']))
- {
- $sql = 'DELETE FROM ' . TOPICS_WATCH_TABLE . "
- WHERE topic_id = $topic_id
- AND " . $db->sql_in_set('user_id', $delete_ids['topic']);
- $db->sql_query($sql);
- }
-
- if (!empty($delete_ids['forum']))
- {
- $sql = 'DELETE FROM ' . FORUMS_WATCH_TABLE . "
- WHERE forum_id = $forum_id
- AND " . $db->sql_in_set('user_id', $delete_ids['forum']);
- $db->sql_query($sql);
- }
-
- $db->sql_transaction('commit');
-}
-
//
// Post handling functions
//
@@ -1414,14 +1172,14 @@ function user_notification($mode, $subject, $topic_title, $forum_name, $forum_id
/**
* Delete Post
*/
-function delete_post($forum_id, $topic_id, $post_id, &$data)
+function delete_post($forum_id, $topic_id, $post_id, &$data, $is_soft = false, $softdelete_reason = '')
{
- global $db, $user, $auth;
+ global $db, $user, $auth, $phpbb_container;
global $config, $phpEx, $phpbb_root_path;
// Specify our post mode
$post_mode = 'delete';
- if (($data['topic_first_post_id'] === $data['topic_last_post_id']) && $data['topic_replies_real'] == 0)
+ if (($data['topic_first_post_id'] === $data['topic_last_post_id']) && ($data['topic_posts_approved'] + $data['topic_posts_unapproved'] + $data['topic_posts_softdeleted'] == 1))
{
$post_mode = 'delete_topic';
}
@@ -1463,20 +1221,30 @@ function delete_post($forum_id, $topic_id, $post_id, &$data)
$db->sql_freeresult($result);
}
- if (!delete_posts('post_id', array($post_id), false, false))
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+
+ // (Soft) delete the post
+ if ($is_soft && ($post_mode != 'delete_topic'))
{
- // Try to delete topic, we may had an previous error causing inconsistency
- if ($post_mode == 'delete_topic')
+ $phpbb_content_visibility->set_post_visibility(ITEM_DELETED, $post_id, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason, ($data['topic_first_post_id'] == $post_id), ($data['topic_last_post_id'] == $post_id));
+ }
+ else if (!$is_soft)
+ {
+ if (!delete_posts('post_id', array($post_id), false, false, false))
{
- delete_topics('topic_id', array($topic_id), false);
+ // Try to delete topic, we may had an previous error causing inconsistency
+ if ($post_mode == 'delete_topic')
+ {
+ delete_topics('topic_id', array($topic_id), false);
+ }
+ trigger_error('ALREADY_DELETED');
}
- trigger_error('ALREADY_DELETED');
}
$db->sql_transaction('commit');
// Collect the necessary information for updating the tables
- $sql_data[FORUMS_TABLE] = '';
+ $sql_data[FORUMS_TABLE] = $sql_data[TOPICS_TABLE] = '';
switch ($post_mode)
{
case 'delete_topic':
@@ -1485,21 +1253,43 @@ function delete_post($forum_id, $topic_id, $post_id, &$data)
{
// counting is fun! we only have to do sizeof($forum_ids) number of queries,
// even if the topic is moved back to where its shadow lives (we count how many times it is in a forum)
- $db->sql_query('UPDATE ' . FORUMS_TABLE . ' SET forum_topics_real = forum_topics_real - ' . $topic_count . ', forum_topics = forum_topics - ' . $topic_count . ' WHERE forum_id = ' . $updated_forum);
+ $sql = 'UPDATE ' . FORUMS_TABLE . '
+ SET forum_topics_approved = forum_topics_approved - ' . $topic_count . '
+ WHERE forum_id = ' . $updated_forum;
+ $db->sql_query($sql);
update_post_information('forum', $updated_forum);
}
- delete_topics('topic_id', array($topic_id), false);
+ if ($is_soft)
+ {
+ $topic_row = array();
+ $phpbb_content_visibility->set_topic_visibility(ITEM_DELETED, $topic_id, $forum_id, $user->data['user_id'], time(), $softdelete_reason);
+ }
+ else
+ {
+ delete_topics('topic_id', array($topic_id), false);
- $sql_data[FORUMS_TABLE] .= 'forum_topics_real = forum_topics_real - 1';
- $sql_data[FORUMS_TABLE] .= ($data['topic_approved']) ? ', forum_posts = forum_posts - 1, forum_topics = forum_topics - 1' : '';
+ if ($data['topic_visibility'] == ITEM_APPROVED)
+ {
+ $sql_data[FORUMS_TABLE] .= 'forum_posts_approved = forum_posts_approved - 1, forum_topics_approved = forum_topics_approved - 1';
+ }
+ else if ($data['topic_visibility'] == ITEM_UNAPPROVED)
+ {
+ $sql_data[FORUMS_TABLE] .= 'forum_posts_unapproved = forum_posts_unapproved - 1, forum_topics_unapproved = forum_topics_unapproved - 1';
+ }
+ else if ($data['topic_visibility'] == ITEM_DELETED)
+ {
+ $sql_data[FORUMS_TABLE] .= 'forum_posts_softdeleted = forum_posts_softdeleted - 1, forum_topics_softdeleted = forum_topics_softdeleted - 1';
+ }
- $update_sql = update_post_information('forum', $forum_id, true);
- if (sizeof($update_sql))
- {
- $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : '';
- $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]);
+ $update_sql = update_post_information('forum', $forum_id, true);
+ if (sizeof($update_sql))
+ {
+ $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : '';
+ $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]);
+ }
}
+
break;
case 'delete_first_post':
@@ -1507,73 +1297,101 @@ function delete_post($forum_id, $topic_id, $post_id, &$data)
FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u
WHERE p.topic_id = $topic_id
AND p.poster_id = u.user_id
- ORDER BY p.post_time ASC";
+ AND p.post_visibility = " . ITEM_APPROVED . '
+ ORDER BY p.post_time ASC';
$result = $db->sql_query_limit($sql, 1);
$row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- $sql_data[FORUMS_TABLE] = ($data['post_approved']) ? 'forum_posts = forum_posts - 1' : '';
-
- $sql_data[TOPICS_TABLE] = 'topic_poster = ' . intval($row['poster_id']) . ', topic_first_post_id = ' . intval($row['post_id']) . ", topic_first_poster_colour = '" . $db->sql_escape($row['user_colour']) . "', topic_first_poster_name = '" . (($row['poster_id'] == ANONYMOUS) ? $db->sql_escape($row['post_username']) : $db->sql_escape($row['username'])) . "', topic_time = " . (int) $row['post_time'];
-
- // Decrementing topic_replies here is fine because this case only happens if there is more than one post within the topic - basically removing one "reply"
- $sql_data[TOPICS_TABLE] .= ', topic_replies_real = topic_replies_real - 1' . (($data['post_approved']) ? ', topic_replies = topic_replies - 1' : '');
+ if (!$row)
+ {
+ // No approved post, so the first is a not-approved post (unapproved or soft deleted)
+ $sql = 'SELECT p.post_id, p.poster_id, p.post_time, p.post_username, u.username, u.user_colour
+ FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u
+ WHERE p.topic_id = $topic_id
+ AND p.poster_id = u.user_id
+ ORDER BY p.post_time ASC";
+ $result = $db->sql_query_limit($sql, 1);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+ }
$next_post_id = (int) $row['post_id'];
+
+ $sql_data[TOPICS_TABLE] = $db->sql_build_array('UPDATE', array(
+ 'topic_poster' => (int) $row['poster_id'],
+ 'topic_first_post_id' => (int) $row['post_id'],
+ 'topic_first_poster_colour' => $row['user_colour'],
+ 'topic_first_poster_name' => ($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username'],
+ 'topic_time' => (int) $row['post_time'],
+ ));
break;
case 'delete_last_post':
- $sql_data[FORUMS_TABLE] = ($data['post_approved']) ? 'forum_posts = forum_posts - 1' : '';
-
- $update_sql = update_post_information('forum', $forum_id, true);
- if (sizeof($update_sql))
+ if (!$is_soft)
{
- $sql_data[FORUMS_TABLE] .= ($sql_data[FORUMS_TABLE]) ? ', ' : '';
- $sql_data[FORUMS_TABLE] .= implode(', ', $update_sql[$forum_id]);
- }
+ // Update last post information when hard deleting. Soft delete already did that by itself.
+ $update_sql = update_post_information('forum', $forum_id, true);
+ if (sizeof($update_sql))
+ {
+ $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . implode(', ', $update_sql[$forum_id]);
+ }
- $sql_data[TOPICS_TABLE] = 'topic_bumped = 0, topic_bumper = 0, topic_replies_real = topic_replies_real - 1' . (($data['post_approved']) ? ', topic_replies = topic_replies - 1' : '');
+ $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_bumped = 0, topic_bumper = 0';
- $update_sql = update_post_information('topic', $topic_id, true);
- if (sizeof($update_sql))
- {
- $sql_data[TOPICS_TABLE] .= ', ' . implode(', ', $update_sql[$topic_id]);
- $next_post_id = (int) str_replace('topic_last_post_id = ', '', $update_sql[$topic_id][0]);
+ $update_sql = update_post_information('topic', $topic_id, true);
+ if (!empty($update_sql))
+ {
+ $sql_data[TOPICS_TABLE] .= ', ' . implode(', ', $update_sql[$topic_id]);
+ $next_post_id = (int) str_replace('topic_last_post_id = ', '', $update_sql[$topic_id][0]);
+ }
}
- else
+
+ if (!$next_post_id)
{
$sql = 'SELECT MAX(post_id) as last_post_id
FROM ' . POSTS_TABLE . "
- WHERE topic_id = $topic_id " .
- ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND post_approved = 1' : '');
+ WHERE topic_id = $topic_id
+ AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id);
$result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
+ $next_post_id = (int) $db->sql_fetchfield('last_post_id');
$db->sql_freeresult($result);
-
- $next_post_id = (int) $row['last_post_id'];
}
break;
case 'delete':
$sql = 'SELECT post_id
FROM ' . POSTS_TABLE . "
- WHERE topic_id = $topic_id " .
- ((!$auth->acl_get('m_approve', $forum_id)) ? 'AND post_approved = 1' : '') . '
+ WHERE topic_id = $topic_id
+ AND " . $phpbb_content_visibility->get_visibility_sql('post', $forum_id) . '
AND post_time > ' . $data['post_time'] . '
ORDER BY post_time ASC';
$result = $db->sql_query_limit($sql, 1);
- $row = $db->sql_fetchrow($result);
+ $next_post_id = (int) $db->sql_fetchfield('post_id');
$db->sql_freeresult($result);
-
- $sql_data[FORUMS_TABLE] = ($data['post_approved']) ? 'forum_posts = forum_posts - 1' : '';
-
- $sql_data[TOPICS_TABLE] = 'topic_replies_real = topic_replies_real - 1' . (($data['post_approved']) ? ', topic_replies = topic_replies - 1' : '');
- $next_post_id = (int) $row['post_id'];
break;
}
if (($post_mode == 'delete') || ($post_mode == 'delete_last_post') || ($post_mode == 'delete_first_post'))
{
+ if (!$is_soft)
+ {
+ if ($data['post_visibility'] == ITEM_APPROVED)
+ {
+ $phpbb_content_visibility->remove_post_from_statistic($data, $sql_data);
+ }
+ else if ($data['post_visibility'] == ITEM_UNAPPROVED)
+ {
+ $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . 'forum_posts_unapproved = forum_posts_unapproved - 1';
+ $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_posts_unapproved = topic_posts_unapproved - 1';
+ }
+ else if ($data['post_visibility'] == ITEM_DELETED)
+ {
+ $sql_data[FORUMS_TABLE] = (($sql_data[FORUMS_TABLE]) ? $sql_data[FORUMS_TABLE] . ', ' : '') . 'forum_posts_softdeleted = forum_posts_softdeleted - 1';
+ $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_posts_softdeleted = topic_posts_softdeleted - 1';
+ }
+ }
+
$sql = 'SELECT 1 AS has_attachments
FROM ' . ATTACHMENTS_TABLE . '
WHERE topic_id = ' . $topic_id;
@@ -1583,18 +1401,16 @@ function delete_post($forum_id, $topic_id, $post_id, &$data)
if (!$has_attachments)
{
- $sql_data[TOPICS_TABLE] .= ', topic_attachment = 0';
+ $sql_data[TOPICS_TABLE] = (($sql_data[TOPICS_TABLE]) ? $sql_data[TOPICS_TABLE] . ', ' : '') . 'topic_attachment = 0';
}
}
-// $sql_data[USERS_TABLE] = ($data['post_postcount']) ? 'user_posts = user_posts - 1' : '';
-
$db->sql_transaction('begin');
$where_sql = array(
FORUMS_TABLE => "forum_id = $forum_id",
TOPICS_TABLE => "topic_id = $topic_id",
- USERS_TABLE => 'user_id = ' . $data['poster_id']
+ USERS_TABLE => 'user_id = ' . $data['poster_id'],
);
foreach ($sql_data as $table => $update_sql)
@@ -1642,7 +1458,7 @@ function delete_post($forum_id, $topic_id, $post_id, &$data)
*/
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;
+ global $db, $auth, $user, $config, $phpEx, $template, $phpbb_root_path, $phpbb_container;
// We do not handle erasing posts here
if ($mode == 'delete')
@@ -1664,7 +1480,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
}
else if ($mode == 'edit')
{
- $post_mode = ($data['topic_replies_real'] == 0) ? 'edit_topic' : (($data['topic_first_post_id'] == $data['post_id']) ? 'edit_first_post' : (($data['topic_last_post_id'] == $data['post_id']) ? 'edit_last_post' : 'edit'));
+ $post_mode = ($data['topic_posts_approved'] + $data['topic_posts_unapproved'] + $data['topic_posts_softdeleted'] == 1) ? 'edit_topic' : (($data['topic_first_post_id'] == $data['post_id']) ? 'edit_first_post' : (($data['topic_last_post_id'] == $data['post_id']) ? 'edit_last_post' : 'edit'));
}
// First of all make sure the subject and topic title are having the correct length.
@@ -1677,9 +1493,9 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$poster_id = ($mode == 'edit') ? $data['poster_id'] : (int) $user->data['user_id'];
// Retrieve some additional information if not present
- if ($mode == 'edit' && (!isset($data['post_approved']) || !isset($data['topic_approved']) || $data['post_approved'] === false || $data['topic_approved'] === false))
+ if ($mode == 'edit' && (!isset($data['post_visibility']) || !isset($data['topic_visibility']) || $data['post_visibility'] === false || $data['topic_visibility'] === false))
{
- $sql = 'SELECT p.post_approved, t.topic_type, t.topic_replies, t.topic_replies_real, t.topic_approved
+ $sql = 'SELECT p.post_visibility, t.topic_type, t.topic_posts_approved, t.topic_posts_unapproved, t.topic_posts_softdeleted, t.topic_visibility
FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . ' p
WHERE t.topic_id = p.topic_id
AND p.post_id = ' . $data['post_id'];
@@ -1687,25 +1503,29 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$topic_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- $data['topic_approved'] = $topic_row['topic_approved'];
- $data['post_approved'] = $topic_row['post_approved'];
+ $data['topic_visibility'] = $topic_row['topic_visibility'];
+ $data['post_visibility'] = $topic_row['post_visibility'];
}
- // 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;
+ // This variable indicates if the user is able to post or put into the queue
+ $post_visibility = ITEM_APPROVED;
- // 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']))
+ // Check the permissions for post approval.
+ // Moderators must go through post approval like ordinary users.
+ if (!$auth->acl_get('f_noapprove', $data['forum_id']))
{
// Post not approved, but in queue
- $post_approval = 0;
+ $post_visibility = ITEM_UNAPPROVED;
}
- // Mods are able to force approved/unapproved posts. True means the post is approved, false the post is unapproved
+ // MODs/Extensions are able to force any visibility on posts
if (isset($data['force_approved_state']))
{
- $post_approval = ($data['force_approved_state']) ? 1 : 0;
+ $post_visibility = (in_array((int) $data['force_approved_state'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED))) ? (int) $data['force_approved_state'] : $post_visibility;
+ }
+ if (isset($data['force_visibility']))
+ {
+ $post_visibility = (in_array((int) $data['force_visibility'], array(ITEM_APPROVED, ITEM_UNAPPROVED, ITEM_DELETED))) ? (int) $data['force_visibility'] : $post_visibility;
}
// Start the transaction here
@@ -1722,7 +1542,7 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
'icon_id' => $data['icon_id'],
'poster_ip' => $user->ip,
'post_time' => $current_time,
- 'post_approved' => $post_approval,
+ 'post_visibility' => $post_visibility,
'enable_bbcode' => $data['enable_bbcode'],
'enable_smilies' => $data['enable_smilies'],
'enable_magic_url' => $data['enable_urls'],
@@ -1788,7 +1608,8 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
'forum_id' => $data['forum_id'],
'poster_id' => $data['poster_id'],
'icon_id' => $data['icon_id'],
- 'post_approved' => (!$post_approval) ? 0 : $data['post_approved'],
+ // We will change the visibility later
+ //'post_visibility' => $post_visibility,
'enable_bbcode' => $data['enable_bbcode'],
'enable_smilies' => $data['enable_smilies'],
'enable_magic_url' => $data['enable_urls'],
@@ -1809,8 +1630,6 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
break;
}
-
- $post_approved = $sql_data[POSTS_TABLE]['sql']['post_approved'];
$topic_row = array();
// And the topic ladies and gentlemen
@@ -1823,7 +1642,11 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
'topic_last_view_time' => $current_time,
'forum_id' => $data['forum_id'],
'icon_id' => $data['icon_id'],
- 'topic_approved' => $post_approval,
+ 'topic_posts_approved' => ($post_visibility == ITEM_APPROVED) ? 1 : 0,
+ 'topic_posts_softdeleted' => ($post_visibility == ITEM_DELETED) ? 1 : 0,
+ 'topic_posts_unapproved' => ($post_visibility == ITEM_UNAPPROVED) ? 1 : 0,
+ 'topic_visibility' => $post_visibility,
+ 'topic_delete_user' => ($post_visibility != ITEM_APPROVED) ? (int) $user->data['user_id'] : 0,
'topic_title' => $subject,
'topic_first_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''),
'topic_first_poster_colour' => $user->data['user_colour'],
@@ -1855,28 +1678,47 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
);
}
- $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_approval) ? ', user_posts = user_posts + 1' : '');
+ $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : '');
- if ($post_approval)
+ if ($post_visibility == ITEM_APPROVED)
+ {
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_approved = forum_topics_approved + 1';
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1';
+ }
+ else if ($post_visibility == ITEM_UNAPPROVED)
+ {
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_unapproved = forum_topics_unapproved + 1';
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1';
+ }
+ else if ($post_visibility == ITEM_DELETED)
{
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts + 1';
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_softdeleted = forum_topics_softdeleted + 1';
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1';
}
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics_real = forum_topics_real + 1' . (($post_approval) ? ', forum_topics = forum_topics + 1' : '');
break;
case 'reply':
$sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_view_time = ' . $current_time . ',
- topic_replies_real = topic_replies_real + 1,
topic_bumped = 0,
topic_bumper = 0' .
- (($post_approval) ? ', topic_replies = topic_replies + 1' : '') .
+ (($post_visibility == ITEM_APPROVED) ? ', topic_posts_approved = topic_posts_approved + 1' : '') .
+ (($post_visibility == ITEM_UNAPPROVED) ? ', topic_posts_unapproved = topic_posts_unapproved + 1' : '') .
+ (($post_visibility == ITEM_DELETED) ? ', topic_posts_softdeleted = topic_posts_softdeleted + 1' : '') .
((!empty($data['attachment_data']) || (isset($data['topic_attachment']) && $data['topic_attachment'])) ? ', topic_attachment = 1' : '');
- $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_approval) ? ', user_posts = user_posts + 1' : '');
+ $sql_data[USERS_TABLE]['stat'][] = "user_lastpost_time = $current_time" . (($auth->acl_get('f_postcount', $data['forum_id']) && $post_visibility == ITEM_APPROVED) ? ', user_posts = user_posts + 1' : '');
- if ($post_approval)
+ if ($post_visibility == ITEM_APPROVED)
+ {
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_approved = forum_posts_approved + 1';
+ }
+ else if ($post_visibility == ITEM_UNAPPROVED)
{
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts + 1';
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_unapproved = forum_posts_unapproved + 1';
+ }
+ else if ($post_visibility == ITEM_DELETED)
+ {
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts_softdeleted = forum_posts_softdeleted + 1';
}
break;
@@ -1900,7 +1742,6 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
$sql_data[TOPICS_TABLE]['sql'] = array(
'forum_id' => $data['forum_id'],
'icon_id' => $data['icon_id'],
- 'topic_approved' => (!$post_approval) ? 0 : $data['topic_approved'],
'topic_title' => $subject,
'topic_first_poster_name' => $username,
'topic_type' => $topic_type,
@@ -1915,56 +1756,6 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
'topic_attachment' => (!empty($data['attachment_data'])) ? 1 : (isset($data['topic_attachment']) ? $data['topic_attachment'] : 0),
);
- // Correctly set back the topic replies and forum posts... only if the topic was approved before and now gets disapproved
- if (!$post_approval && $data['topic_approved'])
- {
- // Do we need to grab some topic informations?
- if (!sizeof($topic_row))
- {
- $sql = 'SELECT topic_type, topic_replies, topic_replies_real, topic_approved
- FROM ' . TOPICS_TABLE . '
- WHERE topic_id = ' . $data['topic_id'];
- $result = $db->sql_query($sql);
- $topic_row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
- }
-
- // If this is the only post remaining we do not need to decrement topic_replies.
- // Also do not decrement if first post - then the topic_replies will not be adjusted if approving the topic again.
-
- // If this is an edited topic or the first post the topic gets completely disapproved later on...
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_topics = forum_topics - 1';
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts - ' . ($topic_row['topic_replies'] + 1);
-
- set_config_count('num_topics', -1, true);
- set_config_count('num_posts', ($topic_row['topic_replies'] + 1) * (-1), true);
-
- // Only decrement this post, since this is the one non-approved now
- if ($auth->acl_get('f_postcount', $data['forum_id']))
- {
- $sql_data[USERS_TABLE]['stat'][] = 'user_posts = user_posts - 1';
- }
- }
-
- break;
-
- case 'edit':
- case 'edit_last_post':
-
- // Correctly set back the topic replies and forum posts... but only if the post was approved before.
- if (!$post_approval && $data['post_approved'])
- {
- $sql_data[TOPICS_TABLE]['stat'][] = 'topic_replies = topic_replies - 1, topic_last_view_time = ' . $current_time;
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_posts = forum_posts - 1';
-
- set_config_count('num_posts', -1, true);
-
- if ($auth->acl_get('f_postcount', $data['forum_id']))
- {
- $sql_data[USERS_TABLE]['stat'][] = 'user_posts = user_posts - 1';
- }
- }
-
break;
}
@@ -1989,27 +1780,48 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
if ($post_mode == 'reply')
{
$sql_data[POSTS_TABLE]['sql'] = array_merge($sql_data[POSTS_TABLE]['sql'], array(
- 'topic_id' => $data['topic_id'])
- );
+ 'topic_id' => $data['topic_id'],
+ ));
}
$sql = 'INSERT INTO ' . POSTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_data[POSTS_TABLE]['sql']);
$db->sql_query($sql);
$data['post_id'] = $db->sql_nextid();
- if ($post_mode == 'post')
+ if ($post_mode == 'post' || $post_visibility == ITEM_APPROVED)
{
$sql_data[TOPICS_TABLE]['sql'] = array(
- 'topic_first_post_id' => $data['post_id'],
'topic_last_post_id' => $data['post_id'],
'topic_last_post_time' => $current_time,
- 'topic_last_poster_id' => (int) $user->data['user_id'],
- 'topic_last_poster_name' => (!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : ''),
+ 'topic_last_poster_id' => $sql_data[POSTS_TABLE]['sql']['poster_id'],
+ 'topic_last_poster_name' => ($user->data['user_id'] == ANONYMOUS) ? $sql_data[POSTS_TABLE]['sql']['post_username'] : $user->data['username'],
'topic_last_poster_colour' => $user->data['user_colour'],
'topic_last_post_subject' => (string) $subject,
);
}
+ if ($post_mode == 'post')
+ {
+ $sql_data[TOPICS_TABLE]['sql']['topic_first_post_id'] = $data['post_id'];
+ }
+
+ // Update total post count and forum information
+ if ($post_visibility == ITEM_APPROVED)
+ {
+ if ($post_mode == 'post')
+ {
+ set_config_count('num_topics', 1, true);
+ }
+ set_config_count('num_posts', 1, true);
+
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . $data['post_id'];
+ $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'";
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . $current_time;
+ $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $user->data['user_id'];
+ $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape((!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '')) . "'";
+ $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($user->data['user_colour']) . "'";
+ }
+
unset($sql_data[POSTS_TABLE]['sql']);
}
@@ -2020,6 +1832,8 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
SET ' . $db->sql_build_array('UPDATE', $sql_data[TOPICS_TABLE]['sql']) . '
WHERE topic_id = ' . $data['topic_id'];
$db->sql_query($sql);
+
+ unset($sql_data[TOPICS_TABLE]['sql']);
}
// Update the posts table
@@ -2029,6 +1843,8 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
SET ' . $db->sql_build_array('UPDATE', $sql_data[POSTS_TABLE]['sql']) . '
WHERE post_id = ' . $data['post_id'];
$db->sql_query($sql);
+
+ unset($sql_data[POSTS_TABLE]['sql']);
}
// Update Poll Tables
@@ -2174,114 +1990,25 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
}
}
- // we need to update the last forum information
- // only applicable if the topic is approved
- if ($post_approved || !$data['post_approved'])
+ $first_post_has_topic_info = ($post_mode == 'edit_first_post' &&
+ (($post_visibility == ITEM_DELETED && $data['topic_posts_softdeleted'] == 1) ||
+ ($post_visibility == ITEM_UNAPPROVED && $data['topic_posts_unapproved'] == 1) ||
+ ($post_visibility == ITEM_APPROVED && $data['topic_posts_approved'] == 1)));
+ // Fix the post's and topic's visibility and first/last post information, when the post is edited
+ if (($post_mode != 'post' && $post_mode != 'reply') && $data['post_visibility'] != $post_visibility)
{
- // the last post makes us update the forum table. This can happen if...
- // We make a new topic
- // We reply to a topic
- // We edit the last post in a topic and this post is the latest in the forum (maybe)
- // We edit the only post in the topic
- // We edit the first post in the topic and all the other posts are not approved
- if (($post_mode == 'post' || $post_mode == 'reply') && $post_approved)
- {
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . $data['post_id'];
- $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'";
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . $current_time;
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $user->data['user_id'];
- $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape((!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '')) . "'";
- $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($user->data['user_colour']) . "'";
- }
- else if ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || ($post_mode == 'edit_first_post' && !$data['topic_replies']))
- {
- // this does not _necessarily_ mean that we must update the info again,
- // it just means that we might have to
- $sql = 'SELECT forum_last_post_id, forum_last_post_subject
- FROM ' . FORUMS_TABLE . '
- WHERE forum_id = ' . (int) $data['forum_id'];
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
+ // If the post was not approved, it could also be the starter,
+ // so we sync the starter after approving/restoring, to ensure that the stats are correct
+ // Same applies for the last post
+ $is_starter = ($post_mode == 'edit_first_post' || $data['post_visibility'] != ITEM_APPROVED);
+ $is_latest = ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $data['post_visibility'] != ITEM_APPROVED);
- // this post is the latest post in the forum, better update
- if ($row['forum_last_post_id'] == $data['post_id'])
- {
- // If post approved and subject changed, or poster is anonymous, we need to update the forum_last* rows
- if ($post_approved && ($row['forum_last_post_subject'] !== $subject || $data['poster_id'] == ANONYMOUS))
- {
- // the post's subject changed
- if ($row['forum_last_post_subject'] !== $subject)
- {
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_subject = \'' . $db->sql_escape($subject) . '\'';
- }
-
- // Update the user name if poster is anonymous... just in case an admin changed it
- if ($data['poster_id'] == ANONYMOUS)
- {
- $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape($username) . "'";
- }
- }
- else if ($data['post_approved'] !== $post_approved)
- {
- // we need a fresh change of socks, everything has become invalidated
- $sql = 'SELECT MAX(topic_last_post_id) as last_post_id
- FROM ' . TOPICS_TABLE . '
- WHERE forum_id = ' . (int) $data['forum_id'] . '
- AND topic_approved = 1';
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- // any posts left in this forum?
- if (!empty($row['last_post_id']))
- {
- $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour
- FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
- WHERE p.poster_id = u.user_id
- AND p.post_id = ' . (int) $row['last_post_id'];
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- // salvation, a post is found! jam it into the forums table
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = ' . (int) $row['post_id'];
- $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'";
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = ' . (int) $row['post_time'];
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = ' . (int) $row['poster_id'];
- $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape(($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']) . "'";
- $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'";
- }
- else
- {
- // just our luck, the last topic in the forum has just been turned unapproved...
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_id = 0';
- $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = ''";
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_post_time = 0';
- $sql_data[FORUMS_TABLE]['stat'][] = 'forum_last_poster_id = 0';
- $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = ''";
- $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_colour = ''";
- }
- }
- }
- }
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+ $phpbb_content_visibility->set_post_visibility($post_visibility, $data['post_id'], $data['topic_id'], $data['forum_id'], $user->data['user_id'], time(), '', $is_starter, $is_latest);
}
-
- // topic sync time!
- // simply, we update if it is a reply or the last post is edited
- if ($post_approved)
+ else if ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || $first_post_has_topic_info)
{
- // reply requires the whole thing
- if ($post_mode == 'reply')
- {
- $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_post_id = ' . (int) $data['post_id'];
- $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_poster_id = ' . (int) $user->data['user_id'];
- $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape((!$user->data['is_registered'] && $username) ? $username : (($user->data['user_id'] != ANONYMOUS) ? $user->data['username'] : '')) . "'";
- $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_colour = '" . (($user->data['user_id'] != ANONYMOUS) ? $db->sql_escape($user->data['user_colour']) : '') . "'";
- $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($subject) . "'";
- $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_post_time = ' . (int) $current_time;
- }
- else if ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || ($post_mode == 'edit_first_post' && !$data['topic_replies']))
+ if ($post_visibility == ITEM_APPROVED || $data['topic_visibility'] == $post_visibility)
{
// only the subject can be changed from edit
$sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($subject) . "'";
@@ -2291,57 +2018,44 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
{
$sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape($username) . "'";
}
- }
- }
- else if (!$data['post_approved'] && ($post_mode == 'edit_last_post' || $post_mode == 'edit_topic' || ($post_mode == 'edit_first_post' && !$data['topic_replies'])))
- {
- // like having the rug pulled from under us
- $sql = 'SELECT MAX(post_id) as last_post_id
- FROM ' . POSTS_TABLE . '
- WHERE topic_id = ' . (int) $data['topic_id'] . '
- AND post_approved = 1';
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
- // any posts left in this forum?
- if (!empty($row['last_post_id']))
- {
- $sql = 'SELECT p.post_id, p.post_subject, p.post_time, p.poster_id, p.post_username, u.user_id, u.username, u.user_colour
- FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
- WHERE p.poster_id = u.user_id
- AND p.post_id = ' . (int) $row['last_post_id'];
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- // salvation, a post is found! jam it into the topics table
- $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_post_id = ' . (int) $row['post_id'];
- $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_post_subject = '" . $db->sql_escape($row['post_subject']) . "'";
- $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_post_time = ' . (int) $row['post_time'];
- $sql_data[TOPICS_TABLE]['stat'][] = 'topic_last_poster_id = ' . (int) $row['poster_id'];
- $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_name = '" . $db->sql_escape(($row['poster_id'] == ANONYMOUS) ? $row['post_username'] : $row['username']) . "'";
- $sql_data[TOPICS_TABLE]['stat'][] = "topic_last_poster_colour = '" . $db->sql_escape($row['user_colour']) . "'";
- }
- }
+ if ($post_visibility == ITEM_APPROVED)
+ {
+ // this does not _necessarily_ mean that we must update the info again,
+ // it just means that we might have to
+ $sql = 'SELECT forum_last_post_id, forum_last_post_subject
+ FROM ' . FORUMS_TABLE . '
+ WHERE forum_id = ' . (int) $data['forum_id'];
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
- // Update total post count, do not consider moderated posts/topics
- if ($post_approval)
- {
- if ($post_mode == 'post')
- {
- set_config_count('num_topics', 1, true);
- set_config_count('num_posts', 1, true);
- }
+ // this post is the latest post in the forum, better update
+ if ($row['forum_last_post_id'] == $data['post_id'] && ($row['forum_last_post_subject'] !== $subject || $data['poster_id'] == ANONYMOUS))
+ {
+ // the post's subject changed
+ if ($row['forum_last_post_subject'] !== $subject)
+ {
+ $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_post_subject = '" . $db->sql_escape($subject) . "'";
+ }
- if ($post_mode == 'reply')
- {
- set_config_count('num_posts', 1, true);
+ // Update the user name if poster is anonymous... just in case a moderator changed it
+ if ($data['poster_id'] == ANONYMOUS)
+ {
+ $sql_data[FORUMS_TABLE]['stat'][] = "forum_last_poster_name = '" . $db->sql_escape($username) . "'";
+ }
+ }
+ }
}
}
// Update forum stats
- $where_sql = array(POSTS_TABLE => 'post_id = ' . $data['post_id'], TOPICS_TABLE => 'topic_id = ' . $data['topic_id'], FORUMS_TABLE => 'forum_id = ' . $data['forum_id'], USERS_TABLE => 'user_id = ' . $poster_id);
+ $where_sql = array(
+ POSTS_TABLE => 'post_id = ' . $data['post_id'],
+ TOPICS_TABLE => 'topic_id = ' . $data['topic_id'],
+ FORUMS_TABLE => 'forum_id = ' . $data['forum_id'],
+ USERS_TABLE => 'user_id = ' . $poster_id
+ );
foreach ($sql_data as $table => $update_ary)
{
@@ -2452,16 +2166,113 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u
update_forum_tracking_info($data['forum_id'], $forum_last_post_time, $f_mark_time, false);
}
+ // If a username was supplied or the poster is a guest, we will use the supplied username.
+ // Doing it this way we can use "...post by guest-username..." in notifications when
+ // "guest-username" is supplied or ommit the username if it is not.
+ $username = ($username !== '' || !$user->data['is_registered']) ? $username : $user->data['username'];
+
// Send Notifications
- if (($mode == 'reply' || $mode == 'quote' || $mode == 'post') && $post_approval)
+ $notification_data = array_merge($data, array(
+ 'topic_title' => (isset($data['topic_title'])) ? $data['topic_title'] : $subject,
+ 'post_username' => $username,
+ 'poster_id' => $poster_id,
+ 'post_text' => $data['message'],
+ 'post_time' => $current_time,
+ 'post_subject' => $subject,
+ ));
+
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ if ($post_visibility == ITEM_APPROVED)
{
- $username = ($username) ? $username : $user->data['username'];
- user_notification($mode, $subject, $data['topic_title'], $data['forum_name'], $data['forum_id'], $data['topic_id'], $data['post_id'], $username);
+ switch ($mode)
+ {
+ case 'post':
+ $phpbb_notifications->add_notifications(array(
+ 'quote',
+ 'topic',
+ ), $notification_data);
+ break;
+
+ case 'reply':
+ case 'quote':
+ $phpbb_notifications->add_notifications(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ ), $notification_data);
+ break;
+
+ case 'edit_topic':
+ case 'edit_first_post':
+ case 'edit':
+ case 'edit_last_post':
+ $phpbb_notifications->update_notifications(array(
+ 'quote',
+ 'bookmark',
+ 'topic',
+ 'post',
+ ), $notification_data);
+ break;
+ }
+ }
+ else if ($post_visibility == ITEM_UNAPPROVED)
+ {
+ switch ($mode)
+ {
+ case 'post':
+ $phpbb_notifications->add_notifications('topic_in_queue', $notification_data);
+ break;
+
+ case 'reply':
+ case 'quote':
+ $phpbb_notifications->add_notifications('post_in_queue', $notification_data);
+ break;
+
+ case 'edit_topic':
+ case 'edit_first_post':
+ case 'edit':
+ case 'edit_last_post':
+ // @todo: Check whether these notification deletions are correct
+ $phpbb_notifications->delete_notifications('topic', $data['topic_id']);
+
+ $phpbb_notifications->delete_notifications(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ ), $data['post_id']);
+ break;
+ }
+ }
+ else if ($post_visibility == ITEM_DELETED)
+ {
+ switch ($mode)
+ {
+ case 'post':
+ case 'reply':
+ case 'quote':
+ // Nothing to do here
+ break;
+
+ case 'edit_topic':
+ case 'edit_first_post':
+ case 'edit':
+ case 'edit_last_post':
+ // @todo: Check whether these notification deletions are correct
+ $phpbb_notifications->delete_notifications('topic', $data['topic_id']);
+
+ $phpbb_notifications->delete_notifications(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ ), $data['post_id']);
+ break;
+ }
}
$params = $add_anchor = '';
- if ($post_approval)
+ if ($post_visibility == ITEM_APPROVED)
{
$params .= '&amp;t=' . $data['topic_id'];
diff --git a/phpBB/includes/functions_privmsgs.php b/phpBB/includes/functions_privmsgs.php
index 57c872d91a..5fc6de8e02 100644
--- a/phpBB/includes/functions_privmsgs.php
+++ b/phpBB/includes/functions_privmsgs.php
@@ -876,7 +876,11 @@ function update_unread_status($unread, $msg_id, $user_id, $folder_id)
return;
}
- global $db, $user;
+ global $db, $user, $phpbb_container;
+
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->mark_notifications_read('pm', $msg_id, $user_id);
$sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . "
SET pm_unread = 0
@@ -981,7 +985,7 @@ function handle_mark_actions($user_id, $mark_action)
*/
function delete_pm($user_id, $msg_ids, $folder_id)
{
- global $db, $user, $phpbb_root_path, $phpEx;
+ global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;
$user_id = (int) $user_id;
$folder_id = (int) $folder_id;
@@ -1093,6 +1097,10 @@ function delete_pm($user_id, $msg_ids, $folder_id)
$user->data['user_unread_privmsg'] -= $num_unread;
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->delete_notifications('pm', array_keys($delete_rows));
+
// Now we have to check which messages we can delete completely
$sql = 'SELECT msg_id
FROM ' . PRIVMSGS_TO_TABLE . '
@@ -1157,7 +1165,7 @@ function phpbb_delete_user_pms($user_id)
*/
function phpbb_delete_users_pms($user_ids)
{
- global $db, $user, $phpbb_root_path, $phpEx;
+ global $db, $user, $phpbb_root_path, $phpEx, $phpbb_container;
$user_id_sql = $db->sql_in_set('user_id', $user_ids);
$author_id_sql = $db->sql_in_set('author_id', $user_ids);
@@ -1202,6 +1210,8 @@ function phpbb_delete_users_pms($user_ids)
$db->sql_transaction('begin');
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
if (!empty($undelivered_msg))
{
// A pm is delivered, if for any recipient the message was moved
@@ -1270,6 +1280,8 @@ function phpbb_delete_users_pms($user_ids)
WHERE folder_id = ' . PRIVMSGS_NO_BOX . '
AND ' . $db->sql_in_set('msg_id', $delivered_msg);
$db->sql_query($sql);
+
+ $phpbb_notifications->delete_notifications('pm', $delivered_msg);
}
if (!empty($undelivered_msg))
@@ -1281,6 +1293,8 @@ function phpbb_delete_users_pms($user_ids)
$sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
WHERE ' . $db->sql_in_set('msg_id', $undelivered_msg);
$db->sql_query($sql);
+
+ $phpbb_notifications->delete_notifications('pm', $undelivered_msg);
}
}
@@ -1323,6 +1337,8 @@ function phpbb_delete_users_pms($user_ids)
$sql = 'DELETE FROM ' . PRIVMSGS_TABLE . '
WHERE ' . $db->sql_in_set('msg_id', $delete_ids);
$db->sql_query($sql);
+
+ $phpbb_notifications->delete_notifications('pm', $delete_ids);
}
}
@@ -1559,7 +1575,7 @@ function get_folder_status($folder_id, $folder)
*/
function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
{
- global $db, $auth, $config, $phpEx, $template, $user, $phpbb_root_path;
+ global $db, $auth, $config, $phpEx, $template, $user, $phpbb_root_path, $phpbb_container;
// We do not handle erasing pms here
if ($mode == 'delete')
@@ -1859,102 +1875,23 @@ function submit_pm($mode, $subject, &$data, $put_in_outbox = true)
$db->sql_transaction('commit');
// Send Notifications
- if ($mode != 'edit')
- {
- pm_notification($mode, $data['from_username'], $recipients, $subject, $data['message'], $data['msg_id']);
- }
-
- return $data['msg_id'];
-}
-
-/**
-* PM Notification
-*/
-function pm_notification($mode, $author, $recipients, $subject, $message, $msg_id)
-{
- global $db, $user, $config, $phpbb_root_path, $phpEx, $auth;
-
- $subject = censor_text($subject);
-
- // Exclude guests, current user and banned users from notifications
- unset($recipients[ANONYMOUS], $recipients[$user->data['user_id']]);
-
- if (!sizeof($recipients))
- {
- return;
- }
-
- // Get currently banned users (do not notify these users)
- if (!function_exists('phpbb_get_banned_user_ids'))
- {
- include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
- }
- $banned_users = phpbb_get_banned_user_ids(array_keys($recipients));
- $recipients = array_diff(array_keys($recipients), $banned_users);
+ $pm_data = array_merge($data, array(
+ 'message_subject' => $subject,
+ 'recipients' => $recipients,
+ ));
- // Get the list of users who can read PMs (only notify those who can read PMs)
- $can_read = $auth->acl_get_list($recipients, 'u_readpm');
- $can_read = (empty($can_read) || !isset($can_read[0]['u_readpm'])) ? array() : $can_read[0]['u_readpm'];
- $recipients = array_intersect($recipients, $can_read);
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
- if (!sizeof($recipients))
+ if ($mode == 'edit')
{
- return;
+ $phpbb_notifications->update_notifications('pm', $pm_data);
}
-
- // Get the list of users who want to receive notifications, are "normal" and not deactivated, and have a non-blank email address
- $sql = 'SELECT user_id, username, user_type, user_inactive_reason, user_email, user_lang, user_notify_pm, user_notify_type, user_jabber
- FROM ' . USERS_TABLE . '
- WHERE ' . $db->sql_in_set('user_id', $recipients);
- $result = $db->sql_query($sql);
-
- $msg_list_ary = array();
- while ($row = $db->sql_fetchrow($result))
- {
- if ($row['user_notify_pm'] == 1 && $row['user_type'] != USER_IGNORE && !($row['user_type'] == USER_INACTIVE && $row['user_inactive_reason'] == INACTIVE_MANUAL) && trim($row['user_email']))
- {
- $msg_list_ary[] = array(
- 'method' => $row['user_notify_type'],
- 'email' => $row['user_email'],
- 'jabber' => $row['user_jabber'],
- 'name' => $row['username'],
- 'lang' => $row['user_lang']
- );
- }
- }
- $db->sql_freeresult($result);
-
- if (!sizeof($msg_list_ary))
- {
- return;
- }
-
- include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
- $messenger = new messenger();
-
- foreach ($msg_list_ary as $pos => $addr)
+ else
{
- $messenger->template('privmsg_notify', $addr['lang']);
-
- $messenger->to($addr['email'], $addr['name']);
- $messenger->im($addr['jabber'], $addr['name']);
-
- $messenger->assign_vars(array(
- 'SUBJECT' => htmlspecialchars_decode($subject),
- 'AUTHOR_NAME' => htmlspecialchars_decode($author),
- 'USERNAME' => htmlspecialchars_decode($addr['name']),
-
- 'U_INBOX' => generate_board_url() . "/ucp.$phpEx?i=pm&folder=inbox",
- 'U_VIEW_MESSAGE' => generate_board_url() . "/ucp.$phpEx?i=pm&mode=view&p=$msg_id",
- ));
-
- $messenger->send($addr['method']);
+ $phpbb_notifications->add_notifications('pm', $pm_data);
}
- unset($msg_list_ary);
-
- $messenger->save_queue();
- unset($messenger);
+ return $data['msg_id'];
}
/**
@@ -2081,14 +2018,11 @@ function message_history($msg_id, $user_id, $message_row, $folder, $in_post_mode
$decoded_message = bbcode_nl2br($decoded_message);
}
-
- if ($row['bbcode_bitfield'])
- {
- $bbcode->bbcode_second_pass($message, $row['bbcode_uid'], $row['bbcode_bitfield']);
- }
-
- $message = bbcode_nl2br($message);
- $message = smiley_text($message, !$row['enable_smilies']);
+
+ $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0);
+ $parse_flags |= ($row['enable_smilies'] ? OPTION_FLAG_SMILIES : 0);
+
+ $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false);
$subject = censor_text($subject);
diff --git a/phpBB/includes/functions_profile_fields.php b/phpBB/includes/functions_profile_fields.php
index 10af997bff..7dd0b0e87d 100644
--- a/phpBB/includes/functions_profile_fields.php
+++ b/phpBB/includes/functions_profile_fields.php
@@ -1040,9 +1040,9 @@ class custom_profile_admin extends custom_profile
global $user;
$options = array(
- 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input type="text" name="field_length" size="5" value="' . $this->vars['field_length'] . '" />'),
- 1 => array('TITLE' => $user->lang['MIN_FIELD_CHARS'], 'FIELD' => '<input type="text" name="field_minlen" size="5" value="' . $this->vars['field_minlen'] . '" />'),
- 2 => array('TITLE' => $user->lang['MAX_FIELD_CHARS'], 'FIELD' => '<input type="text" name="field_maxlen" size="5" value="' . $this->vars['field_maxlen'] . '" />'),
+ 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input type="number" min="0" name="field_length" size="5" value="' . $this->vars['field_length'] . '" />'),
+ 1 => array('TITLE' => $user->lang['MIN_FIELD_CHARS'], 'FIELD' => '<input type="number" min="0" name="field_minlen" size="5" value="' . $this->vars['field_minlen'] . '" />'),
+ 2 => array('TITLE' => $user->lang['MAX_FIELD_CHARS'], 'FIELD' => '<input type="number" min="0" size="5" value="' . $this->vars['field_maxlen'] . '" />'),
3 => array('TITLE' => $user->lang['FIELD_VALIDATION'], 'FIELD' => '<select name="field_validation">' . $this->validate_options() . '</select>')
);
@@ -1057,9 +1057,9 @@ class custom_profile_admin extends custom_profile
global $user;
$options = array(
- 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input name="rows" size="5" value="' . $this->vars['rows'] . '" /> ' . $user->lang['ROWS'] . '</dd><dd><input name="columns" size="5" value="' . $this->vars['columns'] . '" /> ' . $user->lang['COLUMNS'] . ' <input type="hidden" name="field_length" value="' . $this->vars['field_length'] . '" />'),
- 1 => array('TITLE' => $user->lang['MIN_FIELD_CHARS'], 'FIELD' => '<input type="text" name="field_minlen" size="10" value="' . $this->vars['field_minlen'] . '" />'),
- 2 => array('TITLE' => $user->lang['MAX_FIELD_CHARS'], 'FIELD' => '<input type="text" name="field_maxlen" size="10" value="' . $this->vars['field_maxlen'] . '" />'),
+ 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input type="number" min="0" max="99999" name="rows" size="5" value="' . $this->vars['rows'] . '" /> ' . $user->lang['ROWS'] . '</dd><dd><input type="number" min="0" max="99999" name="columns" size="5" value="' . $this->vars['columns'] . '" /> ' . $user->lang['COLUMNS'] . ' <input type="hidden" name="field_length" value="' . $this->vars['field_length'] . '" />'),
+ 1 => array('TITLE' => $user->lang['MIN_FIELD_CHARS'], 'FIELD' => '<input type="number" min="0" max="9999999999" name="field_minlen" size="10" value="' . $this->vars['field_minlen'] . '" />'),
+ 2 => array('TITLE' => $user->lang['MAX_FIELD_CHARS'], 'FIELD' => '<input type="number" min="0" max="9999999999" name="field_maxlen" size="10" value="' . $this->vars['field_maxlen'] . '" />'),
3 => array('TITLE' => $user->lang['FIELD_VALIDATION'], 'FIELD' => '<select name="field_validation">' . $this->validate_options() . '</select>')
);
@@ -1074,9 +1074,9 @@ class custom_profile_admin extends custom_profile
global $user;
$options = array(
- 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input type="text" name="field_length" size="5" value="' . $this->vars['field_length'] . '" />'),
- 1 => array('TITLE' => $user->lang['MIN_FIELD_NUMBER'], 'FIELD' => '<input type="text" name="field_minlen" size="5" value="' . $this->vars['field_minlen'] . '" />'),
- 2 => array('TITLE' => $user->lang['MAX_FIELD_NUMBER'], 'FIELD' => '<input type="text" name="field_maxlen" size="5" value="' . $this->vars['field_maxlen'] . '" />'),
+ 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input type="number" min="0" max="99999" name="field_length" size="5" value="' . $this->vars['field_length'] . '" />'),
+ 1 => array('TITLE' => $user->lang['MIN_FIELD_NUMBER'], 'FIELD' => '<input type="number" min="0" max="99999" name="field_minlen" size="5" value="' . $this->vars['field_minlen'] . '" />'),
+ 2 => array('TITLE' => $user->lang['MAX_FIELD_NUMBER'], 'FIELD' => '<input type="number" min="0" max="99999" name="field_maxlen" size="5" value="' . $this->vars['field_maxlen'] . '" />'),
3 => array('TITLE' => $user->lang['DEFAULT_VALUE'], 'FIELD' => '<input type="post" name="field_default_value" value="' . $this->vars['field_default_value'] . '" />')
);
diff --git a/phpBB/includes/functions_upload.php b/phpBB/includes/functions_upload.php
index b467aa93d1..4f31a85e83 100644
--- a/phpBB/includes/functions_upload.php
+++ b/phpBB/includes/functions_upload.php
@@ -70,7 +70,7 @@ class filespec
$this->mimetype = 'application/octetstream';
}
- $this->extension = strtolower($this->get_extension($this->realname));
+ $this->extension = strtolower(self::get_extension($this->realname));
// Try to get real filesize from temporary folder (not always working) ;)
$this->filesize = (@filesize($this->filename)) ? @filesize($this->filename) : $this->filesize;
@@ -187,8 +187,11 @@ class filespec
/**
* Get file extension
+ *
+ * @param string Filename that needs to be checked
+ * @return string Extension of the supplied filename
*/
- function get_extension($filename)
+ static public function get_extension($filename)
{
if (strpos($filename, '.') === false)
{
@@ -369,7 +372,7 @@ class filespec
}
// Check image type
- $types = $this->upload->image_types();
+ $types = fileupload::image_types();
if (!isset($types[$this->image_info[2]]) || !in_array($this->extension, $types[$this->image_info[2]]))
{
@@ -1019,9 +1022,11 @@ class fileupload
}
/**
- * Return image type/extension mapping
+ * Get image type/extension mapping
+ *
+ * @return array Array containing the image types and their extensions
*/
- function image_types()
+ static public function image_types()
{
return array(
IMAGETYPE_GIF => array('gif'),
diff --git a/phpBB/includes/functions_url_matcher.php b/phpBB/includes/functions_url_matcher.php
index 7280cb74eb..a89ab7b126 100644
--- a/phpBB/includes/functions_url_matcher.php
+++ b/phpBB/includes/functions_url_matcher.php
@@ -60,7 +60,7 @@ function phpbb_create_dumped_url_matcher(phpbb_extension_finder $finder, $root_p
'class' => 'phpbb_url_matcher',
));
- file_put_contents($root_path . 'cache/url_matcher' . $php_ext, $cached_url_matcher_dump);
+ file_put_contents($root_path . 'cache/url_matcher.' . $php_ext, $cached_url_matcher_dump);
}
/**
@@ -87,7 +87,7 @@ function phpbb_create_url_matcher(phpbb_extension_finder $finder, RequestContext
*/
function phpbb_load_url_matcher(RequestContext $context, $root_path, $php_ext)
{
- require($root_path . 'cache/url_matcher' . $php_ext);
+ require($root_path . 'cache/url_matcher.' . $php_ext);
return new phpbb_url_matcher($context);
}
@@ -102,5 +102,5 @@ function phpbb_load_url_matcher(RequestContext $context, $root_path, $php_ext)
*/
function phpbb_url_matcher_dumped($root_path, $php_ext)
{
- return file_exists($root_path . 'cache/url_matcher' . $php_ext);
+ return file_exists($root_path . 'cache/url_matcher.' . $php_ext);
}
diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php
index aeb9c8dd5c..5504a8cd5c 100644
--- a/phpBB/includes/functions_user.php
+++ b/phpBB/includes/functions_user.php
@@ -310,8 +310,10 @@ function user_add($user_row, $cp_data = false)
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;
+ global $phpbb_log;
+
+ // Because these actions only fill the log unneccessarily we skip the add_log() entry.
+ $phpbb_log->disable('admin');
// Add user to "newly registered users" group and set to default group if admin specified so.
if ($config['new_member_group_default'])
@@ -324,7 +326,7 @@ function user_add($user_row, $cp_data = false)
group_user_add($add_group_id, $user_id);
}
- unset($GLOBALS['skip_add_log']);
+ $phpbb_log->enable('admin');
}
}
@@ -1328,22 +1330,12 @@ function validate_data($data, $val_ary)
{
$function = array_shift($validate);
array_unshift($validate, $data[$var]);
+ $function_prefix = (function_exists('phpbb_validate_' . $function)) ? 'phpbb_validate_' : 'validate_';
- if (function_exists('phpbb_validate_' . $function))
+ if ($result = call_user_func_array($function_prefix . $function, $validate))
{
- if ($result = call_user_func_array('phpbb_validate_' . $function, $validate))
- {
- // Since errors are checked later for their language file existence, we need to make sure custom errors are not adjusted.
- $error[] = (empty($user->lang[$result . '_' . strtoupper($var)])) ? $result : $result . '_' . strtoupper($var);
- }
- }
- else
- {
- if ($result = call_user_func_array('validate_' . $function, $validate))
- {
- // Since errors are checked later for their language file existence, we need to make sure custom errors are not adjusted.
- $error[] = (empty($user->lang[$result . '_' . strtoupper($var)])) ? $result : $result . '_' . strtoupper($var);
- }
+ // Since errors are checked later for their language file existence, we need to make sure custom errors are not adjusted.
+ $error[] = (empty($user->lang[$result . '_' . strtoupper($var)])) ? $result : $result . '_' . strtoupper($var);
}
}
}
@@ -1661,7 +1653,7 @@ function validate_username($username, $allowed_username = false)
*/
function validate_password($password)
{
- global $config, $db, $user;
+ global $config;
if ($password === '' || $config['pass_complex'] === 'PASS_TYPE_ANY')
{
@@ -2007,6 +1999,30 @@ function validate_jabber($jid)
}
/**
+* Validate hex colour value
+*
+* @param string $colour The hex colour value
+* @param bool $optional Whether the colour value is optional. True if an empty
+* string will be accepted as correct input, false if not.
+* @return bool|string Error message if colour value is incorrect, false if it
+* fits the hex colour code
+*/
+function phpbb_validate_hex_colour($colour, $optional = false)
+{
+ if ($colour === '')
+ {
+ return (($optional) ? false : 'WRONG_DATA');
+ }
+
+ if (!preg_match('/^([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/', $colour))
+ {
+ return 'WRONG_DATA';
+ }
+
+ return false;
+}
+
+/**
* Verifies whether a style ID corresponds to an active style.
*
* @param int $style_id The style_id of a style which should be checked if activated or not.
@@ -2048,6 +2064,7 @@ function avatar_delete($mode, $row, $clean_db = false)
avatar_remove_db($row[$mode . '_avatar']);
}
$filename = get_avatar_filename($row[$mode . '_avatar']);
+
if (file_exists($phpbb_root_path . $config['avatar_path'] . '/' . $filename))
{
@unlink($phpbb_root_path . $config['avatar_path'] . '/' . $filename);
@@ -2058,134 +2075,6 @@ function avatar_delete($mode, $row, $clean_db = false)
}
/**
-* Remote avatar linkage
-*/
-function avatar_remote($data, &$error)
-{
- global $config, $db, $user, $phpbb_root_path, $phpEx;
-
- if (!preg_match('#^(http|https|ftp)://#i', $data['remotelink']))
- {
- $data['remotelink'] = 'http://' . $data['remotelink'];
- }
- if (!preg_match('#^(http|https|ftp)://(?:(.*?\.)*?[a-z0-9\-]+?\.[a-z]{2,4}|(?:\d{1,3}\.){3,5}\d{1,3}):?([0-9]*?).*?\.(gif|jpg|jpeg|png)$#i', $data['remotelink']))
- {
- $error[] = $user->lang['AVATAR_URL_INVALID'];
- return false;
- }
-
- // Make sure getimagesize works...
- if (($image_data = @getimagesize($data['remotelink'])) === false && (empty($data['width']) || empty($data['height'])))
- {
- $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
- return false;
- }
-
- if (!empty($image_data) && ($image_data[0] < 2 || $image_data[1] < 2))
- {
- $error[] = $user->lang['AVATAR_NO_SIZE'];
- return false;
- }
-
- $width = ($data['width'] && $data['height']) ? $data['width'] : $image_data[0];
- $height = ($data['width'] && $data['height']) ? $data['height'] : $image_data[1];
-
- if ($width < 2 || $height < 2)
- {
- $error[] = $user->lang['AVATAR_NO_SIZE'];
- return false;
- }
-
- // Check image type
- include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx);
- $types = fileupload::image_types();
- $extension = strtolower(filespec::get_extension($data['remotelink']));
-
- if (!empty($image_data) && (!isset($types[$image_data[2]]) || !in_array($extension, $types[$image_data[2]])))
- {
- if (!isset($types[$image_data[2]]))
- {
- $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
- }
- else
- {
- $error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$image_data[2]][0], $extension);
- }
- return false;
- }
-
- if ($config['avatar_max_width'] || $config['avatar_max_height'])
- {
- if ($width > $config['avatar_max_width'] || $height > $config['avatar_max_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($width, $height);
- return false;
- }
- }
-
- if ($config['avatar_min_width'] || $config['avatar_min_height'])
- {
- if ($width < $config['avatar_min_width'] || $height < $config['avatar_min_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($width, $height);
- return false;
- }
- }
-
- return array(AVATAR_REMOTE, $data['remotelink'], $width, $height);
-}
-
-/**
-* Avatar upload using the upload class
-*/
-function avatar_upload($data, &$error)
-{
- global $phpbb_root_path, $config, $db, $user, $phpEx, $request;
-
- // Init upload class
- include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx);
- $upload = new fileupload('AVATAR_', array('jpg', 'jpeg', 'gif', 'png'), $config['avatar_filesize'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], (isset($config['mime_triggers']) ? explode('|', $config['mime_triggers']) : false));
-
- $uploadfile = $request->file('uploadfile');
- if (!empty($uploadfile['name']))
- {
- $file = $upload->form_upload('uploadfile');
- }
- else
- {
- $file = $upload->remote_upload($data['uploadurl']);
- }
-
- $prefix = $config['avatar_salt'] . '_';
- $file->clean_filename('avatar', $prefix, $data['user_id']);
-
- $destination = $config['avatar_path'];
-
- // Adjust destination path (no trailing slash)
- if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\')
- {
- $destination = substr($destination, 0, -1);
- }
-
- $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination);
- if ($destination && ($destination[0] == '/' || $destination[0] == "\\"))
- {
- $destination = '';
- }
-
- // Move file and overwrite any existing image
- $file->move_file($destination, true);
-
- if (sizeof($file->error))
- {
- $file->remove();
- $error = array_merge($error, $file->error);
- }
-
- return array(AVATAR_UPLOAD, $data['user_id'] . '_' . time() . '.' . $file->get('extension'), $file->get('width'), $file->get('height'));
-}
-
-/**
* Generates avatar filename from the database entry
*/
function get_avatar_filename($avatar_entry)
@@ -2208,344 +2097,6 @@ function get_avatar_filename($avatar_entry)
}
/**
-* Avatar Gallery
-*/
-function avatar_gallery($category, $avatar_select, $items_per_column, $block_var = 'avatar_row')
-{
- global $user, $cache, $template;
- global $config, $phpbb_root_path;
-
- $avatar_list = array();
-
- $path = $phpbb_root_path . $config['avatar_gallery_path'];
-
- if (!file_exists($path) || !is_dir($path))
- {
- $avatar_list = array($user->lang['NO_AVATAR_CATEGORY'] => array());
- }
- else
- {
- // Collect images
- $dp = @opendir($path);
-
- if (!$dp)
- {
- return array($user->lang['NO_AVATAR_CATEGORY'] => array());
- }
-
- while (($file = readdir($dp)) !== false)
- {
- if ($file[0] != '.' && preg_match('#^[^&"\'<>]+$#i', $file) && is_dir("$path/$file"))
- {
- $avatar_row_count = $avatar_col_count = 0;
-
- if ($dp2 = @opendir("$path/$file"))
- {
- while (($sub_file = readdir($dp2)) !== false)
- {
- if (preg_match('#^[^&\'"<>]+\.(?:gif|png|jpe?g)$#i', $sub_file))
- {
- $avatar_list[$file][$avatar_row_count][$avatar_col_count] = array(
- 'file' => rawurlencode($file) . '/' . rawurlencode($sub_file),
- 'filename' => rawurlencode($sub_file),
- 'name' => ucfirst(str_replace('_', ' ', preg_replace('#^(.*)\..*$#', '\1', $sub_file))),
- );
- $avatar_col_count++;
- if ($avatar_col_count == $items_per_column)
- {
- $avatar_row_count++;
- $avatar_col_count = 0;
- }
- }
- }
- closedir($dp2);
- }
- }
- }
- closedir($dp);
- }
-
- if (!sizeof($avatar_list))
- {
- $avatar_list = array($user->lang['NO_AVATAR_CATEGORY'] => array());
- }
-
- @ksort($avatar_list);
-
- $category = (!$category) ? key($avatar_list) : $category;
- $avatar_categories = array_keys($avatar_list);
-
- $s_category_options = '';
- foreach ($avatar_categories as $cat)
- {
- $s_category_options .= '<option value="' . $cat . '"' . (($cat == $category) ? ' selected="selected"' : '') . '>' . $cat . '</option>';
- }
-
- $template->assign_vars(array(
- 'S_AVATARS_ENABLED' => true,
- 'S_IN_AVATAR_GALLERY' => true,
- 'S_CAT_OPTIONS' => $s_category_options)
- );
-
- $avatar_list = (isset($avatar_list[$category])) ? $avatar_list[$category] : array();
-
- foreach ($avatar_list as $avatar_row_ary)
- {
- $template->assign_block_vars($block_var, array());
-
- foreach ($avatar_row_ary as $avatar_col_ary)
- {
- $template->assign_block_vars($block_var . '.avatar_column', array(
- 'AVATAR_IMAGE' => $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar_col_ary['file'],
- 'AVATAR_NAME' => $avatar_col_ary['name'],
- 'AVATAR_FILE' => $avatar_col_ary['filename'])
- );
-
- $template->assign_block_vars($block_var . '.avatar_option_column', array(
- 'AVATAR_IMAGE' => $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar_col_ary['file'],
- 'S_OPTIONS_AVATAR' => $avatar_col_ary['filename'])
- );
- }
- }
-
- return $avatar_list;
-}
-
-
-/**
-* Tries to (re-)establish avatar dimensions
-*/
-function avatar_get_dimensions($avatar, $avatar_type, &$error, $current_x = 0, $current_y = 0)
-{
- global $config, $phpbb_root_path, $user;
-
- switch ($avatar_type)
- {
- case AVATAR_REMOTE :
- break;
-
- case AVATAR_UPLOAD :
- $avatar = $phpbb_root_path . $config['avatar_path'] . '/' . get_avatar_filename($avatar);
- break;
-
- case AVATAR_GALLERY :
- $avatar = $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar ;
- break;
- }
-
- // Make sure getimagesize works...
- if (($image_data = @getimagesize($avatar)) === false)
- {
- $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
- return false;
- }
-
- if ($image_data[0] < 2 || $image_data[1] < 2)
- {
- $error[] = $user->lang['AVATAR_NO_SIZE'];
- return false;
- }
-
- // try to maintain ratio
- if (!(empty($current_x) && empty($current_y)))
- {
- if ($current_x != 0)
- {
- $image_data[1] = (int) floor(($current_x / $image_data[0]) * $image_data[1]);
- $image_data[1] = min($config['avatar_max_height'], $image_data[1]);
- $image_data[1] = max($config['avatar_min_height'], $image_data[1]);
- }
- if ($current_y != 0)
- {
- $image_data[0] = (int) floor(($current_y / $image_data[1]) * $image_data[0]);
- $image_data[0] = min($config['avatar_max_width'], $image_data[1]);
- $image_data[0] = max($config['avatar_min_width'], $image_data[1]);
- }
- }
- return array($image_data[0], $image_data[1]);
-}
-
-/**
-* Uploading/Changing user avatar
-*/
-function avatar_process_user(&$error, $custom_userdata = false, $can_upload = null)
-{
- global $config, $phpbb_root_path, $auth, $user, $db, $request;
-
- $data = array(
- 'uploadurl' => request_var('uploadurl', ''),
- 'remotelink' => request_var('remotelink', ''),
- 'width' => request_var('width', 0),
- 'height' => request_var('height', 0),
- );
-
- $error = validate_data($data, array(
- 'uploadurl' => array('string', true, 5, 255),
- 'remotelink' => array('string', true, 5, 255),
- 'width' => array('string', true, 1, 3),
- 'height' => array('string', true, 1, 3),
- ));
-
- if (sizeof($error))
- {
- return false;
- }
-
- $sql_ary = array();
-
- if ($custom_userdata === false)
- {
- $userdata = &$user->data;
- }
- else
- {
- $userdata = &$custom_userdata;
- }
-
- $data['user_id'] = $userdata['user_id'];
- $change_avatar = ($custom_userdata === false) ? $auth->acl_get('u_chgavatar') : true;
- $avatar_select = basename(request_var('avatar_select', ''));
-
- // Can we upload?
- if (is_null($can_upload))
- {
- $can_upload = ($config['allow_avatar_upload'] && file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $change_avatar && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false;
- }
-
- $uploadfile = $request->file('uploadfile');
- if ((!empty($uploadfile['name']) || $data['uploadurl']) && $can_upload)
- {
- list($sql_ary['user_avatar_type'], $sql_ary['user_avatar'], $sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = avatar_upload($data, $error);
- }
- else if ($data['remotelink'] && $change_avatar && $config['allow_avatar_remote'])
- {
- list($sql_ary['user_avatar_type'], $sql_ary['user_avatar'], $sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = avatar_remote($data, $error);
- }
- else if ($avatar_select && $change_avatar && $config['allow_avatar_local'])
- {
- $category = basename(request_var('category', ''));
-
- $sql_ary['user_avatar_type'] = AVATAR_GALLERY;
- $sql_ary['user_avatar'] = $avatar_select;
-
- // check avatar gallery
- if (!is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category))
- {
- $sql_ary['user_avatar'] = '';
- $sql_ary['user_avatar_type'] = $sql_ary['user_avatar_width'] = $sql_ary['user_avatar_height'] = 0;
- }
- else
- {
- list($sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . urldecode($sql_ary['user_avatar']));
- $sql_ary['user_avatar'] = $category . '/' . $sql_ary['user_avatar'];
- }
- }
- else if (isset($_POST['delete']) && $change_avatar)
- {
- $sql_ary['user_avatar'] = '';
- $sql_ary['user_avatar_type'] = $sql_ary['user_avatar_width'] = $sql_ary['user_avatar_height'] = 0;
- }
- else if (!empty($userdata['user_avatar']))
- {
- // Only update the dimensions
-
- if (empty($data['width']) || empty($data['height']))
- {
- if ($dims = avatar_get_dimensions($userdata['user_avatar'], $userdata['user_avatar_type'], $error, $data['width'], $data['height']))
- {
- list($guessed_x, $guessed_y) = $dims;
- if (empty($data['width']))
- {
- $data['width'] = $guessed_x;
- }
- if (empty($data['height']))
- {
- $data['height'] = $guessed_y;
- }
- }
- }
- if (($config['avatar_max_width'] || $config['avatar_max_height']) &&
- (($data['width'] != $userdata['user_avatar_width']) || $data['height'] != $userdata['user_avatar_height']))
- {
- if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
- }
- }
-
- if (!sizeof($error))
- {
- if ($config['avatar_min_width'] || $config['avatar_min_height'])
- {
- if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
- }
- }
- }
-
- if (!sizeof($error))
- {
- $sql_ary['user_avatar_width'] = $data['width'];
- $sql_ary['user_avatar_height'] = $data['height'];
- }
- }
-
- if (!sizeof($error))
- {
- // Do we actually have any data to update?
- if (sizeof($sql_ary))
- {
- $ext_new = $ext_old = '';
- if (isset($sql_ary['user_avatar']))
- {
- $userdata = ($custom_userdata === false) ? $user->data : $custom_userdata;
- $ext_new = (empty($sql_ary['user_avatar'])) ? '' : substr(strrchr($sql_ary['user_avatar'], '.'), 1);
- $ext_old = (empty($userdata['user_avatar'])) ? '' : substr(strrchr($userdata['user_avatar'], '.'), 1);
-
- if ($userdata['user_avatar_type'] == AVATAR_UPLOAD)
- {
- // Delete old avatar if present
- if ((!empty($userdata['user_avatar']) && empty($sql_ary['user_avatar']))
- || ( !empty($userdata['user_avatar']) && !empty($sql_ary['user_avatar']) && $ext_new !== $ext_old))
- {
- avatar_delete('user', $userdata);
- }
- }
- }
-
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
- WHERE user_id = ' . (($custom_userdata === false) ? $user->data['user_id'] : $custom_userdata['user_id']);
- $db->sql_query($sql);
-
- }
- }
-
- return (sizeof($error)) ? false : true;
-}
-
-/**
-* Returns a language string with the avatar size of the new avatar and the allowed maximum and minimum
-*
-* @param $width int The width of the new uploaded/selected avatar
-* @param $height int The height of the new uploaded/selected avatar
-* @return string
-*/
-function phpbb_avatar_error_wrong_size($width, $height)
-{
- global $config, $user;
-
- return $user->lang('AVATAR_WRONG_SIZE',
- $user->lang('PIXELS', (int) $config['avatar_min_width']),
- $user->lang('PIXELS', (int) $config['avatar_min_height']),
- $user->lang('PIXELS', (int) $config['avatar_max_width']),
- $user->lang('PIXELS', (int) $config['avatar_max_height']),
- $user->lang('PIXELS', (int) $width),
- $user->lang('PIXELS', (int) $height));
-}
-
-/**
* Returns an explanation string with maximum avatar settings
*
* @return string
@@ -2570,7 +2121,7 @@ function phpbb_avatar_explanation_string()
*/
function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow_desc_bbcode = false, $allow_desc_urls = false, $allow_desc_smilies = false)
{
- global $phpbb_root_path, $config, $db, $user, $file_upload;
+ global $phpbb_root_path, $config, $db, $user, $file_upload, $phpbb_container;
$error = array();
@@ -2594,22 +2145,32 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
$error[] = $user->lang['GROUP_ERR_TYPE'];
}
+ $group_teampage = !empty($group_attributes['group_teampage']);
+ unset($group_attributes['group_teampage']);
+
if (!sizeof($error))
{
- $current_legend = phpbb_group_positions::GROUP_DISABLED;
- $current_teampage = phpbb_group_positions::GROUP_DISABLED;
+ $current_legend = phpbb_groupposition_legend::GROUP_DISABLED;
+ $current_teampage = phpbb_groupposition_teampage::GROUP_DISABLED;
- $legend = new phpbb_group_positions($db, 'legend');
- $teampage = new phpbb_group_positions($db, 'teampage');
+ $legend = $phpbb_container->get('groupposition.legend');
+ $teampage = $phpbb_container->get('groupposition.teampage');
if ($group_id)
{
- $current_legend = $legend->get_group_value($group_id);
- $current_teampage = $teampage->get_group_value($group_id);
+ try
+ {
+ $current_legend = $legend->get_group_value($group_id);
+ $current_teampage = $teampage->get_group_value($group_id);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()));
+ }
}
if (!empty($group_attributes['group_legend']))
{
- if (($group_id && ($current_legend == phpbb_group_positions::GROUP_DISABLED)) || !$group_id)
+ if (($group_id && ($current_legend == phpbb_groupposition_legend::GROUP_DISABLED)) || !$group_id)
{
// Old group currently not in the legend or new group, add at the end.
$group_attributes['group_legend'] = 1 + $legend->get_group_count();
@@ -2620,44 +2181,26 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
$group_attributes['group_legend'] = $current_legend;
}
}
- else if ($group_id && ($current_legend > phpbb_group_positions::GROUP_DISABLED))
+ else if ($group_id && ($current_legend != phpbb_groupposition_legend::GROUP_DISABLED))
{
// Group is removed from the legend
- $legend->delete_group($group_id, true);
- $group_attributes['group_legend'] = phpbb_group_positions::GROUP_DISABLED;
- }
- else
- {
- $group_attributes['group_legend'] = phpbb_group_positions::GROUP_DISABLED;
- }
-
- if (!empty($group_attributes['group_teampage']))
- {
- if (($group_id && ($current_teampage == phpbb_group_positions::GROUP_DISABLED)) || !$group_id)
+ try
{
- // Old group currently not on the teampage or new group, add at the end.
- $group_attributes['group_teampage'] = 1 + $teampage->get_group_count();
+ $legend->delete_group($group_id, true);
}
- else
+ catch (phpbb_groupposition_exception $exception)
{
- // Group stayes on the teampage
- $group_attributes['group_teampage'] = $current_teampage;
+ trigger_error($user->lang($exception->getMessage()));
}
- }
- else if ($group_id && ($current_teampage > phpbb_group_positions::GROUP_DISABLED))
- {
- // Group is removed from the teampage
- $teampage->delete_group($group_id, true);
- $group_attributes['group_teampage'] = phpbb_group_positions::GROUP_DISABLED;
+ $group_attributes['group_legend'] = phpbb_groupposition_legend::GROUP_DISABLED;
}
else
{
- $group_attributes['group_teampage'] = phpbb_group_positions::GROUP_DISABLED;
+ $group_attributes['group_legend'] = phpbb_groupposition_legend::GROUP_DISABLED;
}
// Unset the objects, we don't need them anymore.
unset($legend);
- unset($teampage);
$user_ary = array();
$sql_ary = array(
@@ -2698,12 +2241,12 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
}
$db->sql_freeresult($result);
- if (isset($sql_ary['group_avatar']) && !$sql_ary['group_avatar'])
+ if (isset($sql_ary['group_avatar']))
{
remove_default_avatar($group_id, $user_ary);
}
- if (isset($sql_ary['group_rank']) && !$sql_ary['group_rank'])
+ if (isset($sql_ary['group_rank']))
{
remove_default_rank($group_id, $user_ary);
}
@@ -2751,6 +2294,20 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
$db->sql_query($sql);
}
+ // Remove the group from the teampage, only if unselected and we are editing a group,
+ // which is currently displayed.
+ if (!$group_teampage && $group_id && $current_teampage != phpbb_groupposition_teampage::GROUP_DISABLED)
+ {
+ try
+ {
+ $teampage->delete_group($group_id);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()));
+ }
+ }
+
if (!$group_id)
{
$group_id = $db->sql_nextid();
@@ -2761,6 +2318,31 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
}
}
+ try
+ {
+ if ($group_teampage && $current_teampage == phpbb_groupposition_teampage::GROUP_DISABLED)
+ {
+ $teampage->add_group($group_id);
+ }
+
+ if ($group_teampage)
+ {
+ if ($current_teampage == phpbb_groupposition_teampage::GROUP_DISABLED)
+ {
+ $teampage->add_group($group_id);
+ }
+ }
+ else if ($group_id && ($current_teampage != phpbb_groupposition_teampage::GROUP_DISABLED))
+ {
+ $teampage->delete_group($group_id);
+ }
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()));
+ }
+ unset($teampage);
+
// Set user attributes
$sql_ary = array();
if (sizeof($group_attributes))
@@ -2842,7 +2424,7 @@ function avatar_remove_db($avatar_name)
*/
function group_delete($group_id, $group_name = false)
{
- global $db, $phpbb_root_path, $phpEx, $phpbb_dispatcher;
+ global $db, $cache, $auth, $user, $phpbb_root_path, $phpEx, $phpbb_dispatcher, $phpbb_container;
if (!$group_name)
{
@@ -2884,12 +2466,31 @@ function group_delete($group_id, $group_name = false)
while ($start);
// Delete group from legend and teampage
- $legend = new phpbb_group_positions($db, 'legend');
- $legend->delete_group($group_id);
- unset($legend);
- $teampage = new phpbb_group_positions($db, 'teampage');
- $teampage->delete_group($group_id);
- unset($teampage);
+ try
+ {
+ $legend = $phpbb_container->get('groupposition.legend');
+ $legend->delete_group($group_id);
+ unset($legend);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ // The group we want to delete does not exist.
+ // No reason to worry, we just continue the deleting process.
+ //trigger_error($user->lang($exception->getMessage()));
+ }
+
+ try
+ {
+ $teampage = $phpbb_container->get('groupposition.teampage');
+ $teampage->delete_group($group_id);
+ unset($teampage);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ // The group we want to delete does not exist.
+ // No reason to worry, we just continue the deleting process.
+ //trigger_error($user->lang($exception->getMessage()));
+ }
// Delete group
$sql = 'DELETE FROM ' . GROUPS_TABLE . "
@@ -2913,12 +2514,12 @@ function group_delete($group_id, $group_name = false)
extract($phpbb_dispatcher->trigger_event('core.delete_group_after', compact($vars)));
// Re-cache moderators
- if (!function_exists('cache_moderators'))
+ if (!function_exists('phpbb_cache_moderators'))
{
include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
}
- cache_moderators();
+ phpbb_cache_moderators($db, $cache, $auth);
add_log('admin', 'LOG_GROUP_DELETE', $group_name);
@@ -3208,8 +2809,8 @@ function remove_default_avatar($group_id, $user_ids)
user_avatar_width = 0,
user_avatar_height = 0
WHERE group_id = " . (int) $group_id . "
- AND user_avatar = '" . $db->sql_escape($row['group_avatar']) . "'
- AND " . $db->sql_in_set('user_id', $user_ids);
+ AND user_avatar = '" . $db->sql_escape($row['group_avatar']) . "'
+ AND " . $db->sql_in_set('user_id', $user_ids);
$db->sql_query($sql);
}
@@ -3246,9 +2847,9 @@ function remove_default_rank($group_id, $user_ids)
$sql = 'UPDATE ' . USERS_TABLE . '
SET user_rank = 0
WHERE group_id = ' . (int)$group_id . '
- AND user_rank <> 0
- AND user_rank = ' . (int)$row['group_rank'] . '
- AND ' . $db->sql_in_set('user_id', $user_ids);
+ AND user_rank <> 0
+ AND user_rank = ' . (int)$row['group_rank'] . '
+ AND ' . $db->sql_in_set('user_id', $user_ids);
$db->sql_query($sql);
}
@@ -3277,7 +2878,8 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna
case 'demote':
case 'promote':
- $sql = 'SELECT user_id FROM ' . USER_GROUP_TABLE . "
+ $sql = 'SELECT user_id
+ FROM ' . USER_GROUP_TABLE . "
WHERE group_id = $group_id
AND user_pending = 1
AND " . $db->sql_in_set('user_id', $user_id_ary);
@@ -3336,8 +2938,7 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna
{
$messenger->template('group_approved', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($row['username']),
@@ -3375,7 +2976,8 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna
return 'NO_USERS';
}
- $sql = 'SELECT user_id, group_id FROM ' . USERS_TABLE . '
+ $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);
@@ -3463,7 +3065,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 $cache, $db, $phpbb_dispatcher;
+ global $phpbb_container, $db, $phpbb_dispatcher;
if (empty($user_id_ary))
{
@@ -3509,45 +3111,69 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal
}
}
- // Before we update the user attributes, we will make a list of those having now the group avatar assigned
- if (isset($sql_ary['user_avatar']))
+ $updated_sql_ary = $sql_ary;
+
+ // Before we update the user attributes, we will update the rank for users that don't have a custom rank
+ if (isset($sql_ary['user_rank']))
{
- // Ok, get the original avatar data from users having an uploaded one (we need to remove these from the filesystem)
- $sql = 'SELECT user_id, group_id, user_avatar
- FROM ' . USERS_TABLE . '
- WHERE ' . $db->sql_in_set('user_id', $user_id_ary) . '
- AND user_avatar_type = ' . AVATAR_UPLOAD;
- $result = $db->sql_query($sql);
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', array('user_rank' => $sql_ary['user_rank'])) . '
+ WHERE user_rank = 0
+ AND ' . $db->sql_in_set('user_id', $user_id_ary);
+ $db->sql_query($sql);
+ unset($sql_ary['user_rank']);
+ }
- while ($row = $db->sql_fetchrow($result))
+ // Before we update the user attributes, we will update the avatar for users that don't have a custom avatar
+ $avatar_options = array('user_avatar', 'user_avatar_type', 'user_avatar_height', 'user_avatar_width');
+
+ if (isset($sql_ary['user_avatar']))
+ {
+ $avatar_sql_ary = array();
+ foreach ($avatar_options as $avatar_option)
{
- avatar_delete('user', $row);
- }
- $db->sql_freeresult($result);
+ if (isset($sql_ary[$avatar_option]))
+ {
+ $avatar_sql_ary[$avatar_option] = $sql_ary[$avatar_option];
+ }
+ }
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $avatar_sql_ary) . "
+ WHERE user_avatar = ''
+ AND " . $db->sql_in_set('user_id', $user_id_ary);
+ $db->sql_query($sql);
}
- else
+
+ // Remove the avatar options, as we already updated them
+ foreach ($avatar_options as $avatar_option)
{
- unset($sql_ary['user_avatar_type']);
- unset($sql_ary['user_avatar_height']);
- unset($sql_ary['user_avatar_width']);
+ unset($sql_ary[$avatar_option]);
}
- $sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
- WHERE ' . $db->sql_in_set('user_id', $user_id_ary);
- $db->sql_query($sql);
+ if (!empty($sql_ary))
+ {
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
+ WHERE ' . $db->sql_in_set('user_id', $user_id_ary);
+ $db->sql_query($sql);
+ }
if (isset($sql_ary['user_colour']))
{
// Update any cached colour information for these users
- $sql = 'UPDATE ' . FORUMS_TABLE . " SET forum_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "'
+ $sql = 'UPDATE ' . FORUMS_TABLE . "
+ SET forum_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "'
WHERE " . $db->sql_in_set('forum_last_poster_id', $user_id_ary);
$db->sql_query($sql);
- $sql = 'UPDATE ' . TOPICS_TABLE . " SET topic_first_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "'
+ $sql = 'UPDATE ' . TOPICS_TABLE . "
+ SET topic_first_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "'
WHERE " . $db->sql_in_set('topic_poster', $user_id_ary);
$db->sql_query($sql);
- $sql = 'UPDATE ' . TOPICS_TABLE . " SET topic_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "'
+ $sql = 'UPDATE ' . TOPICS_TABLE . "
+ SET topic_last_poster_colour = '" . $db->sql_escape($sql_ary['user_colour']) . "'
WHERE " . $db->sql_in_set('topic_last_poster_id', $user_id_ary);
$db->sql_query($sql);
@@ -3559,6 +3185,9 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal
}
}
+ // Make all values available for the event
+ $sql_ary = $updated_sql_ary;
+
/**
* Event when the default group is set for an array of users
*
@@ -3579,7 +3208,7 @@ function group_set_user_default($group_id, $user_id_ary, $group_attributes = fal
}
// Because some tables/caches use usercolour-specific data we need to purge this here.
- $cache->destroy('sql', MODERATOR_CACHE_TABLE);
+ $phpbb_container->get('cache.driver')->destroy('sql', MODERATOR_CACHE_TABLE);
}
/**
@@ -3678,7 +3307,7 @@ function group_memberships($group_id_ary = false, $user_id_ary = false, $return_
*/
function group_update_listings($group_id)
{
- global $auth;
+ global $db, $cache, $auth;
$hold_ary = $auth->acl_group_raw_data($group_id, array('a_', 'm_'));
@@ -3720,22 +3349,22 @@ function group_update_listings($group_id)
if ($mod_permissions)
{
- if (!function_exists('cache_moderators'))
+ if (!function_exists('phpbb_cache_moderators'))
{
global $phpbb_root_path, $phpEx;
include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
}
- cache_moderators();
+ phpbb_cache_moderators($db, $cache, $auth);
}
if ($mod_permissions || $admin_permissions)
{
- if (!function_exists('update_foes'))
+ if (!function_exists('phpbb_update_foes'))
{
global $phpbb_root_path, $phpEx;
include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
}
- update_foes(array($group_id));
+ phpbb_update_foes($db, $auth, array($group_id));
}
}
diff --git a/phpBB/includes/group_positions.php b/phpBB/includes/group_positions.php
deleted file mode 100644
index 60352ed97d..0000000000
--- a/phpBB/includes/group_positions.php
+++ /dev/null
@@ -1,261 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Group Position class, containing all functions to manage the groups in the teampage and legend.
-*
-* group_teampage/group_legend is an ascending list 1, 2, ..., n for groups which are displayed. 1 is the first group, n the last.
-* If the value is 0 (self::GROUP_DISABLED) the group is not displayed.
-* @package phpBB3
-*/
-class phpbb_group_positions
-{
- /**
- * Group is not displayed
- */
- const GROUP_DISABLED = 0;
-
- /**
- * phpbb-database object
- */
- public $db = null;
-
- /**
- * Name of the field we want to handle: either 'teampage' or 'legend'
- */
- private $field = '';
-
- /**
- * URI for the adm_back_link when there was an error.
- */
- private $adm_back_link = '';
-
- /**
- * Constructor
- */
- public function __construct ($db, $field, $adm_back_link = '')
- {
- $this->adm_back_link = $adm_back_link;
-
- if (!in_array($field, array('teampage', 'legend')))
- {
- $this->error('NO_MODE');
- }
-
- $this->db = $db;
- $this->field = $field;
- }
-
- /**
- * Returns the group_{$this->field} for a given group, if the group exists.
- * @param int $group_id group_id of the group to be selected
- * @return int position of the group
- */
- public function get_group_value($group_id)
- {
- $sql = 'SELECT group_' . $this->field . '
- FROM ' . GROUPS_TABLE . '
- WHERE group_id = ' . (int) $group_id;
- $result = $this->db->sql_query($sql);
- $current_value = $this->db->sql_fetchfield('group_' . $this->field);
- $this->db->sql_freeresult($result);
-
- if ($current_value === false)
- {
- // Group not found.
- $this->error('NO_GROUP');
- }
-
- return (int) $current_value;
- }
-
- /**
- * Get number of groups, displayed on the teampage/legend
- *
- * @return int value of the last group displayed
- */
- public function get_group_count()
- {
- $sql = 'SELECT group_' . $this->field . '
- FROM ' . GROUPS_TABLE . '
- ORDER BY group_' . $this->field . ' DESC';
- $result = $this->db->sql_query_limit($sql, 1);
- $group_count = (int) $this->db->sql_fetchfield('group_' . $this->field);
- $this->db->sql_freeresult($result);
-
- return $group_count;
- }
-
- /**
- * Addes a group by group_id
- *
- * @param int $group_id group_id of the group to be added
- * @return null
- */
- public function add_group($group_id)
- {
- $current_value = $this->get_group_value($group_id);
-
- if ($current_value == self::GROUP_DISABLED)
- {
- // Group is currently not displayed, add it at the end.
- $next_value = 1 + $this->get_group_count();
-
- $sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = ' . $next_value . '
- WHERE group_' . $this->field . ' = ' . self::GROUP_DISABLED . '
- AND group_id = ' . (int) $group_id;
- $this->db->sql_query($sql);
- }
- }
-
- /**
- * Deletes a group by setting the field to self::GROUP_DISABLED and closing the gap in the list.
- *
- * @param int $group_id group_id of the group to be deleted
- * @param bool $skip_group Skip setting the group to GROUP_DISABLED, to save the query, when you need to update it anyway.
- * @return null
- */
- public function delete_group($group_id, $skip_group = false)
- {
- $current_value = $this->get_group_value($group_id);
-
- if ($current_value != self::GROUP_DISABLED)
- {
- $this->db->sql_transaction('begin');
-
- $sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = group_' . $this->field . ' - 1
- WHERE group_' . $this->field . ' > ' . $current_value;
- $this->db->sql_query($sql);
-
- if (!$skip_group)
- {
- $sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = ' . self::GROUP_DISABLED . '
- WHERE group_id = ' . (int) $group_id;
- $this->db->sql_query($sql);
- }
-
- $this->db->sql_transaction('commit');
- }
- }
-
- /**
- * Moves a group up by group_id
- *
- * @param int $group_id group_id of the group to be moved
- * @return null
- */
- public function move_up($group_id)
- {
- $this->move($group_id, 1);
- }
-
- /**
- * Moves a group down by group_id
- *
- * @param int $group_id group_id of the group to be moved
- * @return null
- */
- public function move_down($group_id)
- {
- $this->move($group_id, -1);
- }
-
- /**
- * Moves a group up/down
- *
- * @param int $group_id group_id of the group to be moved
- * @param int $delta number of steps:
- * - positive = move up
- * - negative = move down
- * @return null
- */
- public function move($group_id, $delta)
- {
- if (!is_int($delta) || !$delta)
- {
- return;
- }
-
- $move_up = ($delta > 0) ? true : false;
- $current_value = $this->get_group_value($group_id);
-
- if ($current_value != self::GROUP_DISABLED)
- {
- $this->db->sql_transaction('begin');
-
- // First we move all groups between our current value and the target value up/down 1,
- // so we have a gap for our group to move.
- $sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = group_' . $this->field . (($move_up) ? ' + 1' : ' - 1') . '
- WHERE group_' . $this->field . ' > ' . self::GROUP_DISABLED . '
- AND group_' . $this->field . (($move_up) ? ' >= ' : ' <= ') . ($current_value - $delta) . '
- AND group_' . $this->field . (($move_up) ? ' < ' : ' > ') . $current_value;
- $this->db->sql_query($sql);
-
- // Because there might be fewer groups above/below the group than we wanted to move,
- // we use the number of changed groups, to update the group.
- $delta = (int) $this->db->sql_affectedrows();
-
- if ($delta)
- {
- // And now finally, when we moved some other groups and built a gap,
- // we can move the desired group to it.
- $sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = group_' . $this->field . (($move_up) ? ' - ' : ' + ') . $delta . '
- WHERE group_id = ' . (int) $group_id;
- $this->db->sql_query($sql);
- }
-
- $this->db->sql_transaction('commit');
- }
- }
-
- /**
- * Get group type language var
- *
- * @param int $group_type group_type from the groups-table
- * @return string name of the language variable for the given group-type.
- */
- static public function group_type_language($group_type)
- {
- switch ($group_type)
- {
- case GROUP_OPEN:
- return 'GROUP_REQUEST';
- case GROUP_CLOSED:
- return 'GROUP_CLOSED';
- case GROUP_HIDDEN:
- return 'GROUP_HIDDEN';
- case GROUP_SPECIAL:
- return 'GROUP_SPECIAL';
- case GROUP_FREE:
- return 'GROUP_OPEN';
- }
- }
-
- /**
- * Error
- */
- public function error($message)
- {
- global $user;
- trigger_error($user->lang[$message] . (($this->adm_back_link) ? adm_back_link($this->adm_back_link) : ''), E_USER_WARNING);
- }
-}
diff --git a/phpBB/includes/json_response.php b/phpBB/includes/json_response.php
deleted file mode 100644
index 5dd904da09..0000000000
--- a/phpBB/includes/json_response.php
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-license.php GNU Public License
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* JSON class
-* @package phpBB3
-*/
-class phpbb_json_response
-{
- /**
- * Send the data to the client and exit the script.
- *
- * @param array $data Any additional data to send.
- * @param bool $exit Will exit the script if true.
- */
- public function send($data, $exit = true)
- {
- header('Content-Type: application/json');
- echo json_encode($data);
-
- if ($exit)
- {
- garbage_collection();
- exit_handler();
- }
- }
-}
diff --git a/phpBB/includes/lock/db.php b/phpBB/includes/lock/db.php
deleted file mode 100644
index 6e94dd5a85..0000000000
--- a/phpBB/includes/lock/db.php
+++ /dev/null
@@ -1,138 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Database locking class
-* @package phpBB3
-*/
-class phpbb_lock_db
-{
- /**
- * Name of the config variable this lock uses
- * @var string
- */
- private $config_name;
-
- /**
- * Unique identifier for this lock.
- *
- * @var string
- */
- private $unique_id;
-
- /**
- * Stores the state of this lock
- * @var bool
- */
- private $locked;
-
- /**
- * The phpBB configuration
- * @var phpbb_config
- */
- private $config;
-
- /**
- * A database connection
- * @var dbal
- */
- private $db;
-
- /**
- * Creates a named released instance of the lock.
- *
- * You have to call acquire() to actually create the lock.
- *
- * @param string $config_name A config variable to be used for locking
- * @param array $config The phpBB configuration
- * @param dbal $db A database connection
- */
- public function __construct($config_name, phpbb_config $config, dbal $db)
- {
- $this->config_name = $config_name;
- $this->config = $config;
- $this->db = $db;
- }
-
- /**
- * Tries to acquire the lock by updating
- * the configuration variable in the database.
- *
- * As a lock may only be held by one process at a time, lock
- * acquisition may fail if another process is holding the lock
- * or if another process obtained the lock but never released it.
- * Locks are forcibly released after a timeout of 1 hour.
- *
- * @return bool true if lock was acquired
- * false otherwise
- */
- public function acquire()
- {
- if ($this->locked)
- {
- return false;
- }
-
- if (!isset($this->config[$this->config_name]))
- {
- $this->config->set($this->config_name, '0', false);
- }
- $lock_value = $this->config[$this->config_name];
-
- // make sure lock cannot be acquired by multiple processes
- if ($lock_value)
- {
- // if the other process is running more than an hour already we have to assume it
- // aborted without cleaning the lock
- $time = explode(' ', $lock_value);
- $time = $time[0];
-
- if ($time + 3600 >= time())
- {
- return false;
- }
- }
-
- $this->unique_id = time() . ' ' . unique_id();
-
- // try to update the config value, if it was already modified by another
- // process we failed to acquire the lock.
- $this->locked = $this->config->set_atomic($this->config_name, $lock_value, $this->unique_id, false);
-
- return $this->locked;
- }
-
- /**
- * Releases the lock.
- *
- * The lock must have been previously obtained, that is, acquire() call
- * was issued and returned true.
- *
- * Note: Attempting to release a lock that is already released,
- * that is, calling release() multiple times, is harmless.
- *
- * @return null
- */
- public function release()
- {
- if ($this->locked)
- {
- $this->config->set_atomic($this->config_name, $this->unique_id, '0', false);
- $this->locked = false;
- }
- }
-}
diff --git a/phpBB/includes/lock/flock.php b/phpBB/includes/lock/flock.php
deleted file mode 100644
index 97bc7dd2b9..0000000000
--- a/phpBB/includes/lock/flock.php
+++ /dev/null
@@ -1,133 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* File locking class
-* @package phpBB3
-*/
-class phpbb_lock_flock
-{
- /**
- * Path to the file to which access is controlled
- *
- * @var string
- */
- private $path;
-
- /**
- * File pointer for the lock file
- * @var string
- */
- private $lock_fp;
-
- /**
- * Constructor.
- *
- * You have to call acquire() to actually acquire the lock.
- *
- * @param string $path Path to the file to which access is controlled
- */
- public function __construct($path)
- {
- $this->path = $path;
- $this->lock_fp = null;
- }
-
- /**
- * Tries to acquire the lock.
- *
- * If the lock is already held by another process, this call will block
- * until the other process releases the lock. If a lock is acquired and
- * is not released before script finishes but the process continues to
- * live (apache/fastcgi) then subsequent processes trying to acquire
- * the same lock will be blocked forever.
- *
- * If the lock is already held by the same process via another instance
- * of this class, this call will block forever.
- *
- * If flock function is disabled in php or fails to work, lock
- * acquisition will fail and false will be returned.
- *
- * @return bool true if lock was acquired
- * false otherwise
- */
- public function acquire()
- {
- if ($this->lock_fp)
- {
- return false;
- }
-
- // For systems that can't have two processes opening
- // one file for writing simultaneously
- if (file_exists($this->path . '.lock'))
- {
- $mode = 'rb';
- }
- else
- {
- $mode = 'wb';
- }
-
- $this->lock_fp = @fopen($this->path . '.lock', $mode);
-
- if ($mode == 'wb')
- {
- if (!$this->lock_fp)
- {
- // Two processes may attempt to create lock file at the same time.
- // Have the losing process try opening the lock file again for reading
- // on the assumption that the winning process created it
- $mode = 'rb';
- $this->lock_fp = @fopen($this->path . '.lock', $mode);
- }
- else
- {
- // Only need to set mode when the lock file is written
- @chmod($this->path . '.lock', 0666);
- }
- }
-
- if ($this->lock_fp)
- {
- @flock($this->lock_fp, LOCK_EX);
- }
-
- return (bool) $this->lock_fp;
- }
-
- /**
- * Releases the lock.
- *
- * The lock must have been previously obtained, that is, acquire() call
- * was issued and returned true.
- *
- * Note: Attempting to release a lock that is already released,
- * that is, calling release() multiple times, is harmless.
- *
- * @return null
- */
- public function release()
- {
- if ($this->lock_fp)
- {
- @flock($this->lock_fp, LOCK_UN);
- fclose($this->lock_fp);
- $this->lock_fp = null;
- }
- }
-}
diff --git a/phpBB/includes/mcp/info/mcp_queue.php b/phpBB/includes/mcp/info/mcp_queue.php
index 7ad79f9781..68cac5abd2 100644
--- a/phpBB/includes/mcp/info/mcp_queue.php
+++ b/phpBB/includes/mcp/info/mcp_queue.php
@@ -21,6 +21,8 @@ class mcp_queue_info
'modes' => array(
'unapproved_topics' => array('title' => 'MCP_QUEUE_UNAPPROVED_TOPICS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')),
'unapproved_posts' => array('title' => 'MCP_QUEUE_UNAPPROVED_POSTS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')),
+ 'deleted_topics' => array('title' => 'MCP_QUEUE_DELETED_TOPICS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')),
+ 'deleted_posts' => array('title' => 'MCP_QUEUE_DELETED_POSTS', 'auth' => 'aclf_m_approve', 'cat' => array('MCP_QUEUE')),
'approve_details' => array('title' => 'MCP_QUEUE_APPROVE_DETAILS', 'auth' => 'acl_m_approve,$id || (!$id && aclf_m_approve)', 'cat' => array('MCP_QUEUE')),
),
);
diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php
index 4dd5e5856a..841a0afddb 100644
--- a/phpBB/includes/mcp/mcp_forum.php
+++ b/phpBB/includes/mcp/mcp_forum.php
@@ -22,7 +22,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
{
global $template, $db, $user, $auth, $cache, $module;
global $phpEx, $phpbb_root_path, $config;
- global $request, $phpbb_dispatcher;
+ global $request, $phpbb_dispatcher, $phpbb_container;
$user->add_lang(array('viewtopic', 'viewforum'));
@@ -98,7 +98,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
$sort_by_sql = $sort_order_sql = array();
mcp_sorting('viewforum', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $forum_id);
- $forum_topics = ($total == -1) ? $forum_info['forum_topics'] : $total;
+ $forum_topics = ($total == -1) ? $forum_info['forum_topics_approved'] : $total;
$limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : '';
$base_url = $url . "&amp;i=$id&amp;action=$action&amp;mode=$mode&amp;sd=$sort_dir&amp;sk=$sort_key&amp;st=$sort_days" . (($merge_select) ? $selected_ids : '');
@@ -116,6 +116,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
'S_CAN_REPORT' => $auth->acl_get('m_report', $forum_id),
'S_CAN_DELETE' => $auth->acl_get('m_delete', $forum_id),
+ 'S_CAN_RESTORE' => $auth->acl_get('m_approve', $forum_id),
'S_CAN_MERGE' => $auth->acl_get('m_merge', $forum_id),
'S_CAN_MOVE' => $auth->acl_get('m_move', $forum_id),
'S_CAN_FORK' => $auth->acl_get('m_', $forum_id),
@@ -151,10 +152,12 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
$read_tracking_join = $read_tracking_select = '';
}
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+
$sql = 'SELECT t.topic_id
FROM ' . TOPICS_TABLE . ' t
WHERE t.forum_id = ' . $forum_id . '
- ' . (($auth->acl_get('m_approve', $forum_id)) ? '' : 'AND t.topic_approved = 1') . "
+ AND ' . $phpbb_content_visibility->get_visibility_sql('topic', $forum_id, 't.') . "
$limit_time_sql
ORDER BY t.topic_type DESC, $sort_order_sql";
$result = $db->sql_query_limit($sql, $topics_per_page, $start);
@@ -203,7 +206,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
$row = &$topic_rows[$topic_id];
- $replies = ($auth->acl_get('m_approve', $forum_id)) ? $row['topic_replies_real'] : $row['topic_replies'];
+ $replies = $phpbb_content_visibility->get_count('topic_posts', $row, $forum_id) - 1;
if ($row['topic_status'] == ITEM_MOVED)
{
@@ -220,9 +223,11 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
$topic_title = censor_text($row['topic_title']);
- $topic_unapproved = (!$row['topic_approved'] && $auth->acl_get('m_approve', $row['forum_id'])) ? true : false;
- $posts_unapproved = ($row['topic_approved'] && $row['topic_replies'] < $row['topic_replies_real'] && $auth->acl_get('m_approve', $row['forum_id'])) ? true : false;
+ $topic_unapproved = ($row['topic_visibility'] == ITEM_UNAPPROVED && $auth->acl_get('m_approve', $row['forum_id'])) ? true : false;
+ $posts_unapproved = ($row['topic_visibility'] == ITEM_APPROVED && $row['topic_posts_unapproved'] && $auth->acl_get('m_approve', $row['forum_id'])) ? true : false;
+ $topic_deleted = $row['topic_visibility'] == ITEM_DELETED;
$u_mcp_queue = ($topic_unapproved || $posts_unapproved) ? $url . '&amp;i=queue&amp;mode=' . (($topic_unapproved) ? 'approve_details' : 'unapproved_posts') . '&amp;t=' . $row['topic_id'] : '';
+ $u_mcp_queue = (!$u_mcp_queue && $topic_deleted) ? $url . '&amp;i=queue&amp;mode=deleted_topics&amp;t=' . $topic_id : $u_mcp_queue;
$topic_row = array(
'ATTACH_ICON_IMG' => ($auth->acl_get('u_download') && $auth->acl_get('f_download', $row['forum_id']) && $row['topic_attachment']) ? $user->img('icon_topic_attach', $user->lang['TOTAL_ATTACHMENTS']) : '',
@@ -232,6 +237,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
'TOPIC_ICON_IMG_WIDTH' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['width'] : '',
'TOPIC_ICON_IMG_HEIGHT' => (!empty($icons[$row['icon_id']])) ? $icons[$row['icon_id']]['height'] : '',
'UNAPPROVED_IMG' => ($topic_unapproved || $posts_unapproved) ? $user->img('icon_topic_unapproved', ($topic_unapproved) ? 'TOPIC_UNAPPROVED' : 'POSTS_UNAPPROVED') : '',
+ 'DELETED_IMG' => ($topic_deleted) ? $user->img('icon_topic_deleted', 'POSTS_DELETED') : '',
'TOPIC_AUTHOR' => get_username_string('username', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
'TOPIC_AUTHOR_COLOUR' => get_username_string('colour', $row['topic_poster'], $row['topic_first_poster_name'], $row['topic_first_poster_colour']),
@@ -245,7 +251,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
'TOPIC_TYPE' => $topic_type,
'TOPIC_TITLE' => $topic_title,
- 'REPLIES' => ($auth->acl_get('m_approve', $row['forum_id'])) ? $row['topic_replies_real'] : $row['topic_replies'],
+ 'REPLIES' => $phpbb_content_visibility->get_count('topic_posts', $row, $row['forum_id']) - 1,
'LAST_POST_TIME' => $user->format_date($row['topic_last_post_time']),
'FIRST_POST_TIME' => $user->format_date($row['topic_time']),
'LAST_POST_SUBJECT' => $row['topic_last_post_subject'],
@@ -254,6 +260,7 @@ function mcp_forum_view($id, $mode, $action, $forum_info)
'S_TOPIC_REPORTED' => (!empty($row['topic_reported']) && empty($row['topic_moved_id']) && $auth->acl_get('m_report', $row['forum_id'])) ? true : false,
'S_TOPIC_UNAPPROVED' => $topic_unapproved,
'S_POSTS_UNAPPROVED' => $posts_unapproved,
+ 'S_TOPIC_DELETED' => $topic_deleted,
'S_UNREAD_TOPIC' => $unread_topic,
);
@@ -430,13 +437,16 @@ function merge_topics($forum_id, $topic_ids, $to_topic_id)
// Message and return links
$success_msg = 'POSTS_MERGED_SUCCESS';
- // 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...
- $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_return_on_error(false);
+ if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status'))
+ {
+ include($phpbb_root_path . 'includes/functions_database_helper.' . $phpEx);
+ }
+
+ // Update the topic watch table.
+ phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $topic_ids, $to_topic_id);
- $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE ' . $db->sql_in_set('topic_id', $topic_ids));
+ // Update the bookmarks table.
+ phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', $topic_ids, $to_topic_id);
// Link to the new topic
$return_link .= (($return_link) ? '<br /><br />' : '') . sprintf($user->lang['RETURN_NEW_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $to_forum_id . '&amp;t=' . $to_topic_id) . '">', '</a>');
diff --git a/phpBB/includes/mcp/mcp_front.php b/phpBB/includes/mcp/mcp_front.php
index ba4b15895a..44cab5d910 100644
--- a/phpBB/includes/mcp/mcp_front.php
+++ b/phpBB/includes/mcp/mcp_front.php
@@ -39,7 +39,7 @@ function mcp_front_view($id, $mode, $action)
$sql = 'SELECT COUNT(post_id) AS total
FROM ' . POSTS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $forum_list) . '
- AND post_approved = 0';
+ AND post_visibility = ' . ITEM_UNAPPROVED;
$result = $db->sql_query($sql);
$total = (int) $db->sql_fetchfield('total');
$db->sql_freeresult($result);
@@ -60,7 +60,7 @@ function mcp_front_view($id, $mode, $action)
$sql = 'SELECT post_id
FROM ' . POSTS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $forum_list) . '
- AND post_approved = 0
+ AND post_visibility = ' . ITEM_UNAPPROVED . '
ORDER BY post_time DESC';
$result = $db->sql_query_limit($sql, 5);
diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php
index 95ca7c2e1b..275edbe55a 100644
--- a/phpBB/includes/mcp/mcp_main.php
+++ b/phpBB/includes/mcp/mcp_main.php
@@ -33,7 +33,7 @@ class mcp_main
function main($id, $mode)
{
global $auth, $db, $user, $template, $action;
- global $config, $phpbb_root_path, $phpEx;
+ global $config, $phpbb_root_path, $phpEx, $request;
$quickmod = ($mode == 'quickmod') ? true : false;
@@ -108,27 +108,48 @@ class mcp_main
case 'delete_topic':
$user->add_lang('viewtopic');
- $topic_ids = (!$quickmod) ? request_var('topic_id_list', array(0)) : array(request_var('t', 0));
+ // f parameter is not reliable for permission usage, however we just use it to decide
+ // which permission we will check later on. So if it is manipulated, we will still catch it later on.
+ $forum_id = $request->variable('f', 0);
+ $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
+ $soft_delete = (($request->is_set_post('confirm') && !$request->is_set_post('delete_permanent')) || !$auth->acl_get('m_delete', $forum_id)) ? true : false;
if (!sizeof($topic_ids))
{
trigger_error('NO_TOPIC_SELECTED');
}
- mcp_delete_topic($topic_ids);
+ mcp_delete_topic($topic_ids, $soft_delete, ($soft_delete) ? $request->variable('delete_reason', '', true) : '');
break;
case 'delete_post':
$user->add_lang('posting');
- $post_ids = (!$quickmod) ? request_var('post_id_list', array(0)) : array(request_var('p', 0));
+ // f parameter is not reliable for permission usage, however we just use it to decide
+ // which permission we will check later on. So if it is manipulated, we will still catch it later on.
+ $forum_id = $request->variable('f', 0);
+ $post_ids = (!$quickmod) ? $request->variable('post_id_list', array(0)) : array($request->variable('p', 0));
+ $soft_delete = (($request->is_set_post('confirm') && !$request->is_set_post('delete_permanent')) || !$auth->acl_get('m_delete', $forum_id)) ? true : false;
if (!sizeof($post_ids))
{
trigger_error('NO_POST_SELECTED');
}
- mcp_delete_post($post_ids);
+ mcp_delete_post($post_ids, $soft_delete, ($soft_delete) ? $request->variable('delete_reason', '', true) : '');
+ break;
+
+ case 'restore_topic':
+ $user->add_lang('posting');
+
+ $topic_ids = (!$quickmod) ? $request->variable('topic_id_list', array(0)) : array($request->variable('t', 0));
+
+ if (!sizeof($topic_ids))
+ {
+ trigger_error('NO_TOPIC_SELECTED');
+ }
+
+ mcp_restore_topic($topic_ids);
break;
}
@@ -455,59 +476,30 @@ function mcp_move_topic($topic_ids)
$forum_sync_data[$forum_id] = current($topic_data);
$forum_sync_data[$to_forum_id] = $forum_data;
- // Real topics added to target forum
- $topics_moved = sizeof($topic_data);
-
- // Approved topics added to target forum
- $topics_authed_moved = 0;
-
- // Posts (topic replies + topic post if approved) added to target forum
- $topic_posts_added = 0;
-
- // Posts (topic replies + topic post if approved and not global announcement) removed from source forum
- $topic_posts_removed = 0;
-
- // Real topics removed from source forum (all topics without global announcements)
- $topics_removed = 0;
-
- // Approved topics removed from source forum (except global announcements)
- $topics_authed_removed = 0;
+ $topics_moved = $topics_moved_unapproved = $topics_moved_softdeleted = 0;
+ $posts_moved = $posts_moved_unapproved = $posts_moved_softdeleted = 0;
foreach ($topic_data as $topic_id => $topic_info)
{
- if ($topic_info['topic_approved'])
+ if ($topic_info['topic_visibility'] == ITEM_APPROVED)
{
- $topics_authed_moved++;
- $topic_posts_added++;
+ $topics_moved++;
}
-
- $topic_posts_added += $topic_info['topic_replies'];
-
- $topics_removed++;
- $topic_posts_removed += $topic_info['topic_replies'];
-
- if ($topic_info['topic_approved'])
+ elseif ($topic_info['topic_visibility'] == ITEM_UNAPPROVED)
{
- $topics_authed_removed++;
- $topic_posts_removed++;
+ $topics_moved_unapproved++;
+ }
+ elseif ($topic_info['topic_visibility'] == ITEM_DELETED)
+ {
+ $topics_moved_softdeleted++;
}
- }
-
- $db->sql_transaction('begin');
-
- $sync_sql = array();
-
- if ($topic_posts_added)
- {
- $sync_sql[$to_forum_id][] = 'forum_posts = forum_posts + ' . $topic_posts_added;
- }
- if ($topics_authed_moved)
- {
- $sync_sql[$to_forum_id][] = 'forum_topics = forum_topics + ' . (int) $topics_authed_moved;
+ $posts_moved += $topic_info['topic_posts_approved'];
+ $posts_moved_unapproved += $topic_info['topic_posts_unapproved'];
+ $posts_moved_softdeleted += $topic_info['topic_posts_softdeleted'];
}
- $sync_sql[$to_forum_id][] = 'forum_topics_real = forum_topics_real + ' . (int) $topics_moved;
+ $db->sql_transaction('begin');
// Move topics, but do not resync yet
move_topics($topic_ids, $to_forum_id, false);
@@ -520,6 +512,7 @@ function mcp_move_topic($topic_ids)
$db->sql_query($sql);
}
+ $shadow_topics = 0;
$forum_ids = array($to_forum_id);
foreach ($topic_data as $topic_id => $row)
{
@@ -528,21 +521,22 @@ function mcp_move_topic($topic_ids)
add_log('mod', $to_forum_id, $topic_id, 'LOG_MOVE', $row['forum_name'], $forum_data['forum_name']);
// Leave a redirection if required and only if the topic is visible to users
- if ($leave_shadow && $row['topic_approved'] && $row['topic_type'] != POST_GLOBAL)
+ if ($leave_shadow && $row['topic_visibility'] == ITEM_APPROVED && $row['topic_type'] != POST_GLOBAL)
{
$shadow = array(
'forum_id' => (int) $row['forum_id'],
'icon_id' => (int) $row['icon_id'],
'topic_attachment' => (int) $row['topic_attachment'],
- 'topic_approved' => 1, // a shadow topic is always approved
+ 'topic_visibility' => ITEM_APPROVED, // a shadow topic is always approved
'topic_reported' => 0, // a shadow topic is never reported
'topic_title' => (string) $row['topic_title'],
'topic_poster' => (int) $row['topic_poster'],
'topic_time' => (int) $row['topic_time'],
'topic_time_limit' => (int) $row['topic_time_limit'],
'topic_views' => (int) $row['topic_views'],
- 'topic_replies' => (int) $row['topic_replies'],
- 'topic_replies_real' => (int) $row['topic_replies_real'],
+ 'topic_posts_approved' => (int) $row['topic_posts_approved'],
+ 'topic_posts_unapproved'=> (int) $row['topic_posts_unapproved'],
+ 'topic_posts_softdeleted'=> (int) $row['topic_posts_softdeleted'],
'topic_status' => ITEM_MOVED,
'topic_type' => POST_NORMAL,
'topic_first_post_id' => (int) $row['topic_first_post_id'],
@@ -568,25 +562,45 @@ function mcp_move_topic($topic_ids)
$db->sql_query('INSERT INTO ' . TOPICS_TABLE . $db->sql_build_array('INSERT', $shadow));
// Shadow topics only count on new "topics" and not posts... a shadow topic alone has 0 posts
- $topics_removed--;
- $topics_authed_removed--;
+ $shadow_topics++;
}
}
unset($topic_data);
- if ($topic_posts_removed)
+ $sync_sql = array();
+ if ($posts_moved)
{
- $sync_sql[$forum_id][] = 'forum_posts = forum_posts - ' . $topic_posts_removed;
+ $sync_sql[$to_forum_id][] = 'forum_posts_approved = forum_posts_approved + ' . (int) $posts_moved;
+ $sync_sql[$forum_id][] = 'forum_posts_approved = forum_posts_approved - ' . (int) $posts_moved;
}
-
- if ($topics_removed)
+ if ($posts_moved_unapproved)
+ {
+ $sync_sql[$to_forum_id][] = 'forum_posts_unapproved = forum_posts_unapproved + ' . (int) $posts_moved_unapproved;
+ $sync_sql[$forum_id][] = 'forum_posts_unapproved = forum_posts_unapproved - ' . (int) $posts_moved_unapproved;
+ }
+ if ($posts_moved_softdeleted)
{
- $sync_sql[$forum_id][] = 'forum_topics_real = forum_topics_real - ' . (int) $topics_removed;
+ $sync_sql[$to_forum_id][] = 'forum_posts_softdeleted = forum_posts_softdeleted + ' . (int) $posts_moved_softdeleted;
+ $sync_sql[$forum_id][] = 'forum_posts_softdeleted = forum_posts_softdeleted - ' . (int) $posts_moved_softdeleted;
}
- if ($topics_authed_removed)
+ if ($topics_moved)
+ {
+ $sync_sql[$to_forum_id][] = 'forum_topics_approved = forum_topics_approved + ' . (int) $topics_moved;
+ if ($topics_moved - $shadow_topics > 0)
+ {
+ $sync_sql[$forum_id][] = 'forum_topics_approved = forum_topics_approved - ' . (int) ($topics_moved - $shadow_topics);
+ }
+ }
+ if ($topics_moved_unapproved)
+ {
+ $sync_sql[$to_forum_id][] = 'forum_topics_unapproved = forum_topics_unapproved + ' . (int) $topics_moved_unapproved;
+ $sync_sql[$forum_id][] = 'forum_topics_unapproved = forum_topics_unapproved - ' . (int) $topics_moved_unapproved;
+ }
+ if ($topics_moved_softdeleted)
{
- $sync_sql[$forum_id][] = 'forum_topics = forum_topics - ' . (int) $topics_authed_removed;
+ $sync_sql[$to_forum_id][] = 'forum_topics_softdeleted = forum_topics_softdeleted + ' . (int) $topics_moved_softdeleted;
+ $sync_sql[$forum_id][] = 'forum_topics_softdeleted = forum_topics_softdeleted - ' . (int) $topics_moved_softdeleted;
}
$success_msg = (sizeof($topic_ids) == 1) ? 'TOPIC_MOVED_SUCCESS' : 'TOPICS_MOVED_SUCCESS';
@@ -636,25 +650,98 @@ function mcp_move_topic($topic_ids)
}
/**
+* Restore Topics
+*/
+function mcp_restore_topic($topic_ids)
+{
+ global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container;
+
+ if (!check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_approve')))
+ {
+ return;
+ }
+
+ $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
+ $forum_id = $request->variable('f', 0);
+
+ $s_hidden_fields = build_hidden_fields(array(
+ 'topic_id_list' => $topic_ids,
+ 'f' => $forum_id,
+ 'action' => 'restore_topic',
+ 'redirect' => $redirect,
+ ));
+ $success_msg = '';
+
+ if (confirm_box(true))
+ {
+ $success_msg = (sizeof($topic_ids) == 1) ? 'TOPIC_RESTORED_SUCCESS' : 'TOPICS_RESTORED_SUCCESS';
+
+ $data = get_topic_data($topic_ids);
+
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+ foreach ($data as $topic_id => $row)
+ {
+ $return = $phpbb_content_visibility->set_topic_visibility(ITEM_APPROVED, $topic_id, $row['forum_id'], $user->data['user_id'], time(), '');
+ if (!empty($return))
+ {
+ add_log('mod', $row['forum_id'], $topic_id, 'LOG_RESTORE_TOPIC', $row['topic_title'], $row['topic_first_poster_name']);
+ }
+ }
+ }
+ else
+ {
+ confirm_box(false, (sizeof($topic_ids) == 1) ? 'RESTORE_TOPIC' : 'RESTORE_TOPICS', $s_hidden_fields);
+ }
+
+ $topic_id = $request->variable('t', 0);
+ if (!$request->is_set('quickmod', phpbb_request_interface::REQUEST))
+ {
+ $redirect = $request->variable('redirect', "index.$phpEx");
+ $redirect = reapply_sid($redirect);
+ $redirect_message = 'PAGE';
+ }
+ else if ($topic_id)
+ {
+ $redirect = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_id);
+ $redirect_message = 'TOPIC';
+ }
+ else
+ {
+ $redirect = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id);
+ $redirect_message = 'FORUM';
+ }
+
+ if (!$success_msg)
+ {
+ redirect($redirect);
+ }
+ else
+ {
+ meta_refresh(3, $redirect);
+ trigger_error($user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_' . $redirect_message], '<a href="' . $redirect . '">', '</a>'));
+ }
+}
+
+/**
* Delete Topics
*/
-function mcp_delete_topic($topic_ids)
+function mcp_delete_topic($topic_ids, $is_soft = false, $soft_delete_reason = '', $action = 'delete_topic')
{
- global $auth, $user, $db, $phpEx, $phpbb_root_path;
+ global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container;
if (!check_ids($topic_ids, TOPICS_TABLE, 'topic_id', array('m_delete')))
{
return;
}
- $redirect = request_var('redirect', build_url(array('action', 'quickmod')));
- $forum_id = request_var('f', 0);
+ $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
+ $forum_id = $request->variable('f', 0);
- $s_hidden_fields = build_hidden_fields(array(
+ $s_hidden_fields = array(
'topic_id_list' => $topic_ids,
'f' => $forum_id,
- 'action' => 'delete_topic',
- 'redirect' => $redirect)
+ 'action' => $action,
+ 'redirect' => $redirect,
);
$success_msg = '';
@@ -672,23 +759,81 @@ function mcp_delete_topic($topic_ids)
}
else
{
- add_log('mod', $row['forum_id'], $topic_id, 'LOG_DELETE_TOPIC', $row['topic_title'], $row['topic_first_poster_name']);
+ // Only soft delete non-shadow topics
+ if ($is_soft)
+ {
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+ $return = $phpbb_content_visibility->set_topic_visibility(ITEM_DELETED, $topic_id, $row['forum_id'], $user->data['user_id'], time(), $soft_delete_reason);
+ if (!empty($return))
+ {
+ add_log('mod', $row['forum_id'], $topic_id, 'LOG_SOFTDELETE_TOPIC', $row['topic_title'], $row['topic_first_poster_name']);
+ }
+ }
+ else
+ {
+ add_log('mod', $row['forum_id'], $topic_id, 'LOG_DELETE_TOPIC', $row['topic_title'], $row['topic_first_poster_name']);
+ }
}
}
- $return = delete_topics('topic_id', $topic_ids);
+ if (!$is_soft)
+ {
+ $return = delete_topics('topic_id', $topic_ids);
+ }
}
else
{
- confirm_box(false, (sizeof($topic_ids) == 1) ? 'DELETE_TOPIC' : 'DELETE_TOPICS', $s_hidden_fields);
+ global $template;
+
+ $user->add_lang('posting');
+
+ $only_softdeleted = false;
+ if ($auth->acl_get('m_delete', $forum_id) && $auth->acl_get('m_softdelete', $forum_id))
+ {
+ // If there are only soft deleted topics, we display a message why the option is not available
+ $sql = 'SELECT topic_id
+ FROM ' . TOPICS_TABLE . '
+ WHERE ' . $db->sql_in_set('topic_id', $topic_ids) . '
+ AND topic_visibility <> ' . ITEM_DELETED;
+ $result = $db->sql_query_limit($sql, 1);
+ $only_softdeleted = !$db->sql_fetchfield('topic_id');
+ $db->sql_freeresult($result);
+ }
+
+ $template->assign_vars(array(
+ 'S_SOFTDELETED' => $only_softdeleted,
+ 'S_TOPIC_MODE' => true,
+ 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id),
+ 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id),
+ 'S_DELETE_REASON' => $auth->acl_get('m_softdelete', $forum_id),
+ ));
+
+ $l_confirm = (sizeof($topic_ids) == 1) ? 'DELETE_TOPIC' : 'DELETE_TOPICS';
+ if ($only_softdeleted)
+ {
+ $l_confirm .= '_PERMANENTLY';
+ $s_hidden_fields['delete_permanent'] = '1';
+ }
+ else if (!$auth->acl_get('m_softdelete', $forum_id))
+ {
+ $s_hidden_fields['delete_permanent'] = '1';
+ }
+
+ confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html');
}
- if (!isset($_REQUEST['quickmod']))
+ $topic_id = $request->variable('t', 0);
+ if (!$request->is_set('quickmod', phpbb_request_interface::REQUEST))
{
- $redirect = request_var('redirect', "index.$phpEx");
+ $redirect = $request->variable('redirect', "index.$phpEx");
$redirect = reapply_sid($redirect);
$redirect_message = 'PAGE';
}
+ else if ($is_soft && $topic_id)
+ {
+ $redirect = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 't=' . $topic_id);
+ $redirect_message = 'TOPIC';
+ }
else
{
$redirect = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id);
@@ -709,27 +854,93 @@ function mcp_delete_topic($topic_ids)
/**
* Delete Posts
*/
-function mcp_delete_post($post_ids)
+function mcp_delete_post($post_ids, $is_soft = false, $soft_delete_reason = '', $action = 'delete_post')
{
- global $auth, $user, $db, $phpEx, $phpbb_root_path;
+ global $auth, $user, $db, $phpEx, $phpbb_root_path, $request, $phpbb_container;
- if (!check_ids($post_ids, POSTS_TABLE, 'post_id', array('m_delete')))
+ if (!check_ids($post_ids, POSTS_TABLE, 'post_id', array('m_softdelete')))
{
return;
}
- $redirect = request_var('redirect', build_url(array('action', 'quickmod')));
- $forum_id = request_var('f', 0);
+ $redirect = $request->variable('redirect', build_url(array('action', 'quickmod')));
+ $forum_id = $request->variable('f', 0);
- $s_hidden_fields = build_hidden_fields(array(
+ $s_hidden_fields = array(
'post_id_list' => $post_ids,
'f' => $forum_id,
- 'action' => 'delete_post',
- 'redirect' => $redirect)
+ 'action' => $action,
+ 'redirect' => $redirect,
);
$success_msg = '';
- if (confirm_box(true))
+ if (confirm_box(true) && $is_soft)
+ {
+ $post_info = get_post_data($post_ids);
+
+ $topic_info = $approve_log = array();
+
+ // Group the posts by topic_id
+ foreach ($post_info as $post_id => $post_data)
+ {
+ if ($post_data['post_visibility'] != ITEM_APPROVED)
+ {
+ continue;
+ }
+ $topic_id = (int) $post_data['topic_id'];
+
+ $topic_info[$topic_id]['posts'][] = (int) $post_id;
+ $topic_info[$topic_id]['forum_id'] = (int) $post_data['forum_id'];
+
+ if ($post_id == $post_data['topic_first_post_id'])
+ {
+ $topic_info[$topic_id]['first_post'] = true;
+ }
+
+ if ($post_id == $post_data['topic_last_post_id'])
+ {
+ $topic_info[$topic_id]['last_post'] = true;
+ }
+
+ $approve_log[] = array(
+ 'forum_id' => $post_data['forum_id'],
+ 'topic_id' => $post_data['topic_id'],
+ 'post_subject' => $post_data['post_subject'],
+ 'poster_id' => $post_data['poster_id'],
+ 'post_username' => $post_data['post_username'],
+ 'username' => $post_data['username'],
+ );
+ }
+
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+ foreach ($topic_info as $topic_id => $topic_data)
+ {
+ $phpbb_content_visibility->set_post_visibility(ITEM_DELETED, $topic_data['posts'], $topic_id, $topic_data['forum_id'], $user->data['user_id'], time(), $soft_delete_reason, isset($topic_data['first_post']), isset($topic_data['last_post']));
+ }
+ $affected_topics = sizeof($topic_info);
+ // None of the topics is really deleted, so a redirect won't hurt much.
+ $deleted_topics = 0;
+
+ $success_msg = (sizeof($post_info) == 1) ? 'POST_DELETED_SUCCESS' : 'POSTS_DELETED_SUCCESS';
+
+ foreach ($approve_log as $row)
+ {
+ $post_username = ($row['poster_id'] == ANONYMOUS && !empty($row['post_username'])) ? $row['post_username'] : $row['username'];
+ add_log('mod', $row['forum_id'], $row['topic_id'], 'LOG_SOFTDELETE_POST', $row['post_subject'], $post_username);
+ }
+
+ $topic_id = $request->variable('t', 0);
+
+ // Return links
+ $return_link = array();
+ if ($affected_topics == 1 && $topic_id)
+ {
+ $return_link[] = sprintf($user->lang['RETURN_TOPIC'], '<a href="' . append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f=$forum_id&amp;t=$topic_id") . '">', '</a>');
+ }
+ $return_link[] = sprintf($user->lang['RETURN_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id) . '">', '</a>');
+
+ }
+ else if (confirm_box(true))
{
if (!function_exists('delete_posts'))
{
@@ -772,7 +983,7 @@ function mcp_delete_post($post_ids)
$deleted_topics = ($row = $db->sql_fetchrow($result)) ? ($affected_topics - $row['topics_left']) : $affected_topics;
$db->sql_freeresult($result);
- $topic_id = request_var('t', 0);
+ $topic_id = $request->variable('t', 0);
// Return links
$return_link = array();
@@ -810,10 +1021,45 @@ function mcp_delete_post($post_ids)
}
else
{
- confirm_box(false, (sizeof($post_ids) == 1) ? 'DELETE_POST' : 'DELETE_POSTS', $s_hidden_fields);
+ global $template;
+
+ $user->add_lang('posting');
+
+ $only_softdeleted = false;
+ if ($auth->acl_get('m_delete', $forum_id) && $auth->acl_get('m_softdelete', $forum_id))
+ {
+ // If there are only soft deleted posts, we display a message why the option is not available
+ $sql = 'SELECT post_id
+ FROM ' . POSTS_TABLE . '
+ WHERE ' . $db->sql_in_set('post_id', $post_ids) . '
+ AND post_visibility <> ' . ITEM_DELETED;
+ $result = $db->sql_query_limit($sql, 1);
+ $only_softdeleted = !$db->sql_fetchfield('post_id');
+ $db->sql_freeresult($result);
+ }
+
+ $template->assign_vars(array(
+ 'S_SOFTDELETED' => $only_softdeleted,
+ 'S_ALLOWED_DELETE' => $auth->acl_get('m_delete', $forum_id),
+ 'S_ALLOWED_SOFTDELETE' => $auth->acl_get('m_softdelete', $forum_id),
+ 'S_DELETE_REASON' => $auth->acl_get('m_softdelete', $forum_id),
+ ));
+
+ $l_confirm = (sizeof($post_ids) == 1) ? 'DELETE_POST' : 'DELETE_POSTS';
+ if ($only_softdeleted)
+ {
+ $l_confirm .= '_PERMANENTLY';
+ $s_hidden_fields['delete_permanent'] = '1';
+ }
+ else if (!$auth->acl_get('m_softdelete', $forum_id))
+ {
+ $s_hidden_fields['delete_permanent'] = '1';
+ }
+
+ confirm_box(false, $l_confirm, build_hidden_fields($s_hidden_fields), 'confirm_delete_body.html');
}
- $redirect = request_var('redirect', "index.$phpEx");
+ $redirect = $request->variable('redirect', "index.$phpEx");
$redirect = reapply_sid($redirect);
if (!$success_msg)
@@ -898,10 +1144,10 @@ function mcp_fork_topic($topic_ids)
{
$topic_data = get_topic_data($topic_ids, 'f_post');
- $total_posts = 0;
+ $total_topics = $total_topics_unapproved = $total_topics_softdeleted = 0;
+ $total_posts = $total_posts_unapproved = $total_posts_softdeleted = 0;
$new_topic_id_list = array();
-
foreach ($topic_data as $topic_id => $topic_row)
{
if (!isset($search_type) && $topic_row['enable_indexing'])
@@ -932,13 +1178,14 @@ function mcp_fork_topic($topic_ids)
'forum_id' => (int) $to_forum_id,
'icon_id' => (int) $topic_row['icon_id'],
'topic_attachment' => (int) $topic_row['topic_attachment'],
- 'topic_approved' => 1,
+ 'topic_visibility' => (int) $topic_row['topic_visibility'],
'topic_reported' => 0,
'topic_title' => (string) $topic_row['topic_title'],
'topic_poster' => (int) $topic_row['topic_poster'],
'topic_time' => (int) $topic_row['topic_time'],
- 'topic_replies' => (int) $topic_row['topic_replies_real'],
- 'topic_replies_real' => (int) $topic_row['topic_replies_real'],
+ 'topic_posts_approved' => (int) $topic_row['topic_posts_approved'],
+ 'topic_posts_unapproved' => (int) $topic_row['topic_posts_unapproved'],
+ 'topic_posts_softdeleted' => (int) $topic_row['topic_posts_softdeleted'],
'topic_status' => (int) $topic_row['topic_status'],
'topic_type' => (int) $topic_row['topic_type'],
'topic_first_poster_name' => (string) $topic_row['topic_first_poster_name'],
@@ -959,6 +1206,19 @@ function mcp_fork_topic($topic_ids)
$new_topic_id = $db->sql_nextid();
$new_topic_id_list[$topic_id] = $new_topic_id;
+ switch ($topic_row['topic_visibility'])
+ {
+ case ITEM_APPROVED:
+ $total_topics++;
+ break;
+ case ITEM_UNAPPROVED:
+ $total_topics_unapproved++;
+ break;
+ case ITEM_DELETED:
+ $total_topics_softdeleted++;
+ break;
+ }
+
if ($topic_row['poll_start'])
{
$poll_rows = array();
@@ -999,7 +1259,6 @@ function mcp_fork_topic($topic_ids)
continue;
}
- $total_posts += sizeof($post_rows);
foreach ($post_rows as $row)
{
$sql_ary = array(
@@ -1009,7 +1268,7 @@ function mcp_fork_topic($topic_ids)
'icon_id' => (int) $row['icon_id'],
'poster_ip' => (string) $row['poster_ip'],
'post_time' => (int) $row['post_time'],
- 'post_approved' => 1,
+ 'post_visibility' => (int) $row['post_visibility'],
'post_reported' => 0,
'enable_bbcode' => (int) $row['enable_bbcode'],
'enable_smilies' => (int) $row['enable_smilies'],
@@ -1033,6 +1292,19 @@ function mcp_fork_topic($topic_ids)
$db->sql_query('INSERT INTO ' . POSTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
$new_post_id = $db->sql_nextid();
+ switch ($row['post_visibility'])
+ {
+ case ITEM_APPROVED:
+ $total_posts++;
+ break;
+ case ITEM_UNAPPROVED:
+ $total_posts_unapproved++;
+ break;
+ case ITEM_DELETED:
+ $total_posts_softdeleted++;
+ break;
+ }
+
// Copy whether the topic is dotted
markread('post', $to_forum_id, $new_topic_id, 0, $row['poster_id']);
@@ -1080,6 +1352,7 @@ function mcp_fork_topic($topic_ids)
}
}
+ // Copy topic subscriptions to new topic
$sql = 'SELECT user_id, notify_status
FROM ' . TOPICS_WATCH_TABLE . '
WHERE topic_id = ' . $topic_id;
@@ -1100,26 +1373,43 @@ function mcp_fork_topic($topic_ids)
{
$db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary);
}
- }
-
- // Sync new topics, parent forums and board stats
- sync('topic', 'topic_id', $new_topic_id_list);
- $sync_sql = array();
+ // Copy bookmarks to new topic
+ $sql = 'SELECT user_id
+ FROM ' . BOOKMARKS_TABLE . '
+ WHERE topic_id = ' . $topic_id;
+ $result = $db->sql_query($sql);
- $sync_sql[$to_forum_id][] = 'forum_posts = forum_posts + ' . $total_posts;
- $sync_sql[$to_forum_id][] = 'forum_topics = forum_topics + ' . sizeof($new_topic_id_list);
- $sync_sql[$to_forum_id][] = 'forum_topics_real = forum_topics_real + ' . sizeof($new_topic_id_list);
+ $sql_ary = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $sql_ary[] = array(
+ 'topic_id' => (int) $new_topic_id,
+ 'user_id' => (int) $row['user_id'],
+ );
+ }
+ $db->sql_freeresult($result);
- foreach ($sync_sql as $forum_id_key => $array)
- {
- $sql = 'UPDATE ' . FORUMS_TABLE . '
- SET ' . implode(', ', $array) . '
- WHERE forum_id = ' . $forum_id_key;
- $db->sql_query($sql);
+ if (sizeof($sql_ary))
+ {
+ $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary);
+ }
}
+ // Sync new topics, parent forums and board stats
+ $sql = 'UPDATE ' . FORUMS_TABLE . '
+ SET forum_posts_approved = forum_posts_approved + ' . $total_posts . ',
+ forum_posts_unapproved = forum_posts_unapproved + ' . $total_posts_unapproved . ',
+ forum_posts_softdeleted = forum_posts_softdeleted + ' . $total_posts_softdeleted . ',
+ forum_topics_approved = forum_topics_approved + ' . $total_topics . ',
+ forum_topics_unapproved = forum_topics_unapproved + ' . $total_topics_unapproved . ',
+ forum_topics_softdeleted = forum_topics_softdeleted + ' . $total_topics_softdeleted . '
+ WHERE forum_id = ' . $to_forum_id;
+ $db->sql_query($sql);
+
+ sync('topic', 'topic_id', $new_topic_id_list);
sync('forum', 'forum_id', $to_forum_id);
+
set_config_count('num_topics', sizeof($new_topic_id_list), true);
set_config_count('num_posts', $total_posts, true);
diff --git a/phpBB/includes/mcp/mcp_notes.php b/phpBB/includes/mcp/mcp_notes.php
index 59cdf3c27e..12fcbfe91e 100644
--- a/phpBB/includes/mcp/mcp_notes.php
+++ b/phpBB/includes/mcp/mcp_notes.php
@@ -173,13 +173,13 @@ class mcp_notes
}
// Generate the appropriate user information for the user we are looking at
- if (!function_exists('get_user_avatar'))
+ if (!function_exists('phpbb_get_user_avatar'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
$rank_title = $rank_img = '';
- $avatar_img = get_user_avatar($userrow['user_avatar'], $userrow['user_avatar_type'], $userrow['user_avatar_width'], $userrow['user_avatar_height']);
+ $avatar_img = phpbb_get_user_avatar($userrow);
$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('a' => $user->lang['SORT_USERNAME'], 'b' => $user->lang['SORT_DATE'], 'c' => $user->lang['SORT_IP'], 'd' => $user->lang['SORT_ACTION']);
diff --git a/phpBB/includes/mcp/mcp_pm_reports.php b/phpBB/includes/mcp/mcp_pm_reports.php
index be18dba944..cb61b25174 100644
--- a/phpBB/includes/mcp/mcp_pm_reports.php
+++ b/phpBB/includes/mcp/mcp_pm_reports.php
@@ -33,7 +33,7 @@ class mcp_pm_reports
function main($id, $mode)
{
global $auth, $db, $user, $template, $cache;
- global $config, $phpbb_root_path, $phpEx, $action;
+ global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container;
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
include_once($phpbb_root_path . 'includes/functions_privmsgs.' . $phpEx);
@@ -89,6 +89,10 @@ class mcp_pm_reports
trigger_error('NO_REPORT');
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->mark_notifications_read_by_parent('report_pm', $report_id, $user->data['user_id']);
+
$pm_id = $report['pm_id'];
$report_id = $report['report_id'];
@@ -111,17 +115,10 @@ class mcp_pm_reports
}
// 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']);
- }
+ $parse_flags = ($pm_info['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
+ $message = generate_text_for_display($pm_info['message_text'], $pm_info['bbcode_uid'], $pm_info['bbcode_bitfield'], $parse_flags, false);
- $message = bbcode_nl2br($message);
- $message = smiley_text($message);
+ $report['report_text'] = make_clickable(bbcode_nl2br($report['report_text']));
if ($pm_info['message_attachment'] && $auth->acl_get('u_pm_download'))
{
diff --git a/phpBB/includes/mcp/mcp_post.php b/phpBB/includes/mcp/mcp_post.php
index 520c964228..06f27655ae 100644
--- a/phpBB/includes/mcp/mcp_post.php
+++ b/phpBB/includes/mcp/mcp_post.php
@@ -125,17 +125,8 @@ function mcp_post_details($id, $mode, $action)
$post_unread = (isset($topic_tracking_info[$post_info['topic_id']]) && $post_info['post_time'] > $topic_tracking_info[$post_info['topic_id']]) ? true : false;
// Process message, leave it uncensored
- $message = $post_info['post_text'];
-
- if ($post_info['bbcode_bitfield'])
- {
- include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx);
- $bbcode = new bbcode($post_info['bbcode_bitfield']);
- $bbcode->bbcode_second_pass($message, $post_info['bbcode_uid'], $post_info['bbcode_bitfield']);
- }
-
- $message = bbcode_nl2br($message);
- $message = smiley_text($message);
+ $parse_flags = ($post_info['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
+ $message = generate_text_for_display($post_info['post_text'], $post_info['bbcode_uid'], $post_info['bbcode_bitfield'], $parse_flags, false);
if ($post_info['post_attachment'] && $auth->acl_get('u_download') && $auth->acl_get('f_download', $post_info['forum_id']))
{
@@ -174,6 +165,33 @@ function mcp_post_details($id, $mode, $action)
}
}
+ // Deleting information
+ if ($post_info['post_visibility'] == ITEM_DELETED && $post_info['post_delete_user'])
+ {
+ // User having deleted the post also being the post author?
+ if (!$post_info['post_delete_user'] || $post_info['post_delete_user'] == $post_info['poster_id'])
+ {
+ $display_username = get_username_string('full', $post_info['poster_id'], $post_info['username'], $post_info['user_colour'], $post_info['post_username']);
+ }
+ else
+ {
+ $sql = 'SELECT user_id, username, user_colour
+ FROM ' . USERS_TABLE . '
+ WHERE user_id = ' . (int) $post_info['post_delete_user'];
+ $result = $db->sql_query($sql);
+ $user_delete_row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+ $display_username = get_username_string('full', $post_info['post_delete_user'], $user_delete_row['username'], $user_delete_row['user_colour']);
+ }
+
+ $user->add_lang('viewtopic');
+ $l_deleted_by = $user->lang('DELETED_INFORMATION', $display_username, $user->format_date($post_info['post_delete_time'], false, true));
+ }
+ else
+ {
+ $l_deleted_by = '';
+ }
+
$template->assign_vars(array(
'U_MCP_ACTION' => "$url&amp;i=main&amp;quickmod=1&amp;mode=post_details", // Use this for mode paramaters
'U_POST_ACTION' => "$url&amp;i=$id&amp;mode=post_details", // Use this for action parameters
@@ -185,10 +203,13 @@ function mcp_post_details($id, $mode, $action)
'S_CAN_DELETE_POST' => $auth->acl_get('m_delete', $post_info['forum_id']),
'S_POST_REPORTED' => ($post_info['post_reported']) ? true : false,
- 'S_POST_UNAPPROVED' => (!$post_info['post_approved']) ? true : false,
+ 'S_POST_UNAPPROVED' => ($post_info['post_visibility'] == ITEM_UNAPPROVED) ? true : false,
+ 'S_POST_DELETED' => ($post_info['post_visibility'] == ITEM_DELETED) ? true : false,
'S_POST_LOCKED' => ($post_info['post_edit_locked']) ? true : false,
'S_USER_NOTES' => true,
'S_CLEAR_ALLOWED' => ($auth->acl_get('a_clearlogs')) ? true : false,
+ 'DELETED_MESSAGE' => $l_deleted_by,
+ 'DELETE_REASON' => $post_info['post_delete_reason'],
'U_EDIT' => ($auth->acl_get('m_edit', $post_info['forum_id'])) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=edit&amp;f={$post_info['forum_id']}&amp;p={$post_info['post_id']}") : '',
'U_FIND_USERNAME' => append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&amp;form=mcp_chgposter&amp;field=username&amp;select_single=true'),
@@ -205,6 +226,7 @@ function mcp_post_details($id, $mode, $action)
'RETURN_FORUM' => sprintf($user->lang['RETURN_FORUM'], '<a href="' . append_sid("{$phpbb_root_path}viewforum.$phpEx", "f={$post_info['forum_id']}&amp;start={$start}") . '">', '</a>'),
'REPORTED_IMG' => $user->img('icon_topic_reported', $user->lang['POST_REPORTED']),
'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', $user->lang['POST_UNAPPROVED']),
+ 'DELETED_IMG' => $user->img('icon_topic_deleted', $user->lang['POST_DELETED']),
'EDIT_IMG' => $user->img('icon_post_edit', $user->lang['EDIT_POST']),
'SEARCH_IMG' => $user->img('icon_user_search', $user->lang['SEARCH']),
@@ -415,7 +437,7 @@ function change_poster(&$post_info, $userdata)
}
// Adjust post counts... only if the post is approved (else, it was not added the users post count anyway)
- if ($post_info['post_postcount'] && $post_info['post_approved'])
+ if ($post_info['post_postcount'] && $post_info['post_visibility'] == ITEM_APPROVED)
{
$sql = 'UPDATE ' . USERS_TABLE . '
SET user_posts = user_posts - 1
diff --git a/phpBB/includes/mcp/mcp_queue.php b/phpBB/includes/mcp/mcp_queue.php
index 0b195aa9d8..1fa89af8e1 100644
--- a/phpBB/includes/mcp/mcp_queue.php
+++ b/phpBB/includes/mcp/mcp_queue.php
@@ -25,15 +25,15 @@ class mcp_queue
var $p_master;
var $u_action;
- function mcp_queue(&$p_master)
+ public function mcp_queue(&$p_master)
{
$this->p_master = &$p_master;
}
- function main($id, $mode)
+ public function main($id, $mode)
{
- global $auth, $db, $user, $template, $cache;
- global $config, $phpbb_root_path, $phpEx, $action;
+ global $auth, $db, $user, $template, $cache, $request;
+ global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container;
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
@@ -45,25 +45,99 @@ class mcp_queue
switch ($action)
{
case 'approve':
- case 'disapprove':
+ case 'restore':
include_once($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
- $post_id_list = request_var('post_id_list', array(0));
+ $post_id_list = $request->variable('post_id_list', array(0));
+ $topic_id_list = $request->variable('topic_id_list', array(0));
- if (!sizeof($post_id_list))
+ if (!empty($post_id_list))
+ {
+ self::approve_posts($action, $post_id_list, 'queue', $mode);
+ }
+ else if (!empty($topic_id_list))
+ {
+ self::approve_topics($action, $topic_id_list, 'queue', $mode);
+ }
+ else
{
trigger_error('NO_POST_SELECTED');
}
+ break;
+
+ case 'delete':
+ $post_id_list = $request->variable('post_id_list', array(0));
+ $topic_id_list = $request->variable('topic_id_list', array(0));
- if ($action == 'approve')
+ if (!empty($post_id_list))
{
- approve_post($post_id_list, 'queue', $mode);
+ if (!function_exists('mcp_delete_post'))
+ {
+ global $phpbb_root_path, $phpEx;
+ include($phpbb_root_path . 'includes/mcp/mcp_main.' . $phpEx);
+ }
+ mcp_delete_post($post_id_list, false, '', $action);
+ }
+ else if (!empty($topic_id_list))
+ {
+ if (!function_exists('mcp_delete_topic'))
+ {
+ global $phpbb_root_path, $phpEx;
+ include($phpbb_root_path . 'includes/mcp/mcp_main.' . $phpEx);
+ }
+ mcp_delete_topic($topic_id_list, false, '', $action);
}
else
{
- disapprove_post($post_id_list, 'queue', $mode);
+ trigger_error('NO_POST_SELECTED');
+ }
+ break;
+
+ case 'disapprove':
+ $post_id_list = $request->variable('post_id_list', array(0));
+ $topic_id_list = $request->variable('topic_id_list', array(0));
+
+ if (!empty($topic_id_list) && $mode == 'deleted_topics')
+ {
+ if (!function_exists('mcp_delete_topics'))
+ {
+ global $phpbb_root_path, $phpEx;
+ include($phpbb_root_path . 'includes/mcp/mcp_main.' . $phpEx);
+ }
+ mcp_delete_topic($topic_id_list, false, '', 'disapprove');
+ return;
+ }
+
+ if (!class_exists('messenger'))
+ {
+ include($phpbb_root_path . 'includes/functions_messenger.' . $phpEx);
}
+ if (!empty($topic_id_list))
+ {
+ $post_visibility = ($mode == 'deleted_topics') ? ITEM_DELETED : ITEM_UNAPPROVED;
+ $sql = 'SELECT post_id
+ FROM ' . POSTS_TABLE . '
+ WHERE post_visibility = ' . $post_visibility . '
+ AND ' . $db->sql_in_set('topic_id', $topic_id_list);
+ $result = $db->sql_query($sql);
+
+ $post_id_list = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $post_id_list[] = (int) $row['post_id'];
+ }
+ $db->sql_freeresult($result);
+ }
+
+ if (!empty($post_id_list))
+ {
+ self::disapprove_posts($post_id_list, 'queue', $mode);
+ }
+ else
+ {
+ trigger_error('NO_POST_SELECTED');
+ }
break;
}
@@ -78,12 +152,16 @@ class mcp_queue
$post_id = request_var('p', 0);
$topic_id = request_var('t', 0);
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
if ($topic_id)
{
$topic_info = get_topic_data(array($topic_id), 'm_approve');
if (isset($topic_info[$topic_id]['topic_first_post_id']))
{
$post_id = (int) $topic_info[$topic_id]['topic_first_post_id'];
+
+ $phpbb_notifications->mark_notifications_read('topic_in_queue', $topic_id, $user->data['user_id']);
}
else
{
@@ -91,6 +169,8 @@ class mcp_queue
}
}
+ $phpbb_notifications->mark_notifications_read('post_in_queue', $post_id, $user->data['user_id']);
+
$post_info = get_post_data(array($post_id), 'm_approve', true);
if (!sizeof($post_info))
@@ -105,8 +185,8 @@ class mcp_queue
$template->assign_vars(array(
'S_TOPIC_REVIEW' => true,
'S_BBCODE_ALLOWED' => $post_info['enable_bbcode'],
- 'TOPIC_TITLE' => $post_info['topic_title'])
- );
+ 'TOPIC_TITLE' => $post_info['topic_title'],
+ ));
}
$extensions = $attachments = $topic_tracking_info = array();
@@ -126,17 +206,8 @@ class mcp_queue
$post_unread = (isset($topic_tracking_info[$post_info['topic_id']]) && $post_info['post_time'] > $topic_tracking_info[$post_info['topic_id']]) ? true : false;
// Process message, leave it uncensored
- $message = $post_info['post_text'];
-
- if ($post_info['bbcode_bitfield'])
- {
- include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx);
- $bbcode = new bbcode($post_info['bbcode_bitfield']);
- $bbcode->bbcode_second_pass($message, $post_info['bbcode_uid'], $post_info['bbcode_bitfield']);
- }
-
- $message = bbcode_nl2br($message);
- $message = smiley_text($message);
+ $parse_flags = ($post_info['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
+ $message = generate_text_for_display($post_info['post_text'], $post_info['bbcode_uid'], $post_info['bbcode_bitfield'], $parse_flags, false);
if ($post_info['post_attachment'] && $auth->acl_get('u_download') && $auth->acl_get('f_download', $post_info['forum_id']))
{
@@ -169,12 +240,39 @@ class mcp_queue
foreach ($attachments as $attachment)
{
$template->assign_block_vars('attachment', array(
- 'DISPLAY_ATTACHMENT' => $attachment)
- );
+ 'DISPLAY_ATTACHMENT' => $attachment,
+ ));
}
}
}
+ // Deleting information
+ if ($post_info['post_visibility'] == ITEM_DELETED && $post_info['post_delete_user'])
+ {
+ // User having deleted the post also being the post author?
+ if (!$post_info['post_delete_user'] || $post_info['post_delete_user'] == $post_info['poster_id'])
+ {
+ $display_username = get_username_string('full', $post_info['poster_id'], $post_info['username'], $post_info['user_colour'], $post_info['post_username']);
+ }
+ else
+ {
+ $sql = 'SELECT u.user_id, u.username, u.user_colour
+ FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
+ WHERE p.post_id = ' . $post_info['post_id'] . '
+ AND p.post_delete_user = u.user_id';
+ $result = $db->sql_query($sql);
+ $post_delete_userinfo = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+ $display_username = get_username_string('full', $post_info['post_delete_user'], $post_delete_userinfo['username'], $post_delete_userinfo['user_colour']);
+ }
+
+ $l_deleted_by = $user->lang('DELETED_INFORMATION', $display_username, $user->format_date($post_info['post_delete_time'], false, true));
+ }
+ else
+ {
+ $l_deleted_by = '';
+ }
+
$post_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $post_info['forum_id'] . '&amp;p=' . $post_info['post_id'] . '#p' . $post_info['post_id']);
$topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $post_info['forum_id'] . '&amp;t=' . $post_info['topic_id']);
@@ -183,9 +281,12 @@ class mcp_queue
'U_APPROVE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", "i=queue&amp;p=$post_id&amp;f=$forum_id"),
'S_CAN_VIEWIP' => $auth->acl_get('m_info', $post_info['forum_id']),
'S_POST_REPORTED' => $post_info['post_reported'],
- 'S_POST_UNAPPROVED' => !$post_info['post_approved'],
+ 'S_POST_UNAPPROVED' => ($post_info['post_visibility'] == ITEM_UNAPPROVED),
'S_POST_LOCKED' => $post_info['post_edit_locked'],
'S_USER_NOTES' => true,
+ 'S_POST_DELETED' => ($post_info['post_visibility'] == ITEM_DELETED),
+ 'DELETED_MESSAGE' => $l_deleted_by,
+ 'DELETE_REASON' => $post_info['post_delete_reason'],
'U_EDIT' => ($auth->acl_get('m_edit', $post_info['forum_id'])) ? append_sid("{$phpbb_root_path}posting.$phpEx", "mode=edit&amp;f={$post_info['forum_id']}&amp;p={$post_info['post_id']}") : '',
'U_MCP_APPROVE' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue&amp;mode=approve_details&amp;f=' . $post_info['forum_id'] . '&amp;p=' . $post_id),
@@ -197,7 +298,8 @@ class mcp_queue
'MINI_POST_IMG' => ($post_unread) ? $user->img('icon_post_target_unread', 'UNREAD_POST') : $user->img('icon_post_target', 'POST'),
- 'RETURN_QUEUE' => sprintf($user->lang['RETURN_QUEUE'], '<a href="' . append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue' . (($topic_id) ? '&amp;mode=unapproved_topics' : '&amp;mode=unapproved_posts')) . "&amp;start=$start\">", '</a>'),
+
+ 'RETURN_QUEUE' => sprintf($user->lang['RETURN_QUEUE'], '<a href="' . append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=queue' . (($topic_id) ? '&amp;mode=unapproved_topics' : '&amp;mode=unapproved_posts')) . '&amp;start=' . $start . '">', '</a>'),
'RETURN_POST' => sprintf($user->lang['RETURN_POST'], '<a href="' . $post_url . '">', '</a>'),
'RETURN_TOPIC_SIMPLE' => sprintf($user->lang['RETURN_TOPIC_SIMPLE'], '<a href="' . $topic_url . '">', '</a>'),
'REPORTED_IMG' => $user->img('icon_topic_reported', $user->lang['POST_REPORTED']),
@@ -224,9 +326,16 @@ class mcp_queue
case 'unapproved_topics':
case 'unapproved_posts':
+ case 'deleted_topics':
+ case 'deleted_posts':
+ $m_perm = 'm_approve';
+ $is_topics = ($mode == 'unapproved_topics' || $mode == 'deleted_topics') ? true : false;
+ $is_restore = ($mode == 'deleted_posts' || $mode == 'deleted_topics') ? true : false;
+ $visibility_const = (!$is_restore) ? ITEM_UNAPPROVED : ITEM_DELETED;
+
$user->add_lang(array('viewtopic', 'viewforum'));
- $topic_id = request_var('t', 0);
+ $topic_id = $request->variable('t', 0);
$forum_info = array();
if ($topic_id)
@@ -242,7 +351,7 @@ class mcp_queue
$forum_id = $topic_info['forum_id'];
}
- $forum_list_approve = get_forum_list('m_approve', false, true);
+ $forum_list_approve = get_forum_list($m_perm, false, true);
$forum_list_read = array_flip(get_forum_list('f_read', true, true)); // Flipped so we can isset() the forum IDs
// Remove forums we cannot read
@@ -268,16 +377,16 @@ class mcp_queue
trigger_error('NOT_MODERATOR');
}
- $sql = 'SELECT SUM(forum_topics) as sum_forum_topics
+ $sql = 'SELECT SUM(forum_topics_approved) as sum_forum_topics
FROM ' . FORUMS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $forum_list);
$result = $db->sql_query($sql);
- $forum_info['forum_topics'] = (int) $db->sql_fetchfield('sum_forum_topics');
+ $forum_info['forum_topics_approved'] = (int) $db->sql_fetchfield('sum_forum_topics');
$db->sql_freeresult($result);
}
else
{
- $forum_info = get_forum_data(array($forum_id), 'm_approve');
+ $forum_info = get_forum_data(array($forum_id), $m_perm);
if (!sizeof($forum_info))
{
@@ -299,21 +408,22 @@ class mcp_queue
$sort_by_sql = $sort_order_sql = array();
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;
+ $forum_topics = ($total == -1) ? $forum_info['forum_topics_approved'] : $total;
$limit_time_sql = ($sort_days) ? 'AND t.topic_last_post_time >= ' . (time() - ($sort_days * 86400)) : '';
$forum_names = array();
- if ($mode == 'unapproved_posts')
+ if (!$is_topics)
{
$sql = 'SELECT p.post_id
FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t' . (($sort_order_sql[0] == 'u') ? ', ' . USERS_TABLE . ' u' : '') . '
WHERE ' . $db->sql_in_set('p.forum_id', $forum_list) . '
- AND p.post_approved = 0
+ AND p.post_visibility = ' . $visibility_const . '
' . (($sort_order_sql[0] == 'u') ? 'AND u.user_id = p.poster_id' : '') . '
' . (($topic_id) ? 'AND p.topic_id = ' . $topic_id : '') . "
AND t.topic_id = p.topic_id
- AND t.topic_first_post_id <> p.post_id
+ AND (t.topic_visibility <> p.post_visibility
+ OR t.topic_delete_user = 0)
$limit_time_sql
ORDER BY $sort_order_sql";
$result = $db->sql_query_limit($sql, $config['topics_per_page'], $start);
@@ -359,9 +469,10 @@ class mcp_queue
else
{
$sql = 'SELECT t.forum_id, t.topic_id, t.topic_title, t.topic_title AS post_subject, t.topic_time AS post_time, t.topic_poster AS poster_id, t.topic_first_post_id AS post_id, t.topic_attachment AS post_attachment, t.topic_first_poster_name AS username, t.topic_first_poster_colour AS user_colour
- FROM ' . TOPICS_TABLE . " t
- WHERE " . $db->sql_in_set('forum_id', $forum_list) . "
- AND topic_approved = 0
+ FROM ' . TOPICS_TABLE . ' t
+ WHERE ' . $db->sql_in_set('forum_id', $forum_list) . '
+ AND topic_visibility = ' . $visibility_const . "
+ AND topic_delete_user <> 0
$limit_time_sql
ORDER BY $sort_order_sql";
$result = $db->sql_query_limit($sql, $config['topics_per_page'], $start);
@@ -395,7 +506,7 @@ class mcp_queue
{
if (empty($row['post_username']))
{
- $row['post_username'] = $user->lang['GUEST'];
+ $row['post_username'] = $row['username'] ?: $user->lang['GUEST'];
}
$template->assign_block_vars('postrow', array(
@@ -410,6 +521,7 @@ class mcp_queue
'U_POST_AUTHOR' => get_username_string('profile', $row['poster_id'], $row['username'], $row['user_colour'], $row['post_username']),
'POST_ID' => $row['post_id'],
+ 'TOPIC_ID' => $row['topic_id'],
'FORUM_NAME' => $forum_names[$row['forum_id']],
'POST_SUBJECT' => ($row['post_subject'] != '') ? $row['post_subject'] : $user->lang['NO_SUBJECT'],
'TOPIC_TITLE' => $row['topic_title'],
@@ -424,578 +536,693 @@ class mcp_queue
// Now display the page
$template->assign_vars(array(
- 'L_DISPLAY_ITEMS' => ($mode == 'unapproved_posts') ? $user->lang['DISPLAY_POSTS'] : $user->lang['DISPLAY_TOPICS'],
- 'L_EXPLAIN' => ($mode == 'unapproved_posts') ? $user->lang['MCP_QUEUE_UNAPPROVED_POSTS_EXPLAIN'] : $user->lang['MCP_QUEUE_UNAPPROVED_TOPICS_EXPLAIN'],
- 'L_TITLE' => ($mode == 'unapproved_posts') ? $user->lang['MCP_QUEUE_UNAPPROVED_POSTS'] : $user->lang['MCP_QUEUE_UNAPPROVED_TOPICS'],
+ 'L_DISPLAY_ITEMS' => (!$is_topics) ? $user->lang['DISPLAY_POSTS'] : $user->lang['DISPLAY_TOPICS'],
+ 'L_EXPLAIN' => $user->lang['MCP_QUEUE_' . strtoupper($mode) . '_EXPLAIN'],
+ 'L_TITLE' => $user->lang['MCP_QUEUE_' . strtoupper($mode)],
'L_ONLY_TOPIC' => ($topic_id) ? sprintf($user->lang['ONLY_TOPIC'], $topic_info['topic_title']) : '',
'S_FORUM_OPTIONS' => $forum_options,
'S_MCP_ACTION' => build_url(array('t', 'f', 'sd', 'st', 'sk')),
- 'S_TOPICS' => ($mode == 'unapproved_posts') ? false : true,
+ 'S_TOPICS' => $is_topics,
+ 'S_RESTORE' => $is_restore,
'PAGE_NUMBER' => phpbb_on_page($template, $user, $base_url, $total, $config['topics_per_page'], $start),
'TOPIC_ID' => $topic_id,
- 'TOTAL' => $user->lang((($mode == 'unapproved_posts') ? 'VIEW_TOPIC_POSTS' : 'VIEW_FORUM_TOPICS'), (int) $total),
+ 'TOTAL' => $user->lang(((!$is_topics) ? 'VIEW_TOPIC_POSTS' : 'VIEW_FORUM_TOPICS'), (int) $total),
));
$this->tpl_name = 'mcp_queue';
break;
}
}
-}
-/**
-* Approve Post/Topic
-*/
-function approve_post($post_id_list, $id, $mode)
-{
- global $db, $template, $user, $config;
- global $phpEx, $phpbb_root_path;
- global $request;
-
- if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_approve')))
+ /**
+ * Approve/Restore posts
+ *
+ * @param $action string Action we perform on the posts ('approve' or 'restore')
+ * @param $post_id_list array IDs of the posts to approve/restore
+ * @param $id mixed Category of the current active module
+ * @param $mode string Active module
+ * @return null
+ */
+ static public function approve_posts($action, $post_id_list, $id, $mode)
{
- trigger_error('NOT_AUTHORISED');
- }
+ global $db, $template, $user, $config, $request, $phpbb_container;
+ global $phpEx, $phpbb_root_path;
- $redirect = request_var('redirect', build_url(array('quickmod')));
- $success_msg = '';
+ if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_approve')))
+ {
+ trigger_error('NOT_AUTHORISED');
+ }
- $s_hidden_fields = build_hidden_fields(array(
- 'i' => $id,
- 'mode' => $mode,
- 'post_id_list' => $post_id_list,
- 'action' => 'approve',
- 'redirect' => $redirect)
- );
+ $redirect = $request->variable('redirect', build_url(array('quickmod')));
+ $success_msg = $post_url = '';
+ $approve_log = array();
- $post_info = get_post_data($post_id_list, 'm_approve');
+ $s_hidden_fields = build_hidden_fields(array(
+ 'i' => $id,
+ 'mode' => $mode,
+ 'post_id_list' => $post_id_list,
+ 'action' => $action,
+ 'redirect' => $redirect,
+ ));
- if (confirm_box(true))
- {
- $notify_poster = (isset($_REQUEST['notify_poster'])) ? true : false;
+ $post_info = get_post_data($post_id_list, 'm_approve');
- // If Topic -> total_topics = total_topics+1, total_posts = total_posts+1, forum_topics = forum_topics+1, forum_posts = forum_posts+1
- // If Post -> total_posts = total_posts+1, forum_posts = forum_posts+1, topic_replies = topic_replies+1
+ if (confirm_box(true))
+ {
+ $notify_poster = ($action == 'approve' && isset($_REQUEST['notify_poster']));
- $total_topics = $total_posts = 0;
- $topic_approve_sql = $post_approve_sql = $topic_id_list = $forum_id_list = $approve_log = array();
- $user_posts_sql = $post_approved_list = array();
+ $topic_info = array();
- foreach ($post_info as $post_id => $post_data)
- {
- if ($post_data['post_approved'])
+ // Group the posts by topic_id
+ foreach ($post_info as $post_id => $post_data)
{
- $post_approved_list[] = $post_id;
- continue;
- }
+ if ($post_data['post_visibility'] == ITEM_APPROVED)
+ {
+ continue;
+ }
+ $topic_id = (int) $post_data['topic_id'];
- $topic_id_list[$post_data['topic_id']] = 1;
- $forum_id_list[$post_data['forum_id']] = 1;
+ $topic_info[$topic_id]['posts'][] = (int) $post_id;
+ $topic_info[$topic_id]['forum_id'] = (int) $post_data['forum_id'];
- // User post update (we do not care about topic or post, since user posts are strictly connected to posts)
- // But we care about forums where post counts get not increased. ;)
- if ($post_data['post_postcount'])
- {
- $user_posts_sql[$post_data['poster_id']] = (empty($user_posts_sql[$post_data['poster_id']])) ? 1 : $user_posts_sql[$post_data['poster_id']] + 1;
- }
+ // Refresh the first post, if the time or id is older then the current one
+ if ($post_id <= $post_data['topic_first_post_id'] || $post_data['post_time'] <= $post_data['topic_time'])
+ {
+ $topic_info[$topic_id]['first_post'] = true;
+ }
- // Topic or Post. ;)
- if ($post_data['topic_first_post_id'] == $post_id)
- {
- $total_topics++;
- $topic_approve_sql[] = $post_data['topic_id'];
+ // Refresh the last post, if the time or id is newer then the current one
+ if ($post_id >= $post_data['topic_last_post_id'] || $post_data['post_time'] >= $post_data['topic_last_post_time'])
+ {
+ $topic_info[$topic_id]['last_post'] = true;
+ }
+
+ $post_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f={$post_data['forum_id']}&amp;t={$post_data['topic_id']}&amp;p={$post_data['post_id']}") . '#p' . $post_data['post_id'];
$approve_log[] = array(
- 'type' => 'topic',
- 'post_subject' => $post_data['post_subject'],
'forum_id' => $post_data['forum_id'],
'topic_id' => $post_data['topic_id'],
+ 'post_subject' => $post_data['post_subject'],
);
}
- else
+
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+ foreach ($topic_info as $topic_id => $topic_data)
{
- $approve_log[] = array(
- 'type' => 'post',
- 'post_subject' => $post_data['post_subject'],
- 'forum_id' => $post_data['forum_id'],
- 'topic_id' => $post_data['topic_id'],
- );
+ $phpbb_content_visibility->set_post_visibility(ITEM_APPROVED, $topic_data['posts'], $topic_id, $topic_data['forum_id'], $user->data['user_id'], time(), '', isset($topic_data['first_post']), isset($topic_data['last_post']));
}
- $total_posts++;
+ if (sizeof($post_info) >= 1)
+ {
+ $success_msg = (sizeof($post_info) == 1) ? 'POST_' . strtoupper($action) . 'D_SUCCESS' : 'POSTS_' . strtoupper($action) . 'D_SUCCESS';
+ }
- // 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'])
+ foreach ($approve_log as $log_data)
{
- $total_posts += $post_data['topic_replies'];
+ add_log('mod', $log_data['forum_id'], $log_data['topic_id'], 'LOG_POST_' . strtoupper($action) . 'D', $log_data['post_subject']);
}
- $post_approve_sql[] = $post_id;
- }
+ // Only send out the mails, when the posts are being approved
+ if ($action == 'approve')
+ {
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
- $post_id_list = array_values(array_diff($post_id_list, $post_approved_list));
- for ($i = 0, $size = sizeof($post_approved_list); $i < $size; $i++)
- {
- unset($post_info[$post_approved_list[$i]]);
- }
+ // Handle notifications
+ foreach ($post_info as $post_id => $post_data)
+ {
+ $phpbb_notifications->delete_notifications('post_in_queue', $post_id);
+
+ $phpbb_notifications->add_notifications(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ ), $post_data);
+
+ $phpbb_notifications->mark_notifications_read(array(
+ 'quote',
+ 'bookmark',
+ 'post',
+ ), $post_data['post_id'], $user->data['user_id']);
+
+ // Notify Poster?
+ if ($notify_poster)
+ {
+ if ($post_data['poster_id'] == ANONYMOUS)
+ {
+ continue;
+ }
- if (sizeof($topic_approve_sql))
- {
- $sql = 'UPDATE ' . TOPICS_TABLE . '
- SET topic_approved = 1
- WHERE ' . $db->sql_in_set('topic_id', $topic_approve_sql);
- $db->sql_query($sql);
+ $phpbb_notifications->add_notifications('approve_post', $post_data);
+ }
+ }
+ }
}
-
- if (sizeof($post_approve_sql))
+ else
{
- $sql = 'UPDATE ' . POSTS_TABLE . '
- SET post_approved = 1
- WHERE ' . $db->sql_in_set('post_id', $post_approve_sql);
- $db->sql_query($sql);
+ $show_notify = false;
+
+ if ($action == 'approve')
+ {
+ foreach ($post_info as $post_data)
+ {
+ if ($post_data['poster_id'] == ANONYMOUS)
+ {
+ continue;
+ }
+ else
+ {
+ $show_notify = true;
+ break;
+ }
+ }
+ }
+
+ $template->assign_vars(array(
+ 'S_NOTIFY_POSTER' => $show_notify,
+ 'S_' . strtoupper($action) => true,
+ ));
+
+ confirm_box(false, strtoupper($action) . '_POST' . ((sizeof($post_id_list) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_approve.html');
}
- unset($topic_approve_sql, $post_approve_sql);
+ $redirect = $request->variable('redirect', "index.$phpEx");
+ $redirect = reapply_sid($redirect);
- foreach ($approve_log as $log_data)
+ if (!$success_msg)
{
- 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']);
+ redirect($redirect);
}
-
- if (sizeof($user_posts_sql))
+ else
{
- // Try to minimize the query count by merging users with the same post count additions
- $user_posts_update = array();
+ meta_refresh(3, $redirect);
- foreach ($user_posts_sql as $user_id => $user_posts)
+ // If approving one post, also give links back to post...
+ $add_message = '';
+ if (sizeof($post_info) == 1 && $post_url)
{
- $user_posts_update[$user_posts][] = $user_id;
+ $add_message = '<br /><br />' . sprintf($user->lang['RETURN_POST'], '<a href="' . $post_url . '">', '</a>');
}
- foreach ($user_posts_update as $user_posts => $user_id_ary)
+ $message = $user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>') . $add_message;
+
+ if ($request->is_ajax())
{
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_posts = user_posts + ' . $user_posts . '
- WHERE ' . $db->sql_in_set('user_id', $user_id_ary);
- $db->sql_query($sql);
+ $json_response = new phpbb_json_response;
+ $json_response->send(array(
+ 'MESSAGE_TITLE' => $user->lang['INFORMATION'],
+ 'MESSAGE_TEXT' => $message,
+ 'REFRESH_DATA' => null,
+ 'visible' => true,
+ ));
}
- }
- if ($total_topics)
- {
- set_config_count('num_topics', $total_topics, true);
+ trigger_error($message);
}
+ }
- if ($total_posts)
+ /**
+ * Approve/Restore topics
+ *
+ * @param $action string Action we perform on the posts ('approve' or 'restore')
+ * @param $topic_id_list array IDs of the topics to approve/restore
+ * @param $id mixed Category of the current active module
+ * @param $mode string Active module
+ * @return null
+ */
+ static public function approve_topics($action, $topic_id_list, $id, $mode)
+ {
+ global $db, $template, $user, $config;
+ global $phpEx, $phpbb_root_path, $request, $phpbb_container;
+
+ if (!check_ids($topic_id_list, TOPICS_TABLE, 'topic_id', array('m_approve')))
{
- set_config_count('num_posts', $total_posts, true);
+ trigger_error('NOT_AUTHORISED');
}
- 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);
+ $redirect = $request->variable('redirect', build_url(array('quickmod')));
+ $success_msg = $topic_url = '';
+ $approve_log = array();
- $messenger = new messenger();
+ $s_hidden_fields = build_hidden_fields(array(
+ 'i' => $id,
+ 'mode' => $mode,
+ 'topic_id_list' => $topic_id_list,
+ 'action' => $action,
+ 'redirect' => $redirect,
+ ));
- // Notify Poster?
- if ($notify_poster)
- {
- foreach ($post_info as $post_id => $post_data)
- {
- if ($post_data['poster_id'] == ANONYMOUS)
- {
- continue;
- }
-
- $email_template = ($post_data['post_id'] == $post_data['topic_first_post_id'] && $post_data['post_id'] == $post_data['topic_last_post_id']) ? 'topic_approved' : 'post_approved';
+ $topic_info = get_topic_data($topic_id_list, 'm_approve');
- $messenger->template($email_template, $post_data['user_lang']);
+ if (confirm_box(true))
+ {
+ $notify_poster = ($action == 'approve' && isset($_REQUEST['notify_poster'])) ? true : false;
- $messenger->to($post_data['user_email'], $post_data['username']);
- $messenger->im($post_data['user_jabber'], $post_data['username']);
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+ foreach ($topic_info as $topic_id => $topic_data)
+ {
+ $phpbb_content_visibility->set_topic_visibility(ITEM_APPROVED, $topic_id, $topic_data['forum_id'], $user->data['user_id'], time(), '');
- $messenger->assign_vars(array(
- 'USERNAME' => htmlspecialchars_decode($post_data['username']),
- 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_data['post_subject'])),
- 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_data['topic_title'])),
+ $topic_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f={$topic_data['forum_id']}&amp;t={$topic_id}");
- 'U_VIEW_TOPIC' => generate_board_url() . "/viewtopic.$phpEx?f={$post_data['forum_id']}&t={$post_data['topic_id']}&e=0",
- 'U_VIEW_POST' => generate_board_url() . "/viewtopic.$phpEx?f={$post_data['forum_id']}&t={$post_data['topic_id']}&p=$post_id&e=$post_id")
+ $approve_log[] = array(
+ 'forum_id' => $topic_data['forum_id'],
+ 'topic_id' => $topic_data['topic_id'],
+ 'topic_title' => $topic_data['topic_title'],
);
-
- $messenger->send($post_data['user_notify_type']);
}
- }
-
- $messenger->save_queue();
- // Send out normal user notifications
- $email_sig = str_replace('<br />', "\n", "-- \n" . $config['board_email_sig']);
-
- foreach ($post_info as $post_id => $post_data)
- {
- if ($post_id == $post_data['topic_first_post_id'] && $post_id == $post_data['topic_last_post_id'])
+ if (sizeof($topic_info) >= 1)
{
- // Forum Notifications
- user_notification('post', $post_data['topic_title'], $post_data['topic_title'], $post_data['forum_name'], $post_data['forum_id'], $post_data['topic_id'], $post_id);
+ $success_msg = (sizeof($topic_info) == 1) ? 'TOPIC_' . strtoupper($action) . 'D_SUCCESS' : 'TOPICS_' . strtoupper($action) . 'D_SUCCESS';
}
- else
+
+ foreach ($approve_log as $log_data)
{
- // Topic Notifications
- user_notification('reply', $post_data['post_subject'], $post_data['topic_title'], $post_data['forum_name'], $post_data['forum_id'], $post_data['topic_id'], $post_id);
+ add_log('mod', $log_data['forum_id'], $log_data['topic_id'], 'LOG_TOPIC_' . strtoupper($action) . 'D', $log_data['topic_title']);
}
- }
- if (sizeof($post_id_list) == 1)
- {
- $post_data = $post_info[$post_id_list[0]];
- $post_url = append_sid("{$phpbb_root_path}viewtopic.$phpEx", "f={$post_data['forum_id']}&amp;t={$post_data['topic_id']}&amp;p={$post_data['post_id']}") . '#p' . $post_data['post_id'];
- }
- unset($post_info);
+ // Only send out the mails, when the posts are being approved
+ if ($action == 'approve')
+ {
+ // Handle notifications
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
- if ($total_topics)
- {
- $success_msg = ($total_topics == 1) ? 'TOPIC_APPROVED_SUCCESS' : 'TOPICS_APPROVED_SUCCESS';
+ foreach ($topic_info as $topic_id => $topic_data)
+ {
+ $phpbb_notifications->delete_notifications('topic_in_queue', $post_data['topic_id']);
+ $phpbb_notifications->add_notifications(array(
+ 'quote',
+ 'topic',
+ ), $post_data);
+
+ $phpbb_notifications->mark_notifications_read('quote', $post_data['post_id'], $user->data['user_id']);
+ $phpbb_notifications->mark_notifications_read('topic', $post_data['topic_id'], $user->data['user_id']);
+
+ if ($notify_poster)
+ {
+ $phpbb_notifications->add_notifications('approve_topic', $post_data);
+ }
+ }
+ }
}
else
{
- $success_msg = (sizeof($post_id_list) + sizeof($post_approved_list) == 1) ? 'POST_APPROVED_SUCCESS' : 'POSTS_APPROVED_SUCCESS';
- }
- }
- else
- {
- $show_notify = false;
+ $show_notify = false;
- if ($config['email_enable'] || $config['jab_enable'])
- {
- foreach ($post_info as $post_data)
+ if ($action == 'approve')
{
- if ($post_data['poster_id'] == ANONYMOUS)
+ foreach ($topic_info as $topic_data)
{
- continue;
- }
- else
- {
- $show_notify = true;
- break;
+ if ($topic_data['topic_poster'] == ANONYMOUS)
+ {
+ continue;
+ }
+ else
+ {
+ $show_notify = true;
+ break;
+ }
}
}
- }
- $template->assign_vars(array(
- 'S_NOTIFY_POSTER' => $show_notify,
- 'S_APPROVE' => true)
- );
+ $template->assign_vars(array(
+ 'S_NOTIFY_POSTER' => $show_notify,
+ 'S_' . strtoupper($action) => true,
+ ));
- confirm_box(false, 'APPROVE_POST' . ((sizeof($post_id_list) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_approve.html');
- }
+ confirm_box(false, strtoupper($action) . '_TOPIC' . ((sizeof($topic_id_list) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_approve.html');
+ }
- $redirect = request_var('redirect', "index.$phpEx");
- $redirect = reapply_sid($redirect);
+ $redirect = $request->variable('redirect', "index.$phpEx");
+ $redirect = reapply_sid($redirect);
- if (!$success_msg)
- {
- redirect($redirect);
- }
- else
- {
- meta_refresh(3, $redirect);
-
- // If approving one post, also give links back to post...
- $add_message = '';
- if (sizeof($post_id_list) == 1 && !empty($post_url))
+ if (!$success_msg)
{
- $add_message = '<br /><br />' . sprintf($user->lang['RETURN_POST'], '<a href="' . $post_url . '">', '</a>');
+ redirect($redirect);
}
+ else
+ {
+ meta_refresh(3, $redirect);
- $message = $user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], "<a href=\"$redirect\">", '</a>') . $add_message;
+ // If approving one topic, also give links back to topic...
+ $add_message = '';
+ if (sizeof($topic_info) == 1 && $topic_url)
+ {
+ $add_message = '<br /><br />' . sprintf($user->lang['RETURN_TOPIC'], '<a href="' . $topic_url . '">', '</a>');
+ }
- if ($request->is_ajax())
- {
- $json_response = new phpbb_json_response;
- $json_response->send(array(
- 'MESSAGE_TITLE' => $user->lang['INFORMATION'],
- 'MESSAGE_TEXT' => $message,
- 'REFRESH_DATA' => null,
- 'approved' => true
- ));
- }
+ $message = $user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>') . $add_message;
- trigger_error($message);
- }
-}
+ if ($request->is_ajax())
+ {
+ $json_response = new phpbb_json_response;
+ $json_response->send(array(
+ 'MESSAGE_TITLE' => $user->lang['INFORMATION'],
+ 'MESSAGE_TEXT' => $message,
+ 'REFRESH_DATA' => null,
+ 'visible' => true,
+ ));
+ }
-/**
-* Disapprove Post/Topic
-*/
-function disapprove_post($post_id_list, $id, $mode)
-{
- global $db, $template, $user, $config;
- global $phpEx, $phpbb_root_path;
- global $request;
+ trigger_error($message);
+ }
+ }
- if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_approve')))
+ /**
+ * Disapprove Post
+ *
+ * @param $post_id_list array IDs of the posts to disapprove/delete
+ * @param $id mixed Category of the current active module
+ * @param $mode string Active module
+ * @return null
+ */
+ static public function disapprove_posts($post_id_list, $id, $mode)
{
- trigger_error('NOT_AUTHORISED');
- }
+ global $db, $template, $user, $config, $phpbb_container;
+ global $phpEx, $phpbb_root_path, $request;
- $redirect = request_var('redirect', build_url(array('t', 'mode', 'quickmod')) . "&amp;mode=$mode");
- $reason = utf8_normalize_nfc(request_var('reason', '', true));
- $reason_id = request_var('reason_id', 0);
- $success_msg = $additional_msg = '';
+ if (!check_ids($post_id_list, POSTS_TABLE, 'post_id', array('m_approve')))
+ {
+ trigger_error('NOT_AUTHORISED');
+ }
- $s_hidden_fields = build_hidden_fields(array(
- 'i' => $id,
- 'mode' => $mode,
- 'post_id_list' => $post_id_list,
- 'action' => 'disapprove',
- 'redirect' => $redirect)
- );
+ $redirect = $request->variable('redirect', build_url(array('t', 'mode', 'quickmod')) . "&amp;mode=$mode");
+ $reason = $request->variable('reason', '', true);
+ $reason_id = $request->variable('reason_id', 0);
+ $success_msg = $additional_msg = '';
- $notify_poster = (isset($_REQUEST['notify_poster'])) ? true : false;
- $disapprove_reason = '';
+ $s_hidden_fields = build_hidden_fields(array(
+ 'i' => $id,
+ 'mode' => $mode,
+ 'post_id_list' => $post_id_list,
+ 'action' => 'disapprove',
+ 'redirect' => $redirect,
+ ));
- if ($reason_id)
- {
- $sql = 'SELECT reason_title, reason_description
- FROM ' . REPORTS_REASONS_TABLE . "
- WHERE reason_id = $reason_id";
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if (!$row || (!$reason && strtolower($row['reason_title']) == 'other'))
- {
- $additional_msg = $user->lang['NO_REASON_DISAPPROVAL'];
+ $notify_poster = $request->is_set('notify_poster');
+ $disapprove_reason = '';
- $request->overwrite('confirm', null, phpbb_request_interface::POST);
- $request->overwrite('confirm_key', null, phpbb_request_interface::POST);
- $request->overwrite('confirm_key', null, phpbb_request_interface::REQUEST);
- }
- else
+ if ($reason_id)
{
- // If the reason is defined within the language file, we will use the localized version, else just use the database entry...
- $disapprove_reason = (strtolower($row['reason_title']) != 'other') ? ((isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])])) ? $user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])] : $row['reason_description']) : '';
- $disapprove_reason .= ($reason) ? "\n\n" . $reason : '';
-
- if (isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])]))
+ $sql = 'SELECT reason_title, reason_description
+ FROM ' . REPORTS_REASONS_TABLE . "
+ WHERE reason_id = $reason_id";
+ $result = $db->sql_query($sql);
+ $row = $db->sql_fetchrow($result);
+ $db->sql_freeresult($result);
+
+ if (!$row || (!$reason && strtolower($row['reason_title']) == 'other'))
{
- $disapprove_reason_lang = strtoupper($row['reason_title']);
+ $additional_msg = $user->lang['NO_REASON_DISAPPROVAL'];
+
+ $request->overwrite('confirm', null, phpbb_request_interface::POST);
+ $request->overwrite('confirm_key', null, phpbb_request_interface::POST);
+ $request->overwrite('confirm_key', null, phpbb_request_interface::REQUEST);
}
+ else
+ {
+ // If the reason is defined within the language file, we will use the localized version, else just use the database entry...
+ $disapprove_reason = (strtolower($row['reason_title']) != 'other') ? ((isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])])) ? $user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])] : $row['reason_description']) : '';
+ $disapprove_reason .= ($reason) ? "\n\n" . $reason : '';
- $email_disapprove_reason = $disapprove_reason;
+ if (isset($user->lang['report_reasons']['DESCRIPTION'][strtoupper($row['reason_title'])]))
+ {
+ $disapprove_reason_lang = strtoupper($row['reason_title']);
+ }
+ }
}
- }
- $post_info = get_post_data($post_id_list, 'm_approve');
+ $post_info = get_post_data($post_id_list, 'm_approve');
- if (confirm_box(true))
- {
- $disapprove_log = $disapprove_log_topics = $disapprove_log_posts = array();
- $topic_replies_real = $post_disapprove_list = array();
-
- // Build a list of posts to be unapproved and get the related topics real replies count
+ $is_disapproving = false;
foreach ($post_info as $post_id => $post_data)
{
- $post_disapprove_list[$post_id] = $post_data['topic_id'];
- if (!isset($topic_replies_real[$post_data['topic_id']]))
+ if ($post_data['post_visibility'] == ITEM_DELETED)
{
- $topic_replies_real[$post_data['topic_id']] = $post_data['topic_replies_real'];
+ continue;
}
+
+ $is_disapproving = true;
}
- // Now we build the log array
- foreach ($post_disapprove_list as $post_id => $topic_id)
+ if (confirm_box(true))
{
- // 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])
+ $disapprove_log = $disapprove_log_topics = $disapprove_log_posts = array();
+ $topic_posts_unapproved = $post_disapprove_list = $topic_information = array();
+
+ // Build a list of posts to be disapproved and get the related topics real replies count
+ foreach ($post_info as $post_id => $post_data)
{
- // Don't write the log more than once for every topic
- if (!isset($disapprove_log_topics[$topic_id]))
+ $post_disapprove_list[$post_id] = $post_data['topic_id'];
+ if (!isset($topic_posts_unapproved[$post_data['topic_id']]))
{
- // 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
- );
+ $topic_information[$post_data['topic_id']] = $post_data;
+ $topic_posts_unapproved[$post_data['topic_id']] = 0;
}
+ $topic_posts_unapproved[$post_data['topic_id']]++;
}
- else
+
+ // Now we build the log array
+ foreach ($post_disapprove_list as $post_id => $topic_id)
{
- // Build disapproved posts log
- $disapprove_log_posts[] = array(
- 'type' => 'post',
- 'post_subject' => $post_info[$post_id]['post_subject'],
- 'forum_id' => $post_info[$post_id]['forum_id'],
- 'topic_id' => $post_info[$post_id]['topic_id'],
- );
+ // If the count of disapproved posts for the topic is equal
+ // to the number of unapproved posts in the topic, and there are no different
+ // posts, we disapprove the hole topic
+ if ($topic_information[$topic_id]['topic_posts_approved'] == 0 &&
+ $topic_information[$topic_id]['topic_posts_softdeleted'] == 0 &&
+ $topic_information[$topic_id]['topic_posts_unapproved'] == $topic_posts_unapproved[$topic_id])
+ {
+ // Don't write the log more than once for every topic
+ if (!isset($disapprove_log_topics[$topic_id]))
+ {
+ // 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
+ 'post_username' => ($post_info[$post_id]['poster_id'] == ANONYMOUS && !empty($post_info[$post_id]['post_username'])) ? $post_info[$post_id]['post_username'] : $post_info[$post_id]['username'],
+ );
+ }
+ }
+ else
+ {
+ // Build disapproved posts log
+ $disapprove_log_posts[] = array(
+ 'type' => 'post',
+ '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_username' => ($post_info[$post_id]['poster_id'] == ANONYMOUS && !empty($post_info[$post_id]['post_username'])) ? $post_info[$post_id]['post_username'] : $post_info[$post_id]['username'],
+ );
+ }
}
- }
- // Get disapproved posts/topics counts separately
- $num_disapproved_topics = sizeof($disapprove_log_topics);
- $num_disapproved_posts = sizeof($disapprove_log_posts);
+ // Get disapproved posts/topics counts separately
+ $num_disapproved_topics = sizeof($disapprove_log_topics);
+ $num_disapproved_posts = sizeof($disapprove_log_posts);
- // Build the whole log
- $disapprove_log = array_merge($disapprove_log_topics, $disapprove_log_posts);
+ // 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);
+ // 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'))
+ // Let's do the job - delete disapproved posts
+ if (sizeof($post_disapprove_list))
{
- include_once($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
- }
+ if (!function_exists('delete_posts'))
+ {
+ include($phpbb_root_path . 'includes/functions_admin.' . $phpEx);
+ }
- // We do not check for permissions here, because the moderator allowed approval/disapproval should be allowed to delete the disapproved posts
- // 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));
+ // We do not check for permissions here, because the moderator allowed approval/disapproval should be allowed to delete the disapproved posts
+ // 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);
+ foreach ($disapprove_log as $log_data)
+ {
+ if ($is_disapproving)
+ {
+ $l_log_message = ($log_data['type'] == 'topic') ? 'LOG_TOPIC_DISAPPROVED' : 'LOG_POST_DISAPPROVED';
+ add_log('mod', $log_data['forum_id'], $log_data['topic_id'], $l_log_message, $log_data['post_subject'], $disapprove_reason);
+ }
+ else
+ {
+ $l_log_message = ($log_data['type'] == 'topic') ? 'LOG_DELETE_TOPIC' : 'LOG_DELETE_POST';
+ add_log('mod', $log_data['forum_id'], $log_data['topic_id'], $l_log_message, $log_data['post_subject'], $log_data['post_username']);
+ }
+ }
}
- }
- $messenger = new messenger();
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
- // Notify Poster?
- if ($notify_poster)
- {
$lang_reasons = array();
foreach ($post_info as $post_id => $post_data)
{
- if ($post_data['poster_id'] == ANONYMOUS)
+ $disapprove_all_posts_in_topic = $topic_information[$topic_id]['topic_posts_approved'] == 0 &&
+ $topic_information[$topic_id]['topic_posts_softdeleted'] == 0 &&
+ $topic_information[$topic_id]['topic_posts_unapproved'] == $topic_posts_unapproved[$topic_id];
+
+ $phpbb_notifications->delete_notifications('post_in_queue', $post_id);
+
+ // Do we disapprove the whole topic? Remove potential notifications
+ if ($disapprove_all_posts_in_topic)
{
- continue;
+ $phpbb_notifications->delete_notifications('topic_in_queue', $post_data['topic_id']);
}
- if (isset($disapprove_reason_lang))
+ // Notify Poster?
+ if ($notify_poster)
{
- // Okay we need to get the reason from the posters language
- if (!isset($lang_reasons[$post_data['user_lang']]))
+ if ($post_data['poster_id'] == ANONYMOUS)
{
- // Assign the current users translation as the default, this is not ideal but getting the board default adds another layer of complexity.
- $lang_reasons[$post_data['user_lang']] = $user->lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang];
+ continue;
+ }
- // Only load up the language pack if the language is different to the current one
- if ($post_data['user_lang'] != $user->lang_name && file_exists($phpbb_root_path . '/language/' . $post_data['user_lang'] . '/mcp.' . $phpEx))
+ $post_data['disapprove_reason'] = '';
+ if (isset($disapprove_reason_lang))
+ {
+ // Okay we need to get the reason from the posters language
+ if (!isset($lang_reasons[$post_data['user_lang']]))
{
- // Load up the language pack
- $lang = array();
- @include($phpbb_root_path . '/language/' . basename($post_data['user_lang']) . '/mcp.' . $phpEx);
+ // Assign the current users translation as the default, this is not ideal but getting the board default adds another layer of complexity.
+ $lang_reasons[$post_data['user_lang']] = $user->lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang];
- // If we find the reason in this language pack use it
- if (isset($lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang]))
+ // Only load up the language pack if the language is different to the current one
+ if ($post_data['user_lang'] != $user->lang_name && file_exists($phpbb_root_path . '/language/' . $post_data['user_lang'] . '/mcp.' . $phpEx))
{
- $lang_reasons[$post_data['user_lang']] = $lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang];
- }
+ // Load up the language pack
+ $lang = array();
+ @include($phpbb_root_path . '/language/' . basename($post_data['user_lang']) . '/mcp.' . $phpEx);
- unset($lang); // Free memory
+ // If we find the reason in this language pack use it
+ if (isset($lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang]))
+ {
+ $lang_reasons[$post_data['user_lang']] = $lang['report_reasons']['DESCRIPTION'][$disapprove_reason_lang];
+ }
+
+ unset($lang); // Free memory
+ }
}
- }
- $email_disapprove_reason = $lang_reasons[$post_data['user_lang']];
- $email_disapprove_reason .= ($reason) ? "\n\n" . $reason : '';
- }
+ $post_data['disapprove_reason'] = $lang_reasons[$post_data['user_lang']];
+ $post_data['disapprove_reason'] .= ($reason) ? "\n\n" . $reason : '';
+ }
- $email_template = ($post_data['post_id'] == $post_data['topic_first_post_id'] && $post_data['post_id'] == $post_data['topic_last_post_id']) ? 'topic_disapproved' : 'post_disapproved';
- $messenger->template($email_template, $post_data['user_lang']);
+ if ($disapprove_all_posts_in_topic && $topic_information[$topic_id]['topic_posts_unapproved'] == 1)
+ {
+ // If there is only 1 post when disapproving the topic,
+ // we send the user a "disapprove topic" notification...
+ $phpbb_notifications->add_notifications('disapprove_topic', $post_data);
+ }
+ else
+ {
+ // ... otherwise there are multiple unapproved posts and
+ // all of them are disapproved as posts.
+ $phpbb_notifications->add_notifications('disapprove_post', $post_data);
+ }
+ }
+ }
- $messenger->to($post_data['user_email'], $post_data['username']);
- $messenger->im($post_data['user_jabber'], $post_data['username']);
+ unset($lang_reasons, $post_info, $disapprove_reason, $disapprove_reason_lang);
- $messenger->assign_vars(array(
- 'USERNAME' => htmlspecialchars_decode($post_data['username']),
- 'REASON' => htmlspecialchars_decode($email_disapprove_reason),
- 'POST_SUBJECT' => htmlspecialchars_decode(censor_text($post_data['post_subject'])),
- 'TOPIC_TITLE' => htmlspecialchars_decode(censor_text($post_data['topic_title'])))
- );
- $messenger->send($post_data['user_notify_type']);
+ if ($num_disapproved_topics)
+ {
+ $success_msg = ($num_disapproved_topics == 1) ? 'TOPIC' : 'TOPICS';
+ }
+ else
+ {
+ $success_msg = ($num_disapproved_posts == 1) ? 'POST' : 'POSTS';
}
- unset($lang_reasons);
- }
- unset($post_info, $disapprove_reason, $email_disapprove_reason, $disapprove_reason_lang);
-
- $messenger->save_queue();
-
- if ($num_disapproved_topics)
- {
- $success_msg = ($num_disapproved_topics == 1) ? 'TOPIC_DISAPPROVED_SUCCESS' : 'TOPICS_DISAPPROVED_SUCCESS';
+ if ($is_disapproving)
+ {
+ $success_msg .= '_DISAPPROVED_SUCCESS';
+ }
+ else
+ {
+ $success_msg .= '_DELETED_SUCCESS';
+ }
}
else
{
- $success_msg = ($num_disapproved_posts == 1) ? 'POST_DISAPPROVED_SUCCESS' : 'POSTS_DISAPPROVED_SUCCESS';
- }
- }
- else
- {
- include_once($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ if (!function_exists('display_reasons'))
+ {
+ include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ }
- display_reasons($reason_id);
+ $show_notify = false;
- $show_notify = false;
+ foreach ($post_info as $post_data)
+ {
+ if ($post_data['poster_id'] == ANONYMOUS)
+ {
+ continue;
+ }
+ else
+ {
+ $show_notify = true;
+ break;
+ }
+ }
- foreach ($post_info as $post_data)
- {
- if ($post_data['poster_id'] == ANONYMOUS)
+ $l_confirm_msg = 'DISAPPROVE_POST';
+ $confirm_template = 'mcp_approve.html';
+ if ($is_disapproving)
{
- continue;
+ display_reasons($reason_id);
}
else
{
- $show_notify = true;
- break;
- }
- }
+ $user->add_lang('posting');
- $template->assign_vars(array(
- 'S_NOTIFY_POSTER' => $show_notify,
- 'S_APPROVE' => false,
- 'REASON' => $reason,
- 'ADDITIONAL_MSG' => $additional_msg)
- );
+ $l_confirm_msg = 'DELETE_POST_PERMANENTLY';
+ $confirm_template = 'confirm_delete_body.html';
+ }
+ $l_confirm_msg .= ((sizeof($post_id_list) == 1) ? '' : 'S');
- confirm_box(false, 'DISAPPROVE_POST' . ((sizeof($post_id_list) == 1) ? '' : 'S'), $s_hidden_fields, 'mcp_approve.html');
- }
+ $template->assign_vars(array(
+ 'S_NOTIFY_POSTER' => $show_notify,
+ 'S_APPROVE' => false,
+ 'REASON' => ($is_disapproving) ? $reason : '',
+ 'ADDITIONAL_MSG' => $additional_msg,
+ ));
- $redirect = request_var('redirect', "index.$phpEx");
- $redirect = reapply_sid($redirect);
+ confirm_box(false, $l_confirm_msg, $s_hidden_fields, $confirm_template);
+ }
- if (!$success_msg)
- {
- redirect($redirect);
- }
- else
- {
- $message = $user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], "<a href=\"$redirect\">", '</a>');
+ $redirect = $request->variable('redirect', "index.$phpEx");
+ $redirect = reapply_sid($redirect);
- if ($request->is_ajax())
+ if (!$success_msg)
{
- $json_response = new phpbb_json_response;
- $json_response->send(array(
- 'MESSAGE_TITLE' => $user->lang['INFORMATION'],
- 'MESSAGE_TEXT' => $message,
- 'REFRESH_DATA' => null,
- 'approved' => false
- ));
+ redirect($redirect);
}
+ else
+ {
+ $message = $user->lang[$success_msg] . '<br /><br />' . sprintf($user->lang['RETURN_PAGE'], '<a href="' . $redirect . '">', '</a>');
- meta_refresh(3, $redirect);
- trigger_error($message);
+ if ($request->is_ajax())
+ {
+ $json_response = new phpbb_json_response;
+ $json_response->send(array(
+ 'MESSAGE_TITLE' => $user->lang['INFORMATION'],
+ 'MESSAGE_TEXT' => $message,
+ 'REFRESH_DATA' => null,
+ 'visible' => false,
+ ));
+ }
+
+ meta_refresh(3, $redirect);
+ trigger_error($message);
+ }
}
}
diff --git a/phpBB/includes/mcp/mcp_reports.php b/phpBB/includes/mcp/mcp_reports.php
index 3426d62cdb..3f48c58073 100644
--- a/phpBB/includes/mcp/mcp_reports.php
+++ b/phpBB/includes/mcp/mcp_reports.php
@@ -33,7 +33,7 @@ class mcp_reports
function main($id, $mode)
{
global $auth, $db, $user, $template, $cache;
- global $config, $phpbb_root_path, $phpEx, $action;
+ global $config, $phpbb_root_path, $phpEx, $action, $phpbb_container;
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
@@ -71,7 +71,7 @@ class mcp_reports
// closed reports are accessed by report id
$report_id = request_var('r', 0);
- $sql = 'SELECT r.post_id, r.user_id, r.report_id, r.report_closed, report_time, r.report_text, r.reported_post_text, r.reported_post_uid, r.reported_post_bitfield, rr.reason_title, rr.reason_description, u.username, u.username_clean, u.user_colour
+ $sql = 'SELECT r.post_id, r.user_id, r.report_id, r.report_closed, report_time, r.report_text, r.reported_post_text, r.reported_post_uid, r.reported_post_bitfield, r.reported_post_enable_magic_url, r.reported_post_enable_smilies, r.reported_post_enable_bbcode, 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 ' . (($report_id) ? 'r.report_id = ' . $report_id : "r.post_id = $post_id") . '
AND rr.reason_id = r.reason_id
@@ -87,6 +87,10 @@ class mcp_reports
trigger_error('NO_REPORT');
}
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ $phpbb_notifications->mark_notifications_read('report_post', $post_id, $user->data['user_id']);
+
if (!$report_id && $report['report_closed'])
{
trigger_error('REPORT_CLOSED');
@@ -94,6 +98,10 @@ class mcp_reports
$post_id = $report['post_id'];
$report_id = $report['report_id'];
+
+ $parse_post_flags = $report['reported_post_enable_bbcode'] ? OPTION_FLAG_BBCODE : 0;
+ $parse_post_flags += $report['reported_post_enable_smilies'] ? OPTION_FLAG_SMILIES : 0;
+ $parse_post_flags += $report['reported_post_enable_magic_url'] ? OPTION_FLAG_LINKS : 0;
$post_info = get_post_data(array($post_id), 'm_report', true);
@@ -136,18 +144,7 @@ class mcp_reports
$post_unread = (isset($topic_tracking_info[$post_info['topic_id']]) && $post_info['post_time'] > $topic_tracking_info[$post_info['topic_id']]) ? true : false;
- // Process message, leave it uncensored
- $message = $post_info['post_text'];
- if ($post_info['bbcode_bitfield'])
- {
- include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx);
- $bbcode = new bbcode($post_info['bbcode_bitfield']);
- $bbcode->bbcode_second_pass($message, $post_info['bbcode_uid'], $post_info['bbcode_bitfield']);
- }
-
- $message = bbcode_nl2br($message);
- $message = smiley_text($message);
$report['report_text'] = make_clickable(bbcode_nl2br($report['report_text']));
if ($post_info['post_attachment'] && $auth->acl_get('u_download') && $auth->acl_get('f_download', $post_info['forum_id']))
@@ -168,7 +165,7 @@ class mcp_reports
if (sizeof($attachments))
{
$update_count = array();
- parse_attachments($post_info['forum_id'], $message, $attachments, $update_count);
+ parse_attachments($post_info['forum_id'], $report['reported_post_text'], $attachments, $update_count);
}
// Display not already displayed Attachments for this post, we already parsed them. ;)
@@ -190,7 +187,7 @@ class mcp_reports
'S_CLOSE_ACTION' => append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=reports&amp;mode=report_details&amp;f=' . $post_info['forum_id'] . '&amp;p=' . $post_id),
'S_CAN_VIEWIP' => $auth->acl_get('m_info', $post_info['forum_id']),
'S_POST_REPORTED' => $post_info['post_reported'],
- 'S_POST_UNAPPROVED' => !$post_info['post_approved'],
+ 'S_POST_UNAPPROVED' => ($post_info['post_visibility'] == ITEM_UNAPPROVED),
'S_POST_LOCKED' => $post_info['post_edit_locked'],
'S_USER_NOTES' => true,
@@ -227,7 +224,7 @@ class mcp_reports
'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' => generate_text_for_display($report['reported_post_text'], $report['reported_post_uid'], $report['reported_post_bitfield'], OPTION_FLAG_BBCODE | OPTION_FLAG_SMILIES, false),
+ 'POST_PREVIEW' => generate_text_for_display($report['reported_post_text'], $report['reported_post_uid'], $report['reported_post_bitfield'], $parse_post_flags, false),
'POST_SUBJECT' => ($post_info['post_subject']) ? $post_info['post_subject'] : $user->lang['NO_SUBJECT'],
'POST_DATE' => $user->format_date($post_info['post_time']),
'POST_IP' => $post_info['poster_ip'],
@@ -295,11 +292,11 @@ class mcp_reports
$global_id = $forum_list[0];
- $sql = 'SELECT SUM(forum_topics) as sum_forum_topics
+ $sql = 'SELECT SUM(forum_topics_approved) as sum_forum_topics
FROM ' . FORUMS_TABLE . '
WHERE ' . $db->sql_in_set('forum_id', $forum_list);
$result = $db->sql_query($sql);
- $forum_info['forum_topics'] = (int) $db->sql_fetchfield('sum_forum_topics');
+ $forum_info['forum_topics_approved'] = (int) $db->sql_fetchfield('sum_forum_topics');
$db->sql_freeresult($result);
}
else
@@ -331,7 +328,7 @@ class mcp_reports
$sort_by_sql = $sort_order_sql = array();
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;
+ $forum_topics = ($total == -1) ? $forum_info['forum_topics_approved'] : $total;
$limit_time_sql = ($sort_days) ? 'AND r.report_time >= ' . (time() - ($sort_days * 86400)) : '';
if ($mode == 'reports')
@@ -443,7 +440,7 @@ class mcp_reports
function close_report($report_id_list, $mode, $action, $pm = false)
{
global $db, $template, $user, $config, $auth;
- global $phpEx, $phpbb_root_path;
+ global $phpEx, $phpbb_root_path, $phpbb_container;
$pm_where = ($pm) ? ' AND r.post_id = 0 ' : ' AND r.pm_id = 0 ';
$id_column = ($pm) ? 'pm_id' : 'post_id';
@@ -629,11 +626,11 @@ function close_report($report_id_list, $mode, $action, $pm = false)
}
}
- $messenger = new messenger();
-
// Notify reporters
if (sizeof($notify_reporters))
{
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
foreach ($notify_reporters as $report_id => $reporter)
{
if ($reporter['user_id'] == ANONYMOUS)
@@ -643,30 +640,25 @@ function close_report($report_id_list, $mode, $action, $pm = false)
$post_id = $reporter[$id_column];
- $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']);
-
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'])),
- ));
+ $phpbb_notifications->add_notifications('report_pm_closed', array_merge($post_info[$post_id], array(
+ 'reporter' => $reporter['user_id'],
+ 'closer_id' => $user->data['user_id'],
+ 'from_user_id' => $post_info[$post_id]['author_id'],
+ )));
+
+ $phpbb_notifications->delete_notifications('report_pm', $post_id);
}
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'])))
- );
- }
+ $phpbb_notifications->add_notifications('report_post_closed', array_merge($post_info[$post_id], array(
+ 'reporter' => $reporter['user_id'],
+ 'closer_id' => $user->data['user_id'],
+ )));
- $messenger->send($reporter['user_notify_type']);
+ $phpbb_notifications->delete_notifications('report_post', $post_id);
+ }
}
}
@@ -681,8 +673,6 @@ function close_report($report_id_list, $mode, $action, $pm = false)
unset($notify_reporters, $post_info, $reports);
- $messenger->save_queue();
-
$success_msg = (sizeof($report_id_list) == 1) ? "{$pm_prefix}REPORT_" . strtoupper($action) . 'D_SUCCESS' : "{$pm_prefix}REPORTS_" . strtoupper($action) . 'D_SUCCESS';
}
else
diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php
index 63ff7bed72..9c294b96c8 100644
--- a/phpBB/includes/mcp/mcp_topic.php
+++ b/phpBB/includes/mcp/mcp_topic.php
@@ -21,7 +21,7 @@ if (!defined('IN_PHPBB'))
function mcp_topic_view($id, $mode, $action)
{
global $phpEx, $phpbb_root_path, $config;
- global $template, $db, $user, $auth, $cache;
+ global $template, $db, $user, $auth, $cache, $phpbb_container;
$url = append_sid("{$phpbb_root_path}mcp.$phpEx?" . extra_url());
@@ -84,8 +84,8 @@ function mcp_topic_view($id, $mode, $action)
$subject = $topic_info['topic_title'];
}
- // Approve posts?
- if ($action == 'approve' && $auth->acl_get('m_approve', $topic_info['forum_id']))
+ // Restore or pprove posts?
+ if (($action == 'restore' || $action == 'approve') && $auth->acl_get('m_approve', $topic_info['forum_id']))
{
include($phpbb_root_path . 'includes/mcp/mcp_queue.' . $phpEx);
include_once($phpbb_root_path . 'includes/functions_posting.' . $phpEx);
@@ -98,7 +98,7 @@ function mcp_topic_view($id, $mode, $action)
if (!$sort)
{
- approve_post($post_id_list, $id, $mode);
+ mcp_queue::approve_posts($action, $post_id_list, $id, $mode);
}
}
@@ -112,17 +112,11 @@ function mcp_topic_view($id, $mode, $action)
mcp_sorting('viewtopic', $sort_days, $sort_key, $sort_dir, $sort_by_sql, $sort_order_sql, $total, $topic_info['forum_id'], $topic_id, $where_sql);
$limit_time_sql = ($sort_days) ? 'AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
if ($total == -1)
{
- if ($auth->acl_get('m_approve', $topic_info['forum_id']))
- {
- $total = $topic_info['topic_replies_real'] + 1;
- }
- else
- {
- $total = $topic_info['topic_replies'] + 1;
- }
+ $total = $phpbb_content_visibility->get_count('topic_posts', $topic_info, $topic_info['forum_id']);
}
$posts_per_page = max(0, request_var('posts_per_page', intval($config['posts_per_page'])));
@@ -145,8 +139,8 @@ function mcp_topic_view($id, $mode, $action)
$sql = 'SELECT u.username, u.username_clean, u.user_colour, p.*
FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
WHERE ' . (($action == 'reports') ? 'p.post_reported = 1 AND ' : '') . '
- p.topic_id = ' . $topic_id . ' ' .
- ((!$auth->acl_get('m_approve', $topic_info['forum_id'])) ? ' AND p.post_approved = 1 ' : '') . '
+ p.topic_id = ' . $topic_id . '
+ AND ' . $phpbb_content_visibility->get_visibility_sql('post', $topic_info['forum_id'], 'p.') . '
AND p.poster_id = u.user_id ' .
$limit_time_sql . '
ORDER BY ' . $sort_order_sql;
@@ -182,7 +176,7 @@ function mcp_topic_view($id, $mode, $action)
$topic_tracking_info = get_complete_topic_tracking($topic_info['forum_id'], $topic_id);
}
- $has_unapproved_posts = false;
+ $has_unapproved_posts = $has_deleted_posts = false;
// Grab extensions
$extensions = $attachments = array();
@@ -213,13 +207,8 @@ function mcp_topic_view($id, $mode, $action)
$message = $row['post_text'];
$post_subject = ($row['post_subject'] != '') ? $row['post_subject'] : $topic_info['topic_title'];
- if ($row['bbcode_bitfield'])
- {
- $bbcode->bbcode_second_pass($message, $row['bbcode_uid'], $row['bbcode_bitfield']);
- }
-
- $message = bbcode_nl2br($message);
- $message = smiley_text($message);
+ $parse_flags = ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
+ $message = generate_text_for_display($message, $row['bbcode_uid'], $row['bbcode_bitfield'], $parse_flags, false);
if (!empty($attachments[$row['post_id']]))
{
@@ -227,11 +216,16 @@ function mcp_topic_view($id, $mode, $action)
parse_attachments($topic_info['forum_id'], $message, $attachments[$row['post_id']], $update_count);
}
- if (!$row['post_approved'])
+ if ($row['post_visibility'] == ITEM_UNAPPROVED)
{
$has_unapproved_posts = true;
}
+ if ($row['post_visibility'] == ITEM_DELETED)
+ {
+ $has_deleted_posts = true;
+ }
+
$post_unread = (isset($topic_tracking_info[$topic_id]) && $row['post_time'] > $topic_tracking_info[$topic_id]) ? true : false;
$template->assign_block_vars('postrow', array(
@@ -249,7 +243,8 @@ function mcp_topic_view($id, $mode, $action)
'MINI_POST_IMG' => ($post_unread) ? $user->img('icon_post_target_unread', 'UNREAD_POST') : $user->img('icon_post_target', 'POST'),
'S_POST_REPORTED' => ($row['post_reported'] && $auth->acl_get('m_report', $topic_info['forum_id'])),
- 'S_POST_UNAPPROVED' => (!$row['post_approved'] && $auth->acl_get('m_approve', $topic_info['forum_id'])),
+ 'S_POST_UNAPPROVED' => ($row['post_visibility'] == ITEM_UNAPPROVED && $auth->acl_get('m_approve', $topic_info['forum_id'])),
+ 'S_POST_DELETED' => ($row['post_visibility'] == ITEM_DELETED && $auth->acl_get('m_approve', $topic_info['forum_id'])),
'S_CHECKED' => (($submitted_id_list && !in_array(intval($row['post_id']), $submitted_id_list)) || in_array(intval($row['post_id']), $checked_ids)) ? true : false,
'S_HAS_ATTACHMENTS' => (!empty($attachments[$row['post_id']])) ? true : false,
@@ -325,6 +320,7 @@ function mcp_topic_view($id, $mode, $action)
'REPORTED_IMG' => $user->img('icon_topic_reported', 'POST_REPORTED'),
'UNAPPROVED_IMG' => $user->img('icon_topic_unapproved', 'POST_UNAPPROVED'),
+ 'DELETED_IMG' => $user->img('icon_topic_deleted', 'POST_DELETED_RESTORE'),
'INFO_IMG' => $user->img('icon_post_info', 'VIEW_INFO'),
'S_MCP_ACTION' => "$url&amp;i=$id&amp;mode=$mode&amp;action=$action&amp;start=$start",
@@ -333,6 +329,7 @@ function mcp_topic_view($id, $mode, $action)
'S_CAN_MERGE' => ($auth->acl_get('m_merge', $topic_info['forum_id'])) ? true : false,
'S_CAN_DELETE' => ($auth->acl_get('m_delete', $topic_info['forum_id'])) ? true : false,
'S_CAN_APPROVE' => ($has_unapproved_posts && $auth->acl_get('m_approve', $topic_info['forum_id'])) ? true : false,
+ 'S_CAN_RESTORE' => ($has_deleted_posts && $auth->acl_get('m_approve', $topic_info['forum_id'])) ? true : false,
'S_CAN_LOCK' => ($auth->acl_get('m_lock', $topic_info['forum_id'])) ? true : false,
'S_CAN_REPORT' => ($auth->acl_get('m_report', $topic_info['forum_id'])) ? true : false,
'S_CAN_SYNC' => $auth->acl_get('m_', $topic_info['forum_id']),
@@ -448,7 +445,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
if ($sort_order_sql[0] == 'u')
{
- $sql = 'SELECT p.post_id, p.forum_id, p.post_approved
+ $sql = 'SELECT p.post_id, p.forum_id, p.post_visibility
FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . " u
WHERE p.topic_id = $topic_id
AND p.poster_id = u.user_id
@@ -457,7 +454,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
}
else
{
- $sql = 'SELECT p.post_id, p.forum_id, p.post_approved
+ $sql = 'SELECT p.post_id, p.forum_id, p.post_visibility
FROM ' . POSTS_TABLE . " p
WHERE p.topic_id = $topic_id
$limit_time_sql
@@ -470,7 +467,7 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
while ($row = $db->sql_fetchrow($result))
{
// If split from selected post (split_beyond), we split the unapproved items too.
- if (!$row['post_approved'] && !$auth->acl_get('m_approve', $row['forum_id']))
+ if ($row['post_visibility'] == ITEM_UNAPPROVED && !$auth->acl_get('m_approve', $row['forum_id']))
{
// continue;
}
@@ -497,10 +494,10 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
$icon_id = request_var('icon', 0);
$sql_ary = array(
- 'forum_id' => $to_forum_id,
- 'topic_title' => $subject,
- 'icon_id' => $icon_id,
- 'topic_approved'=> 1
+ 'forum_id' => $to_forum_id,
+ 'topic_title' => $subject,
+ 'icon_id' => $icon_id,
+ 'topic_visibility' => 1
);
$sql = 'INSERT INTO ' . TOPICS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
@@ -521,6 +518,49 @@ function split_topic($action, $topic_id, $to_forum_id, $subject)
WHERE post_id = {$post_id_list[0]}";
$db->sql_query($sql);
+ // Copy topic subscriptions to new topic
+ $sql = 'SELECT user_id, notify_status
+ FROM ' . TOPICS_WATCH_TABLE . '
+ WHERE topic_id = ' . $topic_id;
+ $result = $db->sql_query($sql);
+
+ $sql_ary = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $sql_ary[] = array(
+ 'topic_id' => (int) $to_topic_id,
+ 'user_id' => (int) $row['user_id'],
+ 'notify_status' => (int) $row['notify_status'],
+ );
+ }
+ $db->sql_freeresult($result);
+
+ if (sizeof($sql_ary))
+ {
+ $db->sql_multi_insert(TOPICS_WATCH_TABLE, $sql_ary);
+ }
+
+ // Copy bookmarks to new topic
+ $sql = 'SELECT user_id
+ FROM ' . BOOKMARKS_TABLE . '
+ WHERE topic_id = ' . $topic_id;
+ $result = $db->sql_query($sql);
+
+ $sql_ary = array();
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $sql_ary[] = array(
+ 'topic_id' => (int) $to_topic_id,
+ 'user_id' => (int) $row['user_id'],
+ );
+ }
+ $db->sql_freeresult($result);
+
+ if (sizeof($sql_ary))
+ {
+ $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary);
+ }
+
$success_msg = 'TOPIC_SPLIT_SUCCESS';
// Update forum statistics
@@ -623,13 +663,16 @@ function merge_posts($topic_id, $to_topic_id)
}
else
{
+ if (!function_exists('phpbb_update_rows_avoiding_duplicates_notify_status'))
+ {
+ include($phpbb_root_path . 'includes/functions_database_helper.' . $phpEx);
+ }
+
// 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...
- $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_return_on_error(false);
+ phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', array($topic_id), $to_topic_id);
- $db->sql_query('DELETE FROM ' . TOPICS_WATCH_TABLE . ' WHERE topic_id = ' . (int) $topic_id);
+ // If the topic no longer exist, we will update the bookmarks table.
+ phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', array($topic_id), $to_topic_id);
}
// Link to the new topic
diff --git a/phpBB/includes/mcp/mcp_warn.php b/phpBB/includes/mcp/mcp_warn.php
index 6a8fb4c5d5..bb21d3d377 100644
--- a/phpBB/includes/mcp/mcp_warn.php
+++ b/phpBB/includes/mcp/mcp_warn.php
@@ -289,28 +289,17 @@ class mcp_warn
// We want to make the message available here as a reminder
// Parse the message and subject
- $message = censor_text($user_row['post_text']);
-
- // Second parse bbcode here
- if ($user_row['bbcode_bitfield'])
- {
- include_once($phpbb_root_path . 'includes/bbcode.' . $phpEx);
-
- $bbcode = new bbcode($user_row['bbcode_bitfield']);
- $bbcode->bbcode_second_pass($message, $user_row['bbcode_uid'], $user_row['bbcode_bitfield']);
- }
-
- $message = bbcode_nl2br($message);
- $message = smiley_text($message);
+ $parse_flags = OPTION_FLAG_SMILIES | ($row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0);
+ $message = generate_text_for_display($user_row['post_text'], $user_row['bbcode_uid'], $user_row['bbcode_bitfield'], $parse_flags, true);
// Generate the appropriate user information for the user we are looking at
- if (!function_exists('get_user_avatar'))
+ if (!function_exists('phpbb_get_user_avatar'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
get_user_rank($user_row['user_rank'], $user_row['user_posts'], $rank_title, $rank_img, $rank_img_src);
- $avatar_img = get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']);
+ $avatar_img = phpbb_get_user_avatar($user_row);
$template->assign_vars(array(
'U_POST_ACTION' => $this->u_action,
@@ -409,13 +398,13 @@ class mcp_warn
}
// Generate the appropriate user information for the user we are looking at
- if (!function_exists('get_user_avatar'))
+ if (!function_exists('phpbb_get_user_avatar'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
get_user_rank($user_row['user_rank'], $user_row['user_posts'], $rank_title, $rank_img, $rank_img_src);
- $avatar_img = get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']);
+ $avatar_img = phpbb_get_user_avatar($user_row);
// OK, they didn't submit a warning so lets build the page for them to do so
$template->assign_vars(array(
diff --git a/phpBB/includes/message_parser.php b/phpBB/includes/message_parser.php
index 1cd2a46fa1..44960dd78d 100644
--- a/phpBB/includes/message_parser.php
+++ b/phpBB/includes/message_parser.php
@@ -702,17 +702,6 @@ class bbcode_firstpass extends bbcode
{
global $config, $user;
- /**
- * If you change this code, make sure the cases described within the following reports are still working:
- * #3572 - [quote="[test]test"]test [ test[/quote] - (correct: parsed)
- * #14667 - [quote]test[/quote] test ] and [ test [quote]test[/quote] (correct: parsed)
- * #14770 - [quote="["]test[/quote] (correct: parsed)
- * [quote="[i]test[/i]"]test[/quote] (correct: parsed)
- * [quote="[quote]test[/quote]"]test[/quote] (correct: parsed - Username displayed as [quote]test[/quote])
- * #20735 - [quote]test[/[/b]quote] test [/quote][/quote] test - (correct: quoted: "test[/[/b]quote] test" / non-quoted: "[/quote] test" - also failed if layout distorted)
- * #40565 - [quote="a"]a[/quote][quote="a]a[/quote] (correct: first quote tag parsed, second quote tag unparsed)
- */
-
$in = str_replace("\r\n", "\n", str_replace('\"', '"', trim($in)));
if (!$in)
diff --git a/phpBB/includes/php/ini.php b/phpBB/includes/php/ini.php
deleted file mode 100644
index 17e8c54a57..0000000000
--- a/phpBB/includes/php/ini.php
+++ /dev/null
@@ -1,175 +0,0 @@
-<?php
-/**
-*
-* @package phpBB
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Wrapper class for ini_get function.
-*
-* Provides easier handling of the different interpretations of ini values.
-*
-* @package phpBB
-*/
-class phpbb_php_ini
-{
- /**
- * Simple wrapper for ini_get()
- * See http://php.net/manual/en/function.ini-get.php
- *
- * @param string $varname The configuration option name.
- * @return bool|string False if configuration option does not exist,
- * the configuration option value (string) otherwise.
- */
- public function get($varname)
- {
- return ini_get($varname);
- }
-
- /**
- * Gets the configuration option value as a trimmed string.
- *
- * @param string $varname The configuration option name.
- * @return bool|string False if configuration option does not exist,
- * the configuration option value (string) otherwise.
- */
- public function get_string($varname)
- {
- $value = $this->get($varname);
-
- if ($value === false)
- {
- return false;
- }
-
- return trim($value);
- }
-
- /**
- * Gets configuration option value as a boolean.
- * Interprets the string value 'off' as false.
- *
- * @param string $varname The configuration option name.
- * @return bool False if configuration option does not exist.
- * False if configuration option is disabled.
- * True otherwise.
- */
- public function get_bool($varname)
- {
- $value = $this->get_string($varname);
-
- if (empty($value) || strtolower($value) == 'off')
- {
- return false;
- }
-
- return true;
- }
-
- /**
- * Gets configuration option value as an integer.
- *
- * @param string $varname The configuration option name.
- * @return bool|int False if configuration option does not exist,
- * false if configuration option value is not numeric,
- * the configuration option value (integer) otherwise.
- */
- public function get_int($varname)
- {
- $value = $this->get_string($varname);
-
- if (!is_numeric($value))
- {
- return false;
- }
-
- return (int) $value;
- }
-
- /**
- * Gets configuration option value as a float.
- *
- * @param string $varname The configuration option name.
- * @return bool|float False if configuration option does not exist,
- * false if configuration option value is not numeric,
- * the configuration option value (float) otherwise.
- */
- public function get_float($varname)
- {
- $value = $this->get_string($varname);
-
- if (!is_numeric($value))
- {
- return false;
- }
-
- return (float) $value;
- }
-
- /**
- * Gets configuration option value in bytes.
- * Converts strings like '128M' to bytes (integer or float).
- *
- * @param string $varname The configuration option name.
- * @return bool|int|float False if configuration option does not exist,
- * false if configuration option value is not well-formed,
- * the configuration option value otherwise.
- */
- public function get_bytes($varname)
- {
- $value = $this->get_string($varname);
-
- if ($value === false)
- {
- return false;
- }
-
- if (is_numeric($value))
- {
- // Already in bytes.
- return phpbb_to_numeric($value);
- }
- else if (strlen($value) < 2)
- {
- // Single character.
- return false;
- }
- else if (strlen($value) < 3 && $value[0] === '-')
- {
- // Two characters but the first one is a minus.
- return false;
- }
-
- $value_lower = strtolower($value);
- $value_numeric = phpbb_to_numeric($value);
-
- switch ($value_lower[strlen($value_lower) - 1])
- {
- case 'g':
- $value_numeric *= 1024;
- case 'm':
- $value_numeric *= 1024;
- case 'k':
- $value_numeric *= 1024;
- break;
-
- default:
- // It's not already in bytes (and thus numeric)
- // and does not carry a unit.
- return false;
- }
-
- return $value_numeric;
- }
-}
diff --git a/phpBB/includes/questionnaire/questionnaire.php b/phpBB/includes/questionnaire/questionnaire.php
index 2d29fe978e..6f2727a38c 100644
--- a/phpBB/includes/questionnaire/questionnaire.php
+++ b/phpBB/includes/questionnaire/questionnaire.php
@@ -260,6 +260,8 @@ class phpbb_questionnaire_phpbb_data_provider
include("{$phpbb_root_path}config.$phpEx");
unset($dbhost, $dbport, $dbname, $dbuser, $dbpasswd); // Just a precaution
+ $dbms = phpbb_convert_30_dbms_to_31($dbms);
+
// Only send certain config vars
$config_vars = array(
'active_sessions' => true,
diff --git a/phpBB/includes/request/deactivated_super_global.php b/phpBB/includes/request/deactivated_super_global.php
deleted file mode 100644
index cc05847ec7..0000000000
--- a/phpBB/includes/request/deactivated_super_global.php
+++ /dev/null
@@ -1,121 +0,0 @@
-<?php
-/**
-*
-* @package phpbb_request
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Replacement for a superglobal (like $_GET or $_POST) which calls
-* trigger_error on all operations but isset, overloads the [] operator with SPL.
-*
-* @package phpbb_request
-*/
-class phpbb_request_deactivated_super_global implements ArrayAccess, Countable, IteratorAggregate
-{
- /**
- * @var string Holds the name of the superglobal this is replacing.
- */
- private $name;
-
- /**
- * @var phpbb_request_interface::POST|GET|REQUEST|COOKIE Super global constant.
- */
- private $super_global;
-
- /**
- * @var phpbb_request_interface The request class instance holding the actual request data.
- */
- private $request;
-
- /**
- * Constructor generates an error message fitting the super global to be used within the other functions.
- *
- * @param phpbb_request_interface $request A request class instance holding the real super global data.
- * @param string $name Name of the super global this is a replacement for - e.g. '_GET'.
- * @param phpbb_request_interface::POST|GET|REQUEST|COOKIE $super_global The variable's super global constant.
- */
- public function __construct(phpbb_request_interface $request, $name, $super_global)
- {
- $this->request = $request;
- $this->name = $name;
- $this->super_global = $super_global;
- }
-
- /**
- * Calls trigger_error with the file and line number the super global was used in.
- */
- private function error()
- {
- $file = '';
- $line = 0;
-
- $message = 'Illegal use of $' . $this->name . '. You must use the request class or request_var() to access input data. Found in %s on line %d. This error message was generated by deactivated_super_global.';
-
- $backtrace = debug_backtrace();
- if (isset($backtrace[1]))
- {
- $file = $backtrace[1]['file'];
- $line = $backtrace[1]['line'];
- }
- trigger_error(sprintf($message, $file, $line), E_USER_ERROR);
- }
-
- /**
- * Redirects isset to the correct request class call.
- *
- * @param string $offset The key of the super global being accessed.
- *
- * @return bool Whether the key on the super global exists.
- */
- public function offsetExists($offset)
- {
- return $this->request->is_set($offset, $this->super_global);
- }
-
- /**#@+
- * Part of the ArrayAccess implementation, will always result in a FATAL error.
- */
- public function offsetGet($offset)
- {
- $this->error();
- }
-
- public function offsetSet($offset, $value)
- {
- $this->error();
- }
-
- public function offsetUnset($offset)
- {
- $this->error();
- }
- /**#@-*/
-
- /**
- * Part of the Countable implementation, will always result in a FATAL error
- */
- public function count()
- {
- $this->error();
- }
-
- /**
- * Part of the Traversable/IteratorAggregate implementation, will always result in a FATAL error
- */
- public function getIterator()
- {
- $this->error();
- }
-}
-
diff --git a/phpBB/includes/request/interface.php b/phpBB/includes/request/interface.php
deleted file mode 100644
index 741db35917..0000000000
--- a/phpBB/includes/request/interface.php
+++ /dev/null
@@ -1,139 +0,0 @@
-<?php
-/**
-*
-* @package phpbb_request
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* An interface through which all application input can be accessed.
-*
-* @package phpbb_request
-*/
-interface phpbb_request_interface
-{
- /**#@+
- * Constant identifying the super global with the same name.
- */
- const POST = 0;
- const GET = 1;
- const REQUEST = 2;
- const COOKIE = 3;
- const SERVER = 4;
- const FILES = 5;
- /**#@-*/
-
- /**
- * This function allows overwriting or setting a value in one of the super global arrays.
- *
- * Changes which are performed on the super globals directly will not have any effect on the results of
- * other methods this class provides. Using this function should be avoided if possible! It will
- * consume twice the the amount of memory of the value
- *
- * @param string $var_name The name of the variable that shall be overwritten
- * @param mixed $value The value which the variable shall contain.
- * If this is null the variable will be unset.
- * @param phpbb_request_interface::POST|GET|REQUEST|COOKIE $super_global
- * Specifies which super global shall be changed
- */
- public function overwrite($var_name, $value, $super_global = phpbb_request_interface::REQUEST);
-
- /**
- * Central type safe input handling function.
- * All variables in GET or POST requests should be retrieved through this function to maximise security.
- *
- * @param string|array $var_name The form variable's name from which data shall be retrieved.
- * If the value is an array this may be an array of indizes which will give
- * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a")
- * then specifying array("var", 1) as the name will return "a".
- * @param mixed $default A default value that is returned if the variable was not set.
- * This function will always return a value of the same type as the default.
- * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters
- * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks
- * @param phpbb_request_interface::POST|GET|REQUEST|COOKIE $super_global
- * Specifies which super global should be used
- *
- * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the
- * the same as that of $default. If the variable is not set $default is returned.
- */
- public function variable($var_name, $default, $multibyte = false, $super_global = phpbb_request_interface::REQUEST);
-
- /**
- * Shortcut method to retrieve SERVER variables.
- *
- * @param string|array $var_name See phpbb_request_interface::variable
- * @param mixed $default See phpbb_request_interface::variable
- *
- * @return mixed The server variable value.
- */
- public function server($var_name, $default = '');
-
- /**
- * Shortcut method to retrieve the value of client HTTP headers.
- *
- * @param string|array $header_name The name of the header to retrieve.
- * @param mixed $default See phpbb_request_interface::variable
- *
- * @return mixed The header value.
- */
- public function header($var_name, $default = '');
-
- /**
- * Checks whether a certain variable was sent via POST.
- * To make sure that a request was sent using POST you should call this function
- * on at least one variable.
- *
- * @param string $name The name of the form variable which should have a
- * _p suffix to indicate the check in the code that creates the form too.
- *
- * @return bool True if the variable was set in a POST request, false otherwise.
- */
- public function is_set_post($name);
-
- /**
- * Checks whether a certain variable is set in one of the super global
- * arrays.
- *
- * @param string $var Name of the variable
- * @param phpbb_request_interface::POST|GET|REQUEST|COOKIE $super_global
- * Specifies the super global which shall be checked
- *
- * @return bool True if the variable was sent as input
- */
- public function is_set($var, $super_global = phpbb_request_interface::REQUEST);
-
- /**
- * Checks whether the current request is an AJAX request (XMLHttpRequest)
- *
- * @return bool True if the current request is an ajax request
- */
- public function is_ajax();
-
- /**
- * Checks if the current request is happening over HTTPS.
- *
- * @return bool True if the request is secure.
- */
- public function is_secure();
-
- /**
- * Returns all variable names for a given super global
- *
- * @param phpbb_request_interface::POST|GET|REQUEST|COOKIE $super_global
- * The super global from which names shall be taken
- *
- * @return array All variable names that are set for the super global.
- * Pay attention when using these, they are unsanitised!
- */
- public function variable_names($super_global = phpbb_request_interface::REQUEST);
-}
diff --git a/phpBB/includes/request/request.php b/phpBB/includes/request/request.php
deleted file mode 100644
index ae3c526d89..0000000000
--- a/phpBB/includes/request/request.php
+++ /dev/null
@@ -1,415 +0,0 @@
-<?php
-/**
-*
-* @package phpbb_request
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* All application input is accessed through this class.
-*
-* It provides a method to disable access to input data through super globals.
-* This should force MOD authors to read about data validation.
-*
-* @package phpbb_request
-*/
-class phpbb_request implements phpbb_request_interface
-{
- /**
- * @var array The names of super global variables that this class should protect if super globals are disabled.
- */
- protected $super_globals = array(
- phpbb_request_interface::POST => '_POST',
- phpbb_request_interface::GET => '_GET',
- phpbb_request_interface::REQUEST => '_REQUEST',
- phpbb_request_interface::COOKIE => '_COOKIE',
- phpbb_request_interface::SERVER => '_SERVER',
- phpbb_request_interface::FILES => '_FILES',
- );
-
- /**
- * @var array Stores original contents of $_REQUEST array.
- */
- protected $original_request = null;
-
- /**
- * @var
- */
- protected $super_globals_disabled = false;
-
- /**
- * @var array An associative array that has the value of super global constants as keys and holds their data as values.
- */
- protected $input;
-
- /**
- * @var phpbb_request_type_cast_helper_interface An instance of a type cast helper providing convenience methods for type conversions.
- */
- protected $type_cast_helper;
-
- /**
- * Initialises the request class, that means it stores all input data in {@link $input input}
- * and then calls {@link phpbb_request_deactivated_super_global phpbb_request_deactivated_super_global}
- */
- public function __construct(phpbb_request_type_cast_helper_interface $type_cast_helper = null, $disable_super_globals = true)
- {
- if ($type_cast_helper)
- {
- $this->type_cast_helper = $type_cast_helper;
- }
- else
- {
- $this->type_cast_helper = new phpbb_request_type_cast_helper();
- }
-
- foreach ($this->super_globals as $const => $super_global)
- {
- $this->input[$const] = isset($GLOBALS[$super_global]) ? $GLOBALS[$super_global] : array();
- }
-
- // simulate request_order = GP
- $this->original_request = $this->input[phpbb_request_interface::REQUEST];
- $this->input[phpbb_request_interface::REQUEST] = $this->input[phpbb_request_interface::POST] + $this->input[phpbb_request_interface::GET];
-
- if ($disable_super_globals)
- {
- $this->disable_super_globals();
- }
- }
-
- /**
- * Getter for $super_globals_disabled
- *
- * @return bool Whether super globals are disabled or not.
- */
- public function super_globals_disabled()
- {
- return $this->super_globals_disabled;
- }
-
- /**
- * Disables access of super globals specified in $super_globals.
- * This is achieved by overwriting the super globals with instances of {@link phpbb_request_deactivated_super_global phpbb_request_deactivated_super_global}
- */
- public function disable_super_globals()
- {
- if (!$this->super_globals_disabled)
- {
- foreach ($this->super_globals as $const => $super_global)
- {
- unset($GLOBALS[$super_global]);
- $GLOBALS[$super_global] = new phpbb_request_deactivated_super_global($this, $super_global, $const);
- }
-
- $this->super_globals_disabled = true;
- }
- }
-
- /**
- * Enables access of super globals specified in $super_globals if they were disabled by {@link disable_super_globals disable_super_globals}.
- * This is achieved by making the super globals point to the data stored within this class in {@link $input input}.
- */
- public function enable_super_globals()
- {
- if ($this->super_globals_disabled)
- {
- foreach ($this->super_globals as $const => $super_global)
- {
- $GLOBALS[$super_global] = $this->input[$const];
- }
-
- $GLOBALS['_REQUEST'] = $this->original_request;
-
- $this->super_globals_disabled = false;
- }
- }
-
- /**
- * This function allows overwriting or setting a value in one of the super global arrays.
- *
- * Changes which are performed on the super globals directly will not have any effect on the results of
- * other methods this class provides. Using this function should be avoided if possible! It will
- * consume twice the the amount of memory of the value
- *
- * @param string $var_name The name of the variable that shall be overwritten
- * @param mixed $value The value which the variable shall contain.
- * If this is null the variable will be unset.
- * @param phpbb_request_interface::POST|GET|REQUEST|COOKIE $super_global
- * Specifies which super global shall be changed
- */
- public function overwrite($var_name, $value, $super_global = phpbb_request_interface::REQUEST)
- {
- if (!isset($this->super_globals[$super_global]))
- {
- return;
- }
-
- $this->type_cast_helper->add_magic_quotes($value);
-
- // setting to null means unsetting
- if ($value === null)
- {
- unset($this->input[$super_global][$var_name]);
- if (!$this->super_globals_disabled())
- {
- unset($GLOBALS[$this->super_globals[$super_global]][$var_name]);
- }
- }
- else
- {
- $this->input[$super_global][$var_name] = $value;
- if (!$this->super_globals_disabled())
- {
- $GLOBALS[$this->super_globals[$super_global]][$var_name] = $value;
- }
- }
-
- if (!$this->super_globals_disabled())
- {
- unset($GLOBALS[$this->super_globals[$super_global]][$var_name]);
- $GLOBALS[$this->super_globals[$super_global]][$var_name] = $value;
- }
- }
-
- /**
- * Central type safe input handling function.
- * All variables in GET or POST requests should be retrieved through this function to maximise security.
- *
- * @param string|array $var_name The form variable's name from which data shall be retrieved.
- * If the value is an array this may be an array of indizes which will give
- * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a")
- * then specifying array("var", 1) as the name will return "a".
- * @param mixed $default A default value that is returned if the variable was not set.
- * This function will always return a value of the same type as the default.
- * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters
- * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks
- * @param phpbb_request_interface::POST|GET|REQUEST|COOKIE $super_global
- * Specifies which super global should be used
- *
- * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the
- * the same as that of $default. If the variable is not set $default is returned.
- */
- public function variable($var_name, $default, $multibyte = false, $super_global = phpbb_request_interface::REQUEST)
- {
- return $this->_variable($var_name, $default, $multibyte, $super_global, true);
- }
-
- /**
- * Get a variable, but without trimming strings.
- * Same functionality as variable(), except does not run trim() on strings.
- * This method should be used when handling passwords.
- *
- * @param string|array $var_name The form variable's name from which data shall be retrieved.
- * If the value is an array this may be an array of indizes which will give
- * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a")
- * then specifying array("var", 1) as the name will return "a".
- * @param mixed $default A default value that is returned if the variable was not set.
- * This function will always return a value of the same type as the default.
- * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters
- * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks
- * @param phpbb_request_interface::POST|GET|REQUEST|COOKIE $super_global
- * Specifies which super global should be used
- *
- * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the
- * the same as that of $default. If the variable is not set $default is returned.
- */
- public function untrimmed_variable($var_name, $default, $multibyte, $super_global = phpbb_request_interface::REQUEST)
- {
- return $this->_variable($var_name, $default, $multibyte, $super_global, false);
- }
-
- /**
- * Shortcut method to retrieve SERVER variables.
- *
- * Also fall back to getenv(), some CGI setups may need it (probably not, but
- * whatever).
- *
- * @param string|array $var_name See phpbb_request_interface::variable
- * @param mixed $Default See phpbb_request_interface::variable
- *
- * @return mixed The server variable value.
- */
- public function server($var_name, $default = '')
- {
- $multibyte = true;
-
- if ($this->is_set($var_name, phpbb_request_interface::SERVER))
- {
- return $this->variable($var_name, $default, $multibyte, phpbb_request_interface::SERVER);
- }
- else
- {
- $var = getenv($var_name);
- $this->type_cast_helper->recursive_set_var($var, $default, $multibyte);
- return $var;
- }
- }
-
- /**
- * Shortcut method to retrieve the value of client HTTP headers.
- *
- * @param string|array $header_name The name of the header to retrieve.
- * @param mixed $default See phpbb_request_interface::variable
- *
- * @return mixed The header value.
- */
- public function header($header_name, $default = '')
- {
- $var_name = 'HTTP_' . str_replace('-', '_', strtoupper($header_name));
- return $this->server($var_name, $default);
- }
-
- /**
- * Shortcut method to retrieve $_FILES variables
- *
- * @param string $form_name The name of the file input form element
- *
- * @return array The uploaded file's information or an empty array if the
- * variable does not exist in _FILES.
- */
- public function file($form_name)
- {
- return $this->variable($form_name, array('name' => 'none'), false, phpbb_request_interface::FILES);
- }
-
- /**
- * Checks whether a certain variable was sent via POST.
- * To make sure that a request was sent using POST you should call this function
- * on at least one variable.
- *
- * @param string $name The name of the form variable which should have a
- * _p suffix to indicate the check in the code that creates the form too.
- *
- * @return bool True if the variable was set in a POST request, false otherwise.
- */
- public function is_set_post($name)
- {
- return $this->is_set($name, phpbb_request_interface::POST);
- }
-
- /**
- * Checks whether a certain variable is set in one of the super global
- * arrays.
- *
- * @param string $var Name of the variable
- * @param phpbb_request_interface::POST|GET|REQUEST|COOKIE $super_global
- * Specifies the super global which shall be checked
- *
- * @return bool True if the variable was sent as input
- */
- public function is_set($var, $super_global = phpbb_request_interface::REQUEST)
- {
- return isset($this->input[$super_global][$var]);
- }
-
- /**
- * Checks whether the current request is an AJAX request (XMLHttpRequest)
- *
- * @return bool True if the current request is an ajax request
- */
- public function is_ajax()
- {
- return $this->header('X-Requested-With') == 'XMLHttpRequest';
- }
-
- /**
- * Checks if the current request is happening over HTTPS.
- *
- * @return bool True if the request is secure.
- */
- public function is_secure()
- {
- return $this->server('HTTPS') == 'on';
- }
-
- /**
- * Returns all variable names for a given super global
- *
- * @param phpbb_request_interface::POST|GET|REQUEST|COOKIE $super_global
- * The super global from which names shall be taken
- *
- * @return array All variable names that are set for the super global.
- * Pay attention when using these, they are unsanitised!
- */
- public function variable_names($super_global = phpbb_request_interface::REQUEST)
- {
- if (!isset($this->input[$super_global]))
- {
- return array();
- }
-
- return array_keys($this->input[$super_global]);
- }
-
- /**
- * Helper function used by variable() and untrimmed_variable().
- *
- * @param string|array $var_name The form variable's name from which data shall be retrieved.
- * If the value is an array this may be an array of indizes which will give
- * direct access to a value at any depth. E.g. if the value of "var" is array(1 => "a")
- * then specifying array("var", 1) as the name will return "a".
- * @param mixed $default A default value that is returned if the variable was not set.
- * This function will always return a value of the same type as the default.
- * @param bool $multibyte If $default is a string this paramater has to be true if the variable may contain any UTF-8 characters
- * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks
- * @param phpbb_request_interface::POST|GET|REQUEST|COOKIE $super_global
- * Specifies which super global should be used
- * @param bool $trim Indicates whether trim() should be applied to string values.
- *
- * @return mixed The value of $_REQUEST[$var_name] run through {@link set_var set_var} to ensure that the type is the
- * the same as that of $default. If the variable is not set $default is returned.
- */
- protected function _variable($var_name, $default, $multibyte = false, $super_global = phpbb_request_interface::REQUEST, $trim = true)
- {
- $path = false;
-
- // deep direct access to multi dimensional arrays
- if (is_array($var_name))
- {
- $path = $var_name;
- // make sure at least the variable name is specified
- if (empty($path))
- {
- return (is_array($default)) ? array() : $default;
- }
- // the variable name is the first element on the path
- $var_name = array_shift($path);
- }
-
- if (!isset($this->input[$super_global][$var_name]))
- {
- return (is_array($default)) ? array() : $default;
- }
- $var = $this->input[$super_global][$var_name];
-
- if ($path)
- {
- // walk through the array structure and find the element we are looking for
- foreach ($path as $key)
- {
- if (is_array($var) && isset($var[$key]))
- {
- $var = $var[$key];
- }
- else
- {
- return (is_array($default)) ? array() : $default;
- }
- }
- }
-
- $this->type_cast_helper->recursive_set_var($var, $default, $multibyte, $trim);
-
- return $var;
- }
-}
diff --git a/phpBB/includes/request/type_cast_helper.php b/phpBB/includes/request/type_cast_helper.php
deleted file mode 100644
index 1a5274ed14..0000000000
--- a/phpBB/includes/request/type_cast_helper.php
+++ /dev/null
@@ -1,194 +0,0 @@
-<?php
-/**
-*
-* @package phpbb_request
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* A helper class that provides convenience methods for type casting.
-*
-* @package phpbb_request
-*/
-class phpbb_request_type_cast_helper implements phpbb_request_type_cast_helper_interface
-{
-
- /**
- * @var string Whether slashes need to be stripped from input
- */
- protected $strip;
-
- /**
- * Initialises the type cast helper class.
- * All it does is find out whether magic quotes are turned on.
- */
- public function __construct()
- {
- if (version_compare(PHP_VERSION, '5.4.0-dev', '>='))
- {
- $this->strip = false;
- }
- else
- {
- $this->strip = (@get_magic_quotes_gpc()) ? true : false;
- }
- }
-
- /**
- * Recursively applies addslashes to a variable.
- *
- * @param mixed &$var Variable passed by reference to which slashes will be added.
- */
- public function addslashes_recursively(&$var)
- {
- if (is_string($var))
- {
- $var = addslashes($var);
- }
- else if (is_array($var))
- {
- $var_copy = $var;
- $var = array();
- foreach ($var_copy as $key => $value)
- {
- if (is_string($key))
- {
- $key = addslashes($key);
- }
- $var[$key] = $value;
-
- $this->addslashes_recursively($var[$key]);
- }
- }
- }
-
- /**
- * Recursively applies addslashes to a variable if magic quotes are turned on.
- *
- * @param mixed &$var Variable passed by reference to which slashes will be added.
- */
- public function add_magic_quotes(&$var)
- {
- if ($this->strip)
- {
- $this->addslashes_recursively($var);
- }
- }
-
- /**
- * Set variable $result to a particular type.
- *
- * @param mixed &$result The variable to fill
- * @param mixed $var The contents to fill with
- * @param mixed $type The variable type. Will be used with {@link settype()}
- * @param bool $multibyte Indicates whether string values may contain UTF-8 characters.
- * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks.
- * @param bool $trim Indicates whether trim() should be applied to string values.
- * Default is true.
- */
- public function set_var(&$result, $var, $type, $multibyte = false, $trim = true)
- {
- settype($var, $type);
- $result = $var;
-
- if ($type == 'string')
- {
- $result = str_replace(array("\r\n", "\r", "\0"), array("\n", "\n", ''), $result);
-
- if ($trim)
- {
- $result = trim($result);
- }
-
- $result = htmlspecialchars($result, ENT_COMPAT, 'UTF-8');
-
- if ($multibyte)
- {
- $result = utf8_normalize_nfc($result);
- }
-
- if (!empty($result))
- {
- // Make sure multibyte characters are wellformed
- if ($multibyte)
- {
- if (!preg_match('/^./u', $result))
- {
- $result = '';
- }
- }
- else
- {
- // no multibyte, allow only ASCII (0-127)
- $result = preg_replace('/[\x80-\xFF]/', '?', $result);
- }
- }
-
- $result = ($this->strip) ? stripslashes($result) : $result;
- }
- }
-
- /**
- * Recursively sets a variable to a given type using {@link set_var set_var}
- *
- * @param string $var The value which shall be sanitised (passed by reference).
- * @param mixed $default Specifies the type $var shall have.
- * If it is an array and $var is not one, then an empty array is returned.
- * Otherwise var is cast to the same type, and if $default is an array all
- * keys and values are cast recursively using this function too.
- * @param bool $multibyte Indicates whether string keys and values may contain UTF-8 characters.
- * Default is false, causing all bytes outside the ASCII range (0-127) to
- * be replaced with question marks.
- * @param bool $trim Indicates whether trim() should be applied to string values.
- * Default is true.
- */
- public function recursive_set_var(&$var, $default, $multibyte, $trim = true)
- {
- if (is_array($var) !== is_array($default))
- {
- $var = (is_array($default)) ? array() : $default;
- return;
- }
-
- if (!is_array($default))
- {
- $type = gettype($default);
- $this->set_var($var, $var, $type, $multibyte, $trim);
- }
- else
- {
- // make sure there is at least one key/value pair to use get the
- // types from
- if (empty($default))
- {
- $var = array();
- return;
- }
-
- list($default_key, $default_value) = each($default);
- $value_type = gettype($default_value);
- $key_type = gettype($default_key);
-
- $_var = $var;
- $var = array();
-
- foreach ($_var as $k => $v)
- {
- $this->set_var($k, $k, $key_type, $multibyte);
-
- $this->recursive_set_var($v, $default_value, $multibyte, $trim);
- $var[$k] = $v;
- }
- }
- }
-}
diff --git a/phpBB/includes/request/type_cast_helper_interface.php b/phpBB/includes/request/type_cast_helper_interface.php
deleted file mode 100644
index 3920d16fc7..0000000000
--- a/phpBB/includes/request/type_cast_helper_interface.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-/**
-*
-* @package phpbb_request
-* @copyright (c) 2010 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* An interface for type cast operations.
-*
-* @package phpbb_request
-*/
-interface phpbb_request_type_cast_helper_interface
-{
- /**
- * Recursively applies addslashes to a variable.
- *
- * @param mixed &$var Variable passed by reference to which slashes will be added.
- */
- public function addslashes_recursively(&$var);
-
- /**
- * Recursively applies addslashes to a variable if magic quotes are turned on.
- *
- * @param mixed &$var Variable passed by reference to which slashes will be added.
- */
- public function add_magic_quotes(&$var);
-
- /**
- * Set variable $result to a particular type.
- *
- * @param mixed &$result The variable to fill
- * @param mixed $var The contents to fill with
- * @param mixed $type The variable type. Will be used with {@link settype()}
- * @param bool $multibyte Indicates whether string values may contain UTF-8 characters.
- * Default is false, causing all bytes outside the ASCII range (0-127) to be replaced with question marks.
- */
- public function set_var(&$result, $var, $type, $multibyte = false);
-
- /**
- * Recursively sets a variable to a given type using {@link set_var set_var}.
- *
- * @param string $var The value which shall be sanitised (passed by reference).
- * @param mixed $default Specifies the type $var shall have.
- * If it is an array and $var is not one, then an empty array is returned.
- * Otherwise var is cast to the same type, and if $default is an array all
- * keys and values are cast recursively using this function too.
- * @param bool $multibyte Indicates whether string keys and values may contain UTF-8 characters.
- * Default is false, causing all bytes outside the ASCII range (0-127) to
- * be replaced with question marks.
- */
- public function recursive_set_var(&$var, $default, $multibyte);
-}
diff --git a/phpBB/includes/search/base.php b/phpBB/includes/search/base.php
deleted file mode 100644
index b364dead9a..0000000000
--- a/phpBB/includes/search/base.php
+++ /dev/null
@@ -1,317 +0,0 @@
-<?php
-/**
-*
-* @package search
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* @ignore
-*/
-define('SEARCH_RESULT_NOT_IN_CACHE', 0);
-define('SEARCH_RESULT_IN_CACHE', 1);
-define('SEARCH_RESULT_INCOMPLETE', 2);
-
-/**
-* phpbb_search_base
-* optional base class for search plugins providing simple caching based on ACM
-* and functions to retrieve ignore_words and synonyms
-* @package search
-*/
-class phpbb_search_base
-{
- var $ignore_words = array();
- var $match_synonym = array();
- var $replace_synonym = array();
-
- function search_backend(&$error)
- {
- // This class cannot be used as a search plugin
- $error = true;
- }
-
- /**
- * Retrieves a language dependend list of words that should be ignored by the search
- */
- function get_ignore_words()
- {
- if (!sizeof($this->ignore_words))
- {
- global $user, $phpEx;
-
- $words = array();
-
- if (file_exists("{$user->lang_path}{$user->lang_name}/search_ignore_words.$phpEx"))
- {
- // include the file containing ignore words
- include("{$user->lang_path}{$user->lang_name}/search_ignore_words.$phpEx");
- }
-
- $this->ignore_words = $words;
- unset($words);
- }
- }
-
- /**
- * Stores a list of synonyms that should be replaced in $this->match_synonym and $this->replace_synonym and caches them
- */
- function get_synonyms()
- {
- if (!sizeof($this->match_synonym))
- {
- global $user, $phpEx;
-
- $synonyms = array();
-
- if (file_exists("{$user->lang_path}{$user->lang_name}/search_synonyms.$phpEx"))
- {
- // include the file containing synonyms
- include("{$user->lang_path}{$user->lang_name}/search_synonyms.$phpEx");
- }
-
- $this->match_synonym = array_keys($synonyms);
- $this->replace_synonym = array_values($synonyms);
-
- unset($synonyms);
- }
- }
-
- /**
- * Retrieves cached search results
- *
- * @param int &$result_count will contain the number of all results for the search (not only for the current page)
- * @param array &$id_ary is filled with the ids belonging to the requested page that are stored in the cache
- *
- * @return int SEARCH_RESULT_NOT_IN_CACHE or SEARCH_RESULT_IN_CACHE or SEARCH_RESULT_INCOMPLETE
- */
- function obtain_ids($search_key, &$result_count, &$id_ary, $start, $per_page, $sort_dir)
- {
- global $cache;
-
- if (!($stored_ids = $cache->get('_search_results_' . $search_key)))
- {
- // no search results cached for this search_key
- return SEARCH_RESULT_NOT_IN_CACHE;
- }
- else
- {
- $result_count = $stored_ids[-1];
- $reverse_ids = ($stored_ids[-2] != $sort_dir) ? true : false;
- $complete = true;
-
- // change the start to the actual end of the current request if the sort direction differs
- // from the dirction in the cache and reverse the ids later
- if ($reverse_ids)
- {
- $start = $result_count - $start - $per_page;
-
- // the user requested a page past the last index
- if ($start < 0)
- {
- return SEARCH_RESULT_NOT_IN_CACHE;
- }
- }
-
- for ($i = $start, $n = $start + $per_page; ($i < $n) && ($i < $result_count); $i++)
- {
- if (!isset($stored_ids[$i]))
- {
- $complete = false;
- }
- else
- {
- $id_ary[] = $stored_ids[$i];
- }
- }
- unset($stored_ids);
-
- if ($reverse_ids)
- {
- $id_ary = array_reverse($id_ary);
- }
-
- if (!$complete)
- {
- return SEARCH_RESULT_INCOMPLETE;
- }
- return SEARCH_RESULT_IN_CACHE;
- }
- }
-
- /**
- * Caches post/topic ids
- *
- * @param array &$id_ary contains a list of post or topic ids that shall be cached, the first element
- * must have the absolute index $start in the result set.
- */
- function save_ids($search_key, $keywords, $author_ary, $result_count, &$id_ary, $start, $sort_dir)
- {
- global $cache, $config, $db, $user;
-
- $length = min(sizeof($id_ary), $config['search_block_size']);
-
- // nothing to cache so exit
- if (!$length)
- {
- return;
- }
-
- $store_ids = array_slice($id_ary, 0, $length);
-
- // create a new resultset if there is none for this search_key yet
- // or add the ids to the existing resultset
- if (!($store = $cache->get('_search_results_' . $search_key)))
- {
- // add the current keywords to the recent searches in the cache which are listed on the search page
- if (!empty($keywords) || sizeof($author_ary))
- {
- $sql = 'SELECT search_time
- FROM ' . SEARCH_RESULTS_TABLE . '
- WHERE search_key = \'' . $db->sql_escape($search_key) . '\'';
- $result = $db->sql_query($sql);
-
- if (!$db->sql_fetchrow($result))
- {
- $sql_ary = array(
- 'search_key' => $search_key,
- 'search_time' => time(),
- 'search_keywords' => $keywords,
- 'search_authors' => ' ' . implode(' ', $author_ary) . ' '
- );
-
- $sql = 'INSERT INTO ' . SEARCH_RESULTS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
- $db->sql_query($sql);
- }
- $db->sql_freeresult($result);
- }
-
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_last_search = ' . time() . '
- WHERE user_id = ' . $user->data['user_id'];
- $db->sql_query($sql);
-
- $store = array(-1 => $result_count, -2 => $sort_dir);
- $id_range = range($start, $start + $length - 1);
- }
- else
- {
- // we use one set of results for both sort directions so we have to calculate the indizes
- // for the reversed array and we also have to reverse the ids themselves
- if ($store[-2] != $sort_dir)
- {
- $store_ids = array_reverse($store_ids);
- $id_range = range($store[-1] - $start - $length, $store[-1] - $start - 1);
- }
- else
- {
- $id_range = range($start, $start + $length - 1);
- }
- }
-
- $store_ids = array_combine($id_range, $store_ids);
-
- // append the ids
- if (is_array($store_ids))
- {
- $store += $store_ids;
-
- // if the cache is too big
- if (sizeof($store) - 2 > 20 * $config['search_block_size'])
- {
- // remove everything in front of two blocks in front of the current start index
- for ($i = 0, $n = $id_range[0] - 2 * $config['search_block_size']; $i < $n; $i++)
- {
- if (isset($store[$i]))
- {
- unset($store[$i]);
- }
- }
-
- // remove everything after two blocks after the current stop index
- end($id_range);
- for ($i = $store[-1] - 1, $n = current($id_range) + 2 * $config['search_block_size']; $i > $n; $i--)
- {
- if (isset($store[$i]))
- {
- unset($store[$i]);
- }
- }
- }
- $cache->put('_search_results_' . $search_key, $store, $config['search_store_results']);
-
- $sql = 'UPDATE ' . SEARCH_RESULTS_TABLE . '
- SET search_time = ' . time() . '
- WHERE search_key = \'' . $db->sql_escape($search_key) . '\'';
- $db->sql_query($sql);
- }
-
- unset($store);
- unset($store_ids);
- unset($id_range);
- }
-
- /**
- * Removes old entries from the search results table and removes searches with keywords that contain a word in $words.
- */
- function destroy_cache($words, $authors = false)
- {
- global $db, $cache, $config;
-
- // clear all searches that searched for the specified words
- if (sizeof($words))
- {
- $sql_where = '';
- foreach ($words as $word)
- {
- $sql_where .= " OR search_keywords " . $db->sql_like_expression($db->any_char . $word . $db->any_char);
- }
-
- $sql = 'SELECT search_key
- FROM ' . SEARCH_RESULTS_TABLE . "
- WHERE search_keywords LIKE '%*%' $sql_where";
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $cache->destroy('_search_results_' . $row['search_key']);
- }
- $db->sql_freeresult($result);
- }
-
- // clear all searches that searched for the specified authors
- if (is_array($authors) && sizeof($authors))
- {
- $sql_where = '';
- foreach ($authors as $author)
- {
- $sql_where .= (($sql_where) ? ' OR ' : '') . 'search_authors ' . $db->sql_like_expression($db->any_char . ' ' . (int) $author . ' ' . $db->any_char);
- }
-
- $sql = 'SELECT search_key
- FROM ' . SEARCH_RESULTS_TABLE . "
- WHERE $sql_where";
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $cache->destroy('_search_results_' . $row['search_key']);
- }
- $db->sql_freeresult($result);
- }
-
- $sql = 'DELETE
- FROM ' . SEARCH_RESULTS_TABLE . '
- WHERE search_time < ' . (time() - $config['search_store_results']);
- $db->sql_query($sql);
- }
-}
diff --git a/phpBB/includes/search/fulltext_mysql.php b/phpBB/includes/search/fulltext_mysql.php
deleted file mode 100644
index ff2e24aa05..0000000000
--- a/phpBB/includes/search/fulltext_mysql.php
+++ /dev/null
@@ -1,931 +0,0 @@
-<?php
-/**
-*
-* @package search
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* fulltext_mysql
-* Fulltext search for MySQL
-* @package search
-*/
-class phpbb_search_fulltext_mysql extends phpbb_search_base
-{
- /**
- * Associative array holding index stats
- * @var array
- */
- protected $stats = array();
-
- /**
- * Holds the words entered by user, obtained by splitting the entered query on whitespace
- * @var array
- */
- protected $split_words = array();
-
- /**
- * Config object
- * @var phpbb_config
- */
- protected $config;
-
- /**
- * DBAL object
- * @var dbal
- */
- protected $db;
-
- /**
- * User object
- * @var phpbb_user
- */
- protected $user;
-
- /**
- * Associative array stores the min and max word length to be searched
- * @var array
- */
- protected $word_length = array();
-
- /**
- * Contains tidied search query.
- * Operators are prefixed in search query and common words excluded
- * @var string
- */
- protected $search_query;
-
- /**
- * Contains common words.
- * Common words are words with length less/more than min/max length
- * @var array
- */
- protected $common_words = array();
-
- /**
- * Constructor
- * Creates a new phpbb_search_fulltext_mysql, which is used as a search backend
- *
- * @param string|bool $error Any error that occurs is passed on through this reference variable otherwise false
- */
- public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user)
- {
- $this->config = $config;
- $this->db = $db;
- $this->user = $user;
-
- $this->word_length = array('min' => $this->config['fulltext_mysql_min_word_len'], 'max' => $this->config['fulltext_mysql_max_word_len']);
-
- /**
- * Load the UTF tools
- */
- if (!function_exists('utf8_strlen'))
- {
- include($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
- }
-
- $error = false;
- }
-
- /**
- * Returns the name of this search backend to be displayed to administrators
- *
- * @return string Name
- */
- public function get_name()
- {
- return 'MySQL Fulltext';
- }
-
- /**
- * Returns the search_query
- *
- * @return string search query
- */
- public function get_search_query()
- {
- return $this->search_query;
- }
-
- /**
- * Returns the common_words array
- *
- * @return array common words that are ignored by search backend
- */
- public function get_common_words()
- {
- return $this->common_words;
- }
-
- /**
- * Returns the word_length array
- *
- * @return array min and max word length for searching
- */
- public function get_word_length()
- {
- return $this->word_length;
- }
-
- /**
- * Checks for correct MySQL version and stores min/max word length in the config
- *
- * @return string|bool Language key of the error/incompatiblity occured
- */
- public function init()
- {
- if ($this->db->sql_layer != 'mysql4' && $this->db->sql_layer != 'mysqli')
- {
- return $this->user->lang['FULLTEXT_MYSQL_INCOMPATIBLE_DATABASE'];
- }
-
- $result = $this->db->sql_query('SHOW TABLE STATUS LIKE \'' . POSTS_TABLE . '\'');
- $info = $this->db->sql_fetchrow($result);
- $this->db->sql_freeresult($result);
-
- $engine = '';
- if (isset($info['Engine']))
- {
- $engine = $info['Engine'];
- }
- else if (isset($info['Type']))
- {
- $engine = $info['Type'];
- }
-
- if ($engine != 'MyISAM')
- {
- return $this->user->lang['FULLTEXT_MYSQL_NOT_MYISAM'];
- }
-
- $sql = 'SHOW VARIABLES
- LIKE \'ft\_%\'';
- $result = $this->db->sql_query($sql);
-
- $mysql_info = array();
- while ($row = $this->db->sql_fetchrow($result))
- {
- $mysql_info[$row['Variable_name']] = $row['Value'];
- }
- $this->db->sql_freeresult($result);
-
- set_config('fulltext_mysql_max_word_len', $mysql_info['ft_max_word_len']);
- set_config('fulltext_mysql_min_word_len', $mysql_info['ft_min_word_len']);
-
- return false;
- }
-
- /**
- * Splits keywords entered by a user into an array of words stored in $this->split_words
- * Stores the tidied search query in $this->search_query
- *
- * @param string &$keywords Contains the keyword as entered by the user
- * @param string $terms is either 'all' or 'any'
- * @return bool false if no valid keywords were found and otherwise true
- */
- public function split_keywords(&$keywords, $terms)
- {
- if ($terms == 'all')
- {
- $match = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#(^|\s)\+#', '#(^|\s)-#', '#(^|\s)\|#');
- $replace = array(' +', ' |', ' -', ' +', ' -', ' |');
-
- $keywords = preg_replace($match, $replace, $keywords);
- }
-
- // Filter out as above
- $split_keywords = preg_replace("#[\n\r\t]+#", ' ', trim(htmlspecialchars_decode($keywords)));
-
- // Split words
- $split_keywords = preg_replace('#([^\p{L}\p{N}\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords)));
- $matches = array();
- preg_match_all('#(?:[^\p{L}\p{N}*"()]|^)([+\-|]?(?:[\p{L}\p{N}*"()]+\'?)*[\p{L}\p{N}*"()])(?:[^\p{L}\p{N}*"()]|$)#u', $split_keywords, $matches);
- $this->split_words = $matches[1];
-
- // We limit the number of allowed keywords to minimize load on the database
- if ($this->config['max_num_search_keywords'] && sizeof($this->split_words) > $this->config['max_num_search_keywords'])
- {
- trigger_error($this->user->lang('MAX_NUM_SEARCH_KEYWORDS_REFINE', $this->config['max_num_search_keywords'], sizeof($this->split_words)));
- }
-
- // to allow phrase search, we need to concatenate quoted words
- $tmp_split_words = array();
- $phrase = '';
- foreach ($this->split_words as $word)
- {
- if ($phrase)
- {
- $phrase .= ' ' . $word;
- if (strpos($word, '"') !== false && substr_count($word, '"') % 2 == 1)
- {
- $tmp_split_words[] = $phrase;
- $phrase = '';
- }
- }
- else if (strpos($word, '"') !== false && substr_count($word, '"') % 2 == 1)
- {
- $phrase = $word;
- }
- else
- {
- $tmp_split_words[] = $word;
- }
- }
- if ($phrase)
- {
- $tmp_split_words[] = $phrase;
- }
-
- $this->split_words = $tmp_split_words;
-
- unset($tmp_split_words);
- unset($phrase);
-
- foreach ($this->split_words as $i => $word)
- {
- $clean_word = preg_replace('#^[+\-|"]#', '', $word);
-
- // check word length
- $clean_len = utf8_strlen(str_replace('*', '', $clean_word));
- if (($clean_len < $this->config['fulltext_mysql_min_word_len']) || ($clean_len > $this->config['fulltext_mysql_max_word_len']))
- {
- $this->common_words[] = $word;
- unset($this->split_words[$i]);
- }
- }
-
- if ($terms == 'any')
- {
- $this->search_query = '';
- foreach ($this->split_words as $word)
- {
- if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0) || (strpos($word, '|') === 0))
- {
- $word = substr($word, 1);
- }
- $this->search_query .= $word . ' ';
- }
- }
- else
- {
- $this->search_query = '';
- foreach ($this->split_words as $word)
- {
- if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0))
- {
- $this->search_query .= $word . ' ';
- }
- else if (strpos($word, '|') === 0)
- {
- $this->search_query .= substr($word, 1) . ' ';
- }
- else
- {
- $this->search_query .= '+' . $word . ' ';
- }
- }
- }
-
- $this->search_query = utf8_htmlspecialchars($this->search_query);
-
- if ($this->search_query)
- {
- $this->split_words = array_values($this->split_words);
- sort($this->split_words);
- return true;
- }
- return false;
- }
-
- /**
- * Turns text into an array of words
- * @param string $text contains post text/subject
- */
- public function split_message($text)
- {
- // Split words
- $text = preg_replace('#([^\p{L}\p{N}\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text)));
- $matches = array();
- preg_match_all('#(?:[^\p{L}\p{N}*]|^)([+\-|]?(?:[\p{L}\p{N}*]+\'?)*[\p{L}\p{N}*])(?:[^\p{L}\p{N}*]|$)#u', $text, $matches);
- $text = $matches[1];
-
- // remove too short or too long words
- $text = array_values($text);
- for ($i = 0, $n = sizeof($text); $i < $n; $i++)
- {
- $text[$i] = trim($text[$i]);
- if (utf8_strlen($text[$i]) < $this->config['fulltext_mysql_min_word_len'] || utf8_strlen($text[$i]) > $this->config['fulltext_mysql_max_word_len'])
- {
- unset($text[$i]);
- }
- }
-
- return array_values($text);
- }
-
- /**
- * 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 $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
- */
- 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, $author_name, &$id_ary, $start, $per_page)
- {
- // No keywords? No posts
- if (!$this->search_query)
- {
- return false;
- }
-
- // generate a search_key from all the options to identify the results
- $search_key = md5(implode('#', array(
- implode(', ', $this->split_words),
- $type,
- $fields,
- $terms,
- $sort_days,
- $sort_key,
- $topic_id,
- implode(',', $ex_fid_ary),
- implode(',', $m_approve_fid_ary),
- implode(',', $author_ary)
- )));
-
- // try reading the results from cache
- $result_count = 0;
- if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE)
- {
- return $result_count;
- }
-
- $id_ary = array();
-
- $join_topic = ($type == 'posts') ? false : true;
-
- // Build sql strings for sorting
- $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
- $sql_sort_table = $sql_sort_join = '';
-
- switch ($sql_sort[0])
- {
- case 'u':
- $sql_sort_table = USERS_TABLE . ' u, ';
- $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster ';
- break;
-
- case 't':
- $join_topic = true;
- break;
-
- case 'f':
- $sql_sort_table = FORUMS_TABLE . ' f, ';
- $sql_sort_join = ' AND f.forum_id = p.forum_id ';
- break;
- }
-
- // Build some display specific sql strings
- switch ($fields)
- {
- case 'titleonly':
- $sql_match = 'p.post_subject';
- $sql_match_where = ' AND p.post_id = t.topic_first_post_id';
- $join_topic = true;
- break;
-
- case 'msgonly':
- $sql_match = 'p.post_text';
- $sql_match_where = '';
- break;
-
- case 'firstpost':
- $sql_match = 'p.post_subject, p.post_text';
- $sql_match_where = ' AND p.post_id = t.topic_first_post_id';
- $join_topic = true;
- break;
-
- default:
- $sql_match = 'p.post_subject, p.post_text';
- $sql_match_where = '';
- break;
- }
-
- if (!sizeof($m_approve_fid_ary))
- {
- $m_approve_fid_sql = ' AND p.post_approved = 1';
- }
- else if ($m_approve_fid_ary === array(-1))
- {
- $m_approve_fid_sql = '';
- }
- else
- {
- $m_approve_fid_sql = ' AND (p.post_approved = 1 OR ' . $this->db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')';
- }
-
- $sql_select = (!$result_count) ? 'SQL_CALC_FOUND_ROWS ' : '';
- $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';
- if (sizeof($author_ary) && $author_name)
- {
- // first one matches post of registered users, second one guests and deleted users
- $sql_author = ' AND (' . $this->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 ' . $this->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 ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
- $sql_where_options .= $m_approve_fid_sql;
- $sql_where_options .= $sql_author;
- $sql_where_options .= ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
- $sql_where_options .= $sql_match_where;
-
- $sql = "SELECT $sql_select
- FROM $sql_from$sql_sort_table" . POSTS_TABLE . " p
- WHERE MATCH ($sql_match) AGAINST ('" . $this->db->sql_escape(htmlspecialchars_decode($this->search_query)) . "' IN BOOLEAN MODE)
- $sql_where_options
- ORDER BY $sql_sort";
- $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $id_ary[] = (int) $row[$field];
- }
- $this->db->sql_freeresult($result);
-
- $id_ary = array_unique($id_ary);
-
- if (!sizeof($id_ary))
- {
- return false;
- }
-
- // if the total result count is not cached yet, retrieve it from the db
- if (!$result_count)
- {
- $sql = 'SELECT FOUND_ROWS() as result_count';
- $result = $this->db->sql_query($sql);
- $result_count = (int) $this->db->sql_fetchfield('result_count');
- $this->db->sql_freeresult($result);
-
- if (!$result_count)
- {
- return false;
- }
- }
-
- // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page
- $this->save_ids($search_key, implode(' ', $this->split_words), $author_ary, $result_count, $id_ary, $start, $sort_dir);
- $id_ary = array_slice($id_ary, 0, (int) $per_page);
-
- return $result_count;
- }
-
- /**
- * Performs a search on an author's posts without caring about message contents. Depends on display specific params
- *
- * @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
- */
- 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, $author_name, &$id_ary, $start, $per_page)
- {
- // No author? No posts
- if (!sizeof($author_ary))
- {
- return 0;
- }
-
- // generate a search_key from all the options to identify the results
- $search_key = md5(implode('#', array(
- '',
- $type,
- ($firstpost_only) ? 'firstpost' : '',
- '',
- '',
- $sort_days,
- $sort_key,
- $topic_id,
- implode(',', $ex_fid_ary),
- implode(',', $m_approve_fid_ary),
- implode(',', $author_ary),
- $author_name,
- )));
-
- // try reading the results from cache
- $result_count = 0;
- if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE)
- {
- return $result_count;
- }
-
- $id_ary = array();
-
- // Create some display specific sql strings
- if ($author_name)
- {
- // first one matches post of registered users, second one guests and deleted users
- $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')';
- }
- else
- {
- $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary);
- }
- $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $this->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)) : '';
- $sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : '';
-
- // Build sql strings for sorting
- $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
- $sql_sort_table = $sql_sort_join = '';
- switch ($sql_sort[0])
- {
- case 'u':
- $sql_sort_table = USERS_TABLE . ' u, ';
- $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster ';
- break;
-
- case 't':
- $sql_sort_table = ($type == 'posts' && !$firstpost_only) ? TOPICS_TABLE . ' t, ' : '';
- $sql_sort_join = ($type == 'posts' && !$firstpost_only) ? ' AND t.topic_id = p.topic_id ' : '';
- break;
-
- case 'f':
- $sql_sort_table = FORUMS_TABLE . ' f, ';
- $sql_sort_join = ' AND f.forum_id = p.forum_id ';
- break;
- }
-
- if (!sizeof($m_approve_fid_ary))
- {
- $m_approve_fid_sql = ' AND p.post_approved = 1';
- }
- else if ($m_approve_fid_ary == array(-1))
- {
- $m_approve_fid_sql = '';
- }
- else
- {
- $m_approve_fid_sql = ' AND (p.post_approved = 1 OR ' . $this->db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')';
- }
-
- // If the cache was completely empty count the results
- $calc_results = ($result_count) ? '' : 'SQL_CALC_FOUND_ROWS ';
-
- // Build the query for really selecting the post_ids
- if ($type == 'posts')
- {
- $sql = "SELECT {$calc_results}p.post_id
- FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . "
- WHERE $sql_author
- $sql_topic_id
- $sql_firstpost
- $m_approve_fid_sql
- $sql_fora
- $sql_sort_join
- $sql_time
- ORDER BY $sql_sort";
- $field = 'post_id';
- }
- else
- {
- $sql = "SELECT {$calc_results}t.topic_id
- FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
- WHERE $sql_author
- $sql_topic_id
- $sql_firstpost
- $m_approve_fid_sql
- $sql_fora
- AND t.topic_id = p.topic_id
- $sql_sort_join
- $sql_time
- GROUP BY t.topic_id
- ORDER BY $sql_sort";
- $field = 'topic_id';
- }
-
- // Only read one block of posts from the db and then cache it
- $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $id_ary[] = (int) $row[$field];
- }
- $this->db->sql_freeresult($result);
-
- // retrieve the total result count if needed
- if (!$result_count)
- {
- $sql = 'SELECT FOUND_ROWS() as result_count';
- $result = $this->db->sql_query($sql);
- $result_count = (int) $this->db->sql_fetchfield('result_count');
- $this->db->sql_freeresult($result);
-
- if (!$result_count)
- {
- return false;
- }
- }
-
- if (sizeof($id_ary))
- {
- $this->save_ids($search_key, '', $author_ary, $result_count, $id_ary, $start, $sort_dir);
- $id_ary = array_slice($id_ary, 0, $per_page);
-
- return $result_count;
- }
- return false;
- }
-
- /**
- * Destroys cached search results, that contained one of the new words in a post so the results won't be outdated
- *
- * @param string $mode contains the post mode: edit, post, reply, quote ...
- * @param int $post_id contains the post id of the post to index
- * @param string $message contains the post text of the post
- * @param string $subject contains the subject of the post to index
- * @param int $poster_id contains the user id of the poster
- * @param int $forum_id contains the forum id of parent forum of the post
- */
- public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id)
- {
- // Split old and new post/subject to obtain array of words
- $split_text = $this->split_message($message);
- $split_title = ($subject) ? $this->split_message($subject) : array();
-
- $words = array_unique(array_merge($split_text, $split_title));
-
- unset($split_text);
- unset($split_title);
-
- // destroy cached search results containing any of the words removed or added
- $this->destroy_cache($words, array($poster_id));
-
- unset($words);
- }
-
- /**
- * Destroy cached results, that might be outdated after deleting a post
- */
- public function index_remove($post_ids, $author_ids, $forum_ids)
- {
- $this->destroy_cache(array(), array_unique($author_ids));
- }
-
- /**
- * Destroy old cache entries
- */
- public function tidy()
- {
- // destroy too old cached search results
- $this->destroy_cache(array());
-
- set_config('search_last_gc', time(), true);
- }
-
- /**
- * Create fulltext index
- *
- * @return string|bool error string is returned incase of errors otherwise false
- */
- public function create_index($acp_module, $u_action)
- {
- // Make sure we can actually use MySQL with fulltext indexes
- if ($error = $this->init())
- {
- return $error;
- }
-
- if (empty($this->stats))
- {
- $this->get_stats();
- }
-
- $alter = array();
-
- if (!isset($this->stats['post_subject']))
- {
- if ($this->db->sql_layer == 'mysqli' || version_compare($this->db->sql_server_info(true), '4.1.3', '>='))
- {
- $alter[] = 'MODIFY post_subject varchar(255) COLLATE utf8_unicode_ci DEFAULT \'\' NOT NULL';
- }
- else
- {
- $alter[] = 'MODIFY post_subject text NOT NULL';
- }
- $alter[] = 'ADD FULLTEXT (post_subject)';
- }
-
- if (!isset($this->stats['post_text']))
- {
- if ($this->db->sql_layer == 'mysqli' || version_compare($this->db->sql_server_info(true), '4.1.3', '>='))
- {
- $alter[] = 'MODIFY post_text mediumtext COLLATE utf8_unicode_ci NOT NULL';
- }
- else
- {
- $alter[] = 'MODIFY post_text mediumtext NOT NULL';
- }
- $alter[] = 'ADD FULLTEXT (post_text)';
- }
-
- if (!isset($this->stats['post_content']))
- {
- $alter[] = 'ADD FULLTEXT post_content (post_subject, post_text)';
- }
-
- if (sizeof($alter))
- {
- $this->db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter));
- }
-
- $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);
-
- return false;
- }
-
- /**
- * Drop fulltext index
- *
- * @return string|bool error string is returned incase of errors otherwise false
- */
- public function delete_index($acp_module, $u_action)
- {
- // Make sure we can actually use MySQL with fulltext indexes
- if ($error = $this->init())
- {
- return $error;
- }
-
- if (empty($this->stats))
- {
- $this->get_stats();
- }
-
- $alter = array();
-
- if (isset($this->stats['post_subject']))
- {
- $alter[] = 'DROP INDEX post_subject';
- }
-
- if (isset($this->stats['post_text']))
- {
- $alter[] = 'DROP INDEX post_text';
- }
-
- if (isset($this->stats['post_content']))
- {
- $alter[] = 'DROP INDEX post_content';
- }
-
- if (sizeof($alter))
- {
- $this->db->sql_query('ALTER TABLE ' . POSTS_TABLE . ' ' . implode(', ', $alter));
- }
-
- $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);
-
- return false;
- }
-
- /**
- * Returns true if both FULLTEXT indexes exist
- */
- public function index_created()
- {
- if (empty($this->stats))
- {
- $this->get_stats();
- }
-
- return (isset($this->stats['post_text']) && isset($this->stats['post_subject']) && isset($this->stats['post_content'])) ? true : false;
- }
-
- /**
- * Returns an associative array containing information about the indexes
- */
- public function index_stats()
- {
- if (empty($this->stats))
- {
- $this->get_stats();
- }
-
- return array(
- $this->user->lang['FULLTEXT_MYSQL_TOTAL_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] : 0,
- );
- }
-
- /**
- * Computes the stats and store them in the $this->stats associative array
- */
- protected function get_stats()
- {
- if (strpos($this->db->sql_layer, 'mysql') === false)
- {
- $this->stats = array();
- return;
- }
-
- $sql = 'SHOW INDEX
- FROM ' . POSTS_TABLE;
- $result = $this->db->sql_query($sql);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- // deal with older MySQL versions which didn't use Index_type
- $index_type = (isset($row['Index_type'])) ? $row['Index_type'] : $row['Comment'];
-
- if ($index_type == 'FULLTEXT')
- {
- if ($row['Key_name'] == 'post_text')
- {
- $this->stats['post_text'] = $row;
- }
- else if ($row['Key_name'] == 'post_subject')
- {
- $this->stats['post_subject'] = $row;
- }
- else if ($row['Key_name'] == 'post_content')
- {
- $this->stats['post_content'] = $row;
- }
- }
- }
- $this->db->sql_freeresult($result);
-
- $this->stats['total_posts'] = empty($this->stats) ? 0 : $this->db->get_estimated_row_count(POSTS_TABLE);
- }
-
- /**
- * Display a note, that UTF-8 support is not available with certain versions of PHP
- *
- * @return associative array containing template and config variables
- */
- public function acp()
- {
- $tpl = '
- <dl>
- <dt><label>' . $this->user->lang['MIN_SEARCH_CHARS'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_MYSQL_MIN_SEARCH_CHARS_EXPLAIN'] . '</span></dt>
- <dd>' . $this->config['fulltext_mysql_min_word_len'] . '</dd>
- </dl>
- <dl>
- <dt><label>' . $this->user->lang['MAX_SEARCH_CHARS'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_MYSQL_MAX_SEARCH_CHARS_EXPLAIN'] . '</span></dt>
- <dd>' . $this->config['fulltext_mysql_max_word_len'] . '</dd>
- </dl>
- ';
-
- // These are fields required in the config table
- return array(
- 'tpl' => $tpl,
- 'config' => array()
- );
- }
-}
diff --git a/phpBB/includes/search/fulltext_native.php b/phpBB/includes/search/fulltext_native.php
deleted file mode 100644
index 4623326fc7..0000000000
--- a/phpBB/includes/search/fulltext_native.php
+++ /dev/null
@@ -1,1817 +0,0 @@
-<?php
-/**
-*
-* @package search
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* fulltext_native
-* phpBB's own db driven fulltext search, version 2
-* @package search
-*/
-class phpbb_search_fulltext_native extends phpbb_search_base
-{
- /**
- * Associative array holding index stats
- * @var array
- */
- protected $stats = array();
-
- /**
- * Associative array stores the min and max word length to be searched
- * @var array
- */
- protected $word_length = array();
-
- /**
- * Contains tidied search query.
- * Operators are prefixed in search query and common words excluded
- * @var string
- */
- protected $search_query;
-
- /**
- * Contains common words.
- * Common words are words with length less/more than min/max length
- * @var array
- */
- protected $common_words = array();
-
- /**
- * Post ids of posts containing words that are to be included
- * @var array
- */
- protected $must_contain_ids = array();
-
- /**
- * Post ids of posts containing words that should not be included
- * @var array
- */
- protected $must_not_contain_ids = array();
-
- /**
- * Post ids of posts containing atleast one word that needs to be excluded
- * @var array
- */
- protected $must_exclude_one_ids = array();
-
- /**
- * Relative path to board root
- * @var string
- */
- protected $phpbb_root_path;
-
- /**
- * PHP Extension
- * @var string
- */
- protected $php_ext;
-
- /**
- * Config object
- * @var phpbb_config
- */
- protected $config;
-
- /**
- * DBAL object
- * @var dbal
- */
- protected $db;
-
- /**
- * User object
- * @var phpbb_user
- */
- protected $user;
-
- /**
- * Initialises the fulltext_native search backend with min/max word length and makes sure the UTF-8 normalizer is loaded
- *
- * @param boolean|string &$error is passed by reference and should either be set to false on success or an error message on failure
- */
- public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user)
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $phpEx;
- $this->config = $config;
- $this->db = $db;
- $this->user = $user;
-
- $this->word_length = array('min' => $this->config['fulltext_native_min_chars'], 'max' => $this->config['fulltext_native_max_chars']);
-
- /**
- * Load the UTF tools
- */
- if (!class_exists('utf_normalizer'))
- {
- include($this->phpbb_root_path . 'includes/utf/utf_normalizer.' . $this->php_ext);
- }
- if (!function_exists('utf8_decode_ncr'))
- {
- include($this->phpbb_root_path . 'includes/utf/utf_tools.' . $this->php_ext);
- }
-
- $error = false;
- }
-
- /**
- * Returns the name of this search backend to be displayed to administrators
- *
- * @return string Name
- */
- public function get_name()
- {
- return 'phpBB Native Fulltext';
- }
-
- /**
- * Returns the search_query
- *
- * @return string search query
- */
- public function get_search_query()
- {
- return $this->search_query;
- }
-
- /**
- * Returns the common_words array
- *
- * @return array common words that are ignored by search backend
- */
- public function get_common_words()
- {
- return $this->common_words;
- }
-
- /**
- * Returns the word_length array
- *
- * @return array min and max word length for searching
- */
- public function get_word_length()
- {
- return $this->word_length;
- }
-
- /**
- * This function fills $this->search_query with the cleaned user search query
- *
- * If $terms is 'any' then the words will be extracted from the search query
- * and combined with | inside brackets. They will afterwards be treated like
- * an standard search query.
- *
- * Then it analyses the query and fills the internal arrays $must_not_contain_ids,
- * $must_contain_ids and $must_exclude_one_ids which are later used by keyword_search()
- *
- * @param string $keywords contains the search query string as entered by the user
- * @param string $terms is either 'all' (use search query as entered, default words to 'must be contained in post')
- * or 'any' (find all posts containing at least one of the given words)
- * @return boolean false if no valid keywords were found and otherwise true
- */
- public function split_keywords($keywords, $terms)
- {
- $tokens = '+-|()*';
-
- $keywords = trim($this->cleanup($keywords, $tokens));
-
- // allow word|word|word without brackets
- if ((strpos($keywords, ' ') === false) && (strpos($keywords, '|') !== false) && (strpos($keywords, '(') === false))
- {
- $keywords = '(' . $keywords . ')';
- }
-
- $open_bracket = $space = false;
- for ($i = 0, $n = strlen($keywords); $i < $n; $i++)
- {
- if ($open_bracket !== false)
- {
- switch ($keywords[$i])
- {
- case ')':
- if ($open_bracket + 1 == $i)
- {
- $keywords[$i - 1] = '|';
- $keywords[$i] = '|';
- }
- $open_bracket = false;
- break;
- case '(':
- $keywords[$i] = '|';
- break;
- case '+':
- case '-':
- case ' ':
- $keywords[$i] = '|';
- break;
- case '*':
- if ($i === 0 || ($keywords[$i - 1] !== '*' && strcspn($keywords[$i - 1], $tokens) === 0))
- {
- if ($i === $n - 1 || ($keywords[$i + 1] !== '*' && strcspn($keywords[$i + 1], $tokens) === 0))
- {
- $keywords = substr($keywords, 0, $i) . substr($keywords, $i + 1);
- }
- }
- break;
- }
- }
- else
- {
- switch ($keywords[$i])
- {
- case ')':
- $keywords[$i] = ' ';
- break;
- case '(':
- $open_bracket = $i;
- $space = false;
- break;
- case '|':
- $keywords[$i] = ' ';
- break;
- case '-':
- case '+':
- $space = $keywords[$i];
- break;
- case ' ':
- if ($space !== false)
- {
- $keywords[$i] = $space;
- }
- break;
- default:
- $space = false;
- }
- }
- }
-
- if ($open_bracket)
- {
- $keywords .= ')';
- }
-
- $match = array(
- '# +#',
- '#\|\|+#',
- '#(\+|\-)(?:\+|\-)+#',
- '#\(\|#',
- '#\|\)#',
- );
- $replace = array(
- ' ',
- '|',
- '$1',
- '(',
- ')',
- );
-
- $keywords = preg_replace($match, $replace, $keywords);
- $num_keywords = sizeof(explode(' ', $keywords));
-
- // We limit the number of allowed keywords to minimize load on the database
- if ($this->config['max_num_search_keywords'] && $num_keywords > $this->config['max_num_search_keywords'])
- {
- trigger_error($this->user->lang('MAX_NUM_SEARCH_KEYWORDS_REFINE', $this->config['max_num_search_keywords'], $num_keywords));
- }
-
- // $keywords input format: each word separated by a space, words in a bracket are not separated
-
- // the user wants to search for any word, convert the search query
- if ($terms == 'any')
- {
- $words = array();
-
- preg_match_all('#([^\\s+\\-|()]+)(?:$|[\\s+\\-|()])#u', $keywords, $words);
- if (sizeof($words[1]))
- {
- $keywords = '(' . implode('|', $words[1]) . ')';
- }
- }
-
- // set the search_query which is shown to the user
- $this->search_query = $keywords;
-
- $exact_words = array();
- preg_match_all('#([^\\s+\\-|*()]+)(?:$|[\\s+\\-|()])#u', $keywords, $exact_words);
- $exact_words = $exact_words[1];
-
- $common_ids = $words = array();
-
- if (sizeof($exact_words))
- {
- $sql = 'SELECT word_id, word_text, word_common
- FROM ' . SEARCH_WORDLIST_TABLE . '
- WHERE ' . $this->db->sql_in_set('word_text', $exact_words) . '
- ORDER BY word_count ASC';
- $result = $this->db->sql_query($sql);
-
- // store an array of words and ids, remove common words
- while ($row = $this->db->sql_fetchrow($result))
- {
- if ($row['word_common'])
- {
- $this->common_words[] = $row['word_text'];
- $common_ids[$row['word_text']] = (int) $row['word_id'];
- continue;
- }
-
- $words[$row['word_text']] = (int) $row['word_id'];
- }
- $this->db->sql_freeresult($result);
- }
- unset($exact_words);
-
- // now analyse the search query, first split it using the spaces
- $query = explode(' ', $keywords);
-
- $this->must_contain_ids = array();
- $this->must_not_contain_ids = array();
- $this->must_exclude_one_ids = array();
-
- $mode = '';
- $ignore_no_id = true;
-
- foreach ($query as $word)
- {
- if (empty($word))
- {
- continue;
- }
-
- // words which should not be included
- if ($word[0] == '-')
- {
- $word = substr($word, 1);
-
- // a group of which at least one may not be in the resulting posts
- if ($word[0] == '(')
- {
- $word = array_unique(explode('|', substr($word, 1, -1)));
- $mode = 'must_exclude_one';
- }
- // one word which should not be in the resulting posts
- else
- {
- $mode = 'must_not_contain';
- }
- $ignore_no_id = true;
- }
- // words which have to be included
- else
- {
- // no prefix is the same as a +prefix
- if ($word[0] == '+')
- {
- $word = substr($word, 1);
- }
-
- // a group of words of which at least one word should be in every resulting post
- if ($word[0] == '(')
- {
- $word = array_unique(explode('|', substr($word, 1, -1)));
- }
- $ignore_no_id = false;
- $mode = 'must_contain';
- }
-
- if (empty($word))
- {
- continue;
- }
-
- // if this is an array of words then retrieve an id for each
- if (is_array($word))
- {
- $non_common_words = array();
- $id_words = array();
- foreach ($word as $i => $word_part)
- {
- if (strpos($word_part, '*') !== false)
- {
- $id_words[] = '\'' . $this->db->sql_escape(str_replace('*', '%', $word_part)) . '\'';
- $non_common_words[] = $word_part;
- }
- else if (isset($words[$word_part]))
- {
- $id_words[] = $words[$word_part];
- $non_common_words[] = $word_part;
- }
- else
- {
- $len = utf8_strlen($word_part);
- if ($len < $this->word_length['min'] || $len > $this->word_length['max'])
- {
- $this->common_words[] = $word_part;
- }
- }
- }
- if (sizeof($id_words))
- {
- sort($id_words);
- if (sizeof($id_words) > 1)
- {
- $this->{$mode . '_ids'}[] = $id_words;
- }
- else
- {
- $mode = ($mode == 'must_exclude_one') ? 'must_not_contain' : $mode;
- $this->{$mode . '_ids'}[] = $id_words[0];
- }
- }
- // throw an error if we shall not ignore unexistant words
- else if (!$ignore_no_id && sizeof($non_common_words))
- {
- trigger_error(sprintf($user->lang['WORDS_IN_NO_POST'], implode($user->lang['COMMA_SEPARATOR'], $non_common_words)));
- }
- unset($non_common_words);
- }
- // else we only need one id
- else if (($wildcard = strpos($word, '*') !== false) || isset($words[$word]))
- {
- if ($wildcard)
- {
- $len = utf8_strlen(str_replace('*', '', $word));
- if ($len >= $this->word_length['min'] && $len <= $this->word_length['max'])
- {
- $this->{$mode . '_ids'}[] = '\'' . $this->db->sql_escape(str_replace('*', '%', $word)) . '\'';
- }
- else
- {
- $this->common_words[] = $word;
- }
- }
- else
- {
- $this->{$mode . '_ids'}[] = $words[$word];
- }
- }
- // throw an error if we shall not ignore unexistant words
- else if (!$ignore_no_id)
- {
- if (!isset($common_ids[$word]))
- {
- $len = utf8_strlen($word);
- if ($len >= $this->word_length['min'] && $len <= $this->word_length['max'])
- {
- trigger_error(sprintf($this->user->lang['WORD_IN_NO_POST'], $word));
- }
- else
- {
- $this->common_words[] = $word;
- }
- }
- }
- else
- {
- $len = utf8_strlen($word);
- if ($len < $this->word_length['min'] || $len > $this->word_length['max'])
- {
- $this->common_words[] = $word;
- }
- }
- }
-
- // we can't search for negatives only
- if (!sizeof($this->must_contain_ids))
- {
- return false;
- }
-
- if (!empty($this->search_query))
- {
- return true;
- }
- return false;
- }
-
- /**
- * 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 $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
- */
- 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, $author_name, &$id_ary, $start, $per_page)
- {
- // No keywords? No posts.
- if (empty($this->search_query))
- {
- return false;
- }
-
- $must_contain_ids = $this->must_contain_ids;
- $must_not_contain_ids = $this->must_not_contain_ids;
- $must_exclude_one_ids = $this->must_exclude_one_ids;
-
- sort($must_contain_ids);
- sort($must_not_contain_ids);
- sort($must_exclude_one_ids);
-
- // generate a search_key from all the options to identify the results
- $search_key = md5(implode('#', array(
- serialize($must_contain_ids),
- serialize($must_not_contain_ids),
- serialize($must_exclude_one_ids),
- $type,
- $fields,
- $terms,
- $sort_days,
- $sort_key,
- $topic_id,
- implode(',', $ex_fid_ary),
- implode(',', $m_approve_fid_ary),
- implode(',', $author_ary),
- $author_name,
- )));
-
- // try reading the results from cache
- $total_results = 0;
- if ($this->obtain_ids($search_key, $total_results, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE)
- {
- return $total_results;
- }
-
- $id_ary = array();
-
- $sql_where = array();
- $group_by = false;
- $m_num = 0;
- $w_num = 0;
-
- $sql_array = array(
- 'SELECT' => ($type == 'posts') ? 'p.post_id' : 'p.topic_id',
- 'FROM' => array(
- SEARCH_WORDMATCH_TABLE => array(),
- SEARCH_WORDLIST_TABLE => array(),
- ),
- 'LEFT_JOIN' => array(array(
- 'FROM' => array(POSTS_TABLE => 'p'),
- 'ON' => 'm0.post_id = p.post_id',
- )),
- );
-
- $title_match = '';
- $left_join_topics = false;
- $group_by = true;
- // Build some display specific sql strings
- switch ($fields)
- {
- case 'titleonly':
- $title_match = 'title_match = 1';
- $group_by = false;
- // no break
- case 'firstpost':
- $left_join_topics = true;
- $sql_where[] = 'p.post_id = t.topic_first_post_id';
- break;
-
- case 'msgonly':
- $title_match = 'title_match = 0';
- $group_by = false;
- break;
- }
-
- if ($type == 'topics')
- {
- $left_join_topics = true;
- $group_by = true;
- }
-
- /**
- * @todo Add a query optimizer (handle stuff like "+(4|3) +4")
- */
-
- foreach ($this->must_contain_ids as $subquery)
- {
- if (is_array($subquery))
- {
- $group_by = true;
-
- $word_id_sql = array();
- $word_ids = array();
- foreach ($subquery as $id)
- {
- if (is_string($id))
- {
- $sql_array['LEFT_JOIN'][] = array(
- 'FROM' => array(SEARCH_WORDLIST_TABLE => 'w' . $w_num),
- 'ON' => "w$w_num.word_text LIKE $id"
- );
- $word_ids[] = "w$w_num.word_id";
-
- $w_num++;
- }
- else
- {
- $word_ids[] = $id;
- }
- }
-
- $sql_where[] = $this->db->sql_in_set("m$m_num.word_id", $word_ids);
-
- unset($word_id_sql);
- unset($word_ids);
- }
- else if (is_string($subquery))
- {
- $sql_array['FROM'][SEARCH_WORDLIST_TABLE][] = 'w' . $w_num;
-
- $sql_where[] = "w$w_num.word_text LIKE $subquery";
- $sql_where[] = "m$m_num.word_id = w$w_num.word_id";
-
- $group_by = true;
- $w_num++;
- }
- else
- {
- $sql_where[] = "m$m_num.word_id = $subquery";
- }
-
- $sql_array['FROM'][SEARCH_WORDMATCH_TABLE][] = 'm' . $m_num;
-
- if ($title_match)
- {
- $sql_where[] = "m$m_num.$title_match";
- }
-
- if ($m_num != 0)
- {
- $sql_where[] = "m$m_num.post_id = m0.post_id";
- }
- $m_num++;
- }
-
- foreach ($this->must_not_contain_ids as $key => $subquery)
- {
- if (is_string($subquery))
- {
- $sql_array['LEFT_JOIN'][] = array(
- 'FROM' => array(SEARCH_WORDLIST_TABLE => 'w' . $w_num),
- 'ON' => "w$w_num.word_text LIKE $subquery"
- );
-
- $this->must_not_contain_ids[$key] = "w$w_num.word_id";
-
- $group_by = true;
- $w_num++;
- }
- }
-
- if (sizeof($this->must_not_contain_ids))
- {
- $sql_array['LEFT_JOIN'][] = array(
- 'FROM' => array(SEARCH_WORDMATCH_TABLE => 'm' . $m_num),
- 'ON' => $this->db->sql_in_set("m$m_num.word_id", $this->must_not_contain_ids) . (($title_match) ? " AND m$m_num.$title_match" : '') . " AND m$m_num.post_id = m0.post_id"
- );
-
- $sql_where[] = "m$m_num.word_id IS NULL";
- $m_num++;
- }
-
- foreach ($this->must_exclude_one_ids as $ids)
- {
- $is_null_joins = array();
- foreach ($ids as $id)
- {
- if (is_string($id))
- {
- $sql_array['LEFT_JOIN'][] = array(
- 'FROM' => array(SEARCH_WORDLIST_TABLE => 'w' . $w_num),
- 'ON' => "w$w_num.word_text LIKE $id"
- );
- $id = "w$w_num.word_id";
-
- $group_by = true;
- $w_num++;
- }
-
- $sql_array['LEFT_JOIN'][] = array(
- 'FROM' => array(SEARCH_WORDMATCH_TABLE => 'm' . $m_num),
- 'ON' => "m$m_num.word_id = $id AND m$m_num.post_id = m0.post_id" . (($title_match) ? " AND m$m_num.$title_match" : '')
- );
- $is_null_joins[] = "m$m_num.word_id IS NULL";
-
- $m_num++;
- }
- $sql_where[] = '(' . implode(' OR ', $is_null_joins) . ')';
- }
-
- if (!sizeof($m_approve_fid_ary))
- {
- $sql_where[] = 'p.post_approved = 1';
- }
- else if ($m_approve_fid_ary !== array(-1))
- {
- $sql_where[] = '(p.post_approved = 1 OR ' . $this->db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')';
- }
-
- if ($topic_id)
- {
- $sql_where[] = 'p.topic_id = ' . $topic_id;
- }
-
- if (sizeof($author_ary))
- {
- if ($author_name)
- {
- // first one matches post of registered users, second one guests and deleted users
- $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')';
- }
- else
- {
- $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary);
- }
- $sql_where[] = $sql_author;
- }
-
- if (sizeof($ex_fid_ary))
- {
- $sql_where[] = $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true);
- }
-
- if ($sort_days)
- {
- $sql_where[] = 'p.post_time >= ' . (time() - ($sort_days * 86400));
- }
-
- $sql_array['WHERE'] = implode(' AND ', $sql_where);
-
- $is_mysql = false;
- // if the total result count is not cached yet, retrieve it from the db
- if (!$total_results)
- {
- $sql = '';
- $sql_array_count = $sql_array;
-
- if ($left_join_topics)
- {
- $sql_array_count['LEFT_JOIN'][] = array(
- 'FROM' => array(TOPICS_TABLE => 't'),
- 'ON' => 'p.topic_id = t.topic_id'
- );
- }
-
- switch ($this->db->sql_layer)
- {
- case 'mysql4':
- case 'mysqli':
-
- // 3.x does not support SQL_CALC_FOUND_ROWS
- // $sql_array['SELECT'] = 'SQL_CALC_FOUND_ROWS ' . $sql_array['SELECT'];
- $is_mysql = true;
-
- break;
-
- case 'sqlite':
- $sql_array_count['SELECT'] = ($type == 'posts') ? 'DISTINCT p.post_id' : 'DISTINCT p.topic_id';
- $sql = 'SELECT COUNT(' . (($type == 'posts') ? 'post_id' : 'topic_id') . ') as total_results
- FROM (' . $this->db->sql_build_query('SELECT', $sql_array_count) . ')';
-
- // no break
-
- default:
- $sql_array_count['SELECT'] = ($type == 'posts') ? 'COUNT(DISTINCT p.post_id) AS total_results' : 'COUNT(DISTINCT p.topic_id) AS total_results';
- $sql = (!$sql) ? $this->db->sql_build_query('SELECT', $sql_array_count) : $sql;
-
- $result = $this->db->sql_query($sql);
- $total_results = (int) $this->db->sql_fetchfield('total_results');
- $this->db->sql_freeresult($result);
-
- if (!$total_results)
- {
- return false;
- }
- break;
- }
-
- unset($sql_array_count, $sql);
- }
-
- // Build sql strings for sorting
- $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
-
- switch ($sql_sort[0])
- {
- case 'u':
- $sql_array['FROM'][USERS_TABLE] = 'u';
- $sql_where[] = 'u.user_id = p.poster_id ';
- break;
-
- case 't':
- $left_join_topics = true;
- break;
-
- case 'f':
- $sql_array['FROM'][FORUMS_TABLE] = 'f';
- $sql_where[] = 'f.forum_id = p.forum_id';
- break;
- }
-
- if ($left_join_topics)
- {
- $sql_array['LEFT_JOIN'][] = array(
- 'FROM' => array(TOPICS_TABLE => 't'),
- 'ON' => 'p.topic_id = t.topic_id'
- );
- }
-
- $sql_array['WHERE'] = implode(' AND ', $sql_where);
- $sql_array['GROUP_BY'] = ($group_by) ? (($type == 'posts') ? 'p.post_id' : 'p.topic_id') . ', ' . $sort_by_sql[$sort_key] : '';
- $sql_array['ORDER_BY'] = $sql_sort;
-
- unset($sql_where, $sql_sort, $group_by);
-
- $sql = $this->db->sql_build_query('SELECT', $sql_array);
- $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $id_ary[] = (int) $row[(($type == 'posts') ? 'post_id' : 'topic_id')];
- }
- $this->db->sql_freeresult($result);
-
- if (!sizeof($id_ary))
- {
- return false;
- }
-
- // if we use mysql and the total result count is not cached yet, retrieve it from the db
- if (!$total_results && $is_mysql)
- {
- // Count rows for the executed queries. Replace $select within $sql with SQL_CALC_FOUND_ROWS, and run it
- $sql_array_copy = $sql_array;
- $sql_array_copy['SELECT'] = 'SQL_CALC_FOUND_ROWS p.post_id ';
-
- $sql = $this->db->sql_build_query('SELECT', $sql_array_copy);
- unset($sql_array_copy);
-
- $this->db->sql_query($sql);
- $this->db->sql_freeresult($result);
-
- $sql = 'SELECT FOUND_ROWS() as total_results';
- $result = $this->db->sql_query($sql);
- $total_results = (int) $this->db->sql_fetchfield('total_results');
- $this->db->sql_freeresult($result);
-
- if (!$total_results)
- {
- return false;
- }
- }
-
- // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page
- $this->save_ids($search_key, $this->search_query, $author_ary, $total_results, $id_ary, $start, $sort_dir);
- $id_ary = array_slice($id_ary, 0, (int) $per_page);
-
- return $total_results;
- }
-
- /**
- * Performs a search on an author's posts without caring about message contents. Depends on display specific params
- *
- * @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
- */
- 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, $author_name, &$id_ary, $start, $per_page)
- {
- // No author? No posts
- if (!sizeof($author_ary))
- {
- return 0;
- }
-
- // generate a search_key from all the options to identify the results
- $search_key = md5(implode('#', array(
- '',
- $type,
- ($firstpost_only) ? 'firstpost' : '',
- '',
- '',
- $sort_days,
- $sort_key,
- $topic_id,
- implode(',', $ex_fid_ary),
- implode(',', $m_approve_fid_ary),
- implode(',', $author_ary),
- $author_name,
- )));
-
- // try reading the results from cache
- $total_results = 0;
- if ($this->obtain_ids($search_key, $total_results, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE)
- {
- return $total_results;
- }
-
- $id_ary = array();
-
- // Create some display specific sql strings
- if ($author_name)
- {
- // first one matches post of registered users, second one guests and deleted users
- $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')';
- }
- else
- {
- $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary);
- }
- $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $this->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 : '';
- $sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : '';
-
- // Build sql strings for sorting
- $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
- $sql_sort_table = $sql_sort_join = '';
- switch ($sql_sort[0])
- {
- case 'u':
- $sql_sort_table = USERS_TABLE . ' u, ';
- $sql_sort_join = ' AND u.user_id = p.poster_id ';
- break;
-
- case 't':
- $sql_sort_table = ($type == 'posts' && !$firstpost_only) ? TOPICS_TABLE . ' t, ' : '';
- $sql_sort_join = ($type == 'posts' && !$firstpost_only) ? ' AND t.topic_id = p.topic_id ' : '';
- break;
-
- case 'f':
- $sql_sort_table = FORUMS_TABLE . ' f, ';
- $sql_sort_join = ' AND f.forum_id = p.forum_id ';
- break;
- }
-
- if (!sizeof($m_approve_fid_ary))
- {
- $m_approve_fid_sql = ' AND p.post_approved = 1';
- }
- else if ($m_approve_fid_ary == array(-1))
- {
- $m_approve_fid_sql = '';
- }
- else
- {
- $m_approve_fid_sql = ' AND (p.post_approved = 1 OR ' . $this->db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')';
- }
-
- $select = ($type == 'posts') ? 'p.post_id' : 't.topic_id';
- $is_mysql = false;
-
- // If the cache was completely empty count the results
- if (!$total_results)
- {
- switch ($this->db->sql_layer)
- {
- case 'mysql4':
- case 'mysqli':
-// $select = 'SQL_CALC_FOUND_ROWS ' . $select;
- $is_mysql = true;
- break;
-
- default:
- if ($type == 'posts')
- {
- $sql = 'SELECT COUNT(p.post_id) as total_results
- FROM ' . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . "
- WHERE $sql_author
- $sql_topic_id
- $sql_firstpost
- $m_approve_fid_sql
- $sql_fora
- $sql_time";
- }
- else
- {
- if ($this->db->sql_layer == 'sqlite')
- {
- $sql = 'SELECT COUNT(topic_id) as total_results
- FROM (SELECT DISTINCT t.topic_id';
- }
- else
- {
- $sql = 'SELECT COUNT(DISTINCT t.topic_id) as total_results';
- }
-
- $sql .= ' FROM ' . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
- WHERE $sql_author
- $sql_topic_id
- $sql_firstpost
- $m_approve_fid_sql
- $sql_fora
- AND t.topic_id = p.topic_id
- $sql_time" . (($this->db->sql_layer == 'sqlite') ? ')' : '');
- }
- $result = $this->db->sql_query($sql);
-
- $total_results = (int) $this->db->sql_fetchfield('total_results');
- $this->db->sql_freeresult($result);
-
- if (!$total_results)
- {
- return false;
- }
- break;
- }
- }
-
- // Build the query for really selecting the post_ids
- if ($type == 'posts')
- {
- $sql = "SELECT $select
- FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t' : '') . "
- WHERE $sql_author
- $sql_topic_id
- $sql_firstpost
- $m_approve_fid_sql
- $sql_fora
- $sql_sort_join
- $sql_time
- ORDER BY $sql_sort";
- $field = 'post_id';
- }
- else
- {
- $sql = "SELECT $select
- FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
- WHERE $sql_author
- $sql_topic_id
- $sql_firstpost
- $m_approve_fid_sql
- $sql_fora
- AND t.topic_id = p.topic_id
- $sql_sort_join
- $sql_time
- GROUP BY t.topic_id, " . $sort_by_sql[$sort_key] . '
- ORDER BY ' . $sql_sort;
- $field = 'topic_id';
- }
-
- // Only read one block of posts from the db and then cache it
- $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $id_ary[] = (int) $row[$field];
- }
- $this->db->sql_freeresult($result);
-
- if (!$total_results && $is_mysql)
- {
- // Count rows for the executed queries. Replace $select within $sql with SQL_CALC_FOUND_ROWS, and run it.
- $sql = str_replace('SELECT ' . $select, 'SELECT DISTINCT SQL_CALC_FOUND_ROWS p.post_id', $sql);
-
- $this->db->sql_query($sql);
- $this->db->sql_freeresult($result);
-
- $sql = 'SELECT FOUND_ROWS() as total_results';
- $result = $this->db->sql_query($sql);
- $total_results = (int) $this->db->sql_fetchfield('total_results');
- $this->db->sql_freeresult($result);
-
- if (!$total_results)
- {
- return false;
- }
- }
-
- if (sizeof($id_ary))
- {
- $this->save_ids($search_key, '', $author_ary, $total_results, $id_ary, $start, $sort_dir);
- $id_ary = array_slice($id_ary, 0, $per_page);
-
- return $total_results;
- }
- return false;
- }
-
- /**
- * Split a text into words of a given length
- *
- * The text is converted to UTF-8, cleaned up, and split. Then, words that
- * conform to the defined length range are returned in an array.
- *
- * NOTE: duplicates are NOT removed from the return array
- *
- * @param string $text Text to split, encoded in UTF-8
- * @return array Array of UTF-8 words
- */
- public function split_message($text)
- {
- $match = $words = array();
-
- /**
- * Taken from the original code
- */
- // Do not index code
- $match[] = '#\[code(?:=.*?)?(\:?[0-9a-z]{5,})\].*?\[\/code(\:?[0-9a-z]{5,})\]#is';
- // BBcode
- $match[] = '#\[\/?[a-z0-9\*\+\-]+(?:=.*?)?(?::[a-z])?(\:?[0-9a-z]{5,})\]#';
-
- $min = $this->word_length['min'];
- $max = $this->word_length['max'];
-
- $isset_min = $min - 1;
-
- /**
- * Clean up the string, remove HTML tags, remove BBCodes
- */
- $word = strtok($this->cleanup(preg_replace($match, ' ', strip_tags($text)), -1), ' ');
-
- while (strlen($word))
- {
- if (strlen($word) > 255 || strlen($word) <= $isset_min)
- {
- /**
- * Words longer than 255 bytes are ignored. This will have to be
- * changed whenever we change the length of search_wordlist.word_text
- *
- * Words shorter than $isset_min bytes are ignored, too
- */
- $word = strtok(' ');
- continue;
- }
-
- $len = utf8_strlen($word);
-
- /**
- * Test whether the word is too short to be indexed.
- *
- * Note that this limit does NOT apply to CJK and Hangul
- */
- if ($len < $min)
- {
- /**
- * Note: this could be optimized. If the codepoint is lower than Hangul's range
- * we know that it will also be lower than CJK ranges
- */
- if ((strncmp($word, UTF8_HANGUL_FIRST, 3) < 0 || strncmp($word, UTF8_HANGUL_LAST, 3) > 0)
- && (strncmp($word, UTF8_CJK_FIRST, 3) < 0 || strncmp($word, UTF8_CJK_LAST, 3) > 0)
- && (strncmp($word, UTF8_CJK_B_FIRST, 4) < 0 || strncmp($word, UTF8_CJK_B_LAST, 4) > 0))
- {
- $word = strtok(' ');
- continue;
- }
- }
-
- $words[] = $word;
- $word = strtok(' ');
- }
-
- return $words;
- }
-
- /**
- * Updates wordlist and wordmatch tables when a message is posted or changed
- *
- * @param string $mode Contains the post mode: edit, post, reply, quote
- * @param int $post_id The id of the post which is modified/created
- * @param string &$message New or updated post content
- * @param string &$subject New or updated post subject
- * @param int $poster_id Post author's user id
- * @param int $forum_id The id of the forum in which the post is located
- */
- public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id)
- {
- if (!$this->config['fulltext_native_load_upd'])
- {
- /**
- * The search indexer is disabled, return
- */
- return;
- }
-
- // Split old and new post/subject to obtain array of 'words'
- $split_text = $this->split_message($message);
- $split_title = $this->split_message($subject);
-
- $cur_words = array('post' => array(), 'title' => array());
-
- $words = array();
- if ($mode == 'edit')
- {
- $words['add']['post'] = array();
- $words['add']['title'] = array();
- $words['del']['post'] = array();
- $words['del']['title'] = array();
-
- $sql = 'SELECT w.word_id, w.word_text, m.title_match
- FROM ' . SEARCH_WORDLIST_TABLE . ' w, ' . SEARCH_WORDMATCH_TABLE . " m
- WHERE m.post_id = $post_id
- AND w.word_id = m.word_id";
- $result = $this->db->sql_query($sql);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $which = ($row['title_match']) ? 'title' : 'post';
- $cur_words[$which][$row['word_text']] = $row['word_id'];
- }
- $this->db->sql_freeresult($result);
-
- $words['add']['post'] = array_diff($split_text, array_keys($cur_words['post']));
- $words['add']['title'] = array_diff($split_title, array_keys($cur_words['title']));
- $words['del']['post'] = array_diff(array_keys($cur_words['post']), $split_text);
- $words['del']['title'] = array_diff(array_keys($cur_words['title']), $split_title);
- }
- else
- {
- $words['add']['post'] = $split_text;
- $words['add']['title'] = $split_title;
- $words['del']['post'] = array();
- $words['del']['title'] = array();
- }
- unset($split_text);
- unset($split_title);
-
- // Get unique words from the above arrays
- $unique_add_words = array_unique(array_merge($words['add']['post'], $words['add']['title']));
-
- // We now have unique arrays of all words to be added and removed and
- // individual arrays of added and removed words for text and title. What
- // we need to do now is add the new words (if they don't already exist)
- // and then add (or remove) matches between the words and this post
- if (sizeof($unique_add_words))
- {
- $sql = 'SELECT word_id, word_text
- FROM ' . SEARCH_WORDLIST_TABLE . '
- WHERE ' . $this->db->sql_in_set('word_text', $unique_add_words);
- $result = $this->db->sql_query($sql);
-
- $word_ids = array();
- while ($row = $this->db->sql_fetchrow($result))
- {
- $word_ids[$row['word_text']] = $row['word_id'];
- }
- $this->db->sql_freeresult($result);
- $new_words = array_diff($unique_add_words, array_keys($word_ids));
-
- $this->db->sql_transaction('begin');
- if (sizeof($new_words))
- {
- $sql_ary = array();
-
- foreach ($new_words as $word)
- {
- $sql_ary[] = array('word_text' => (string) $word, 'word_count' => 0);
- }
- $this->db->sql_return_on_error(true);
- $this->db->sql_multi_insert(SEARCH_WORDLIST_TABLE, $sql_ary);
- $this->db->sql_return_on_error(false);
- }
- unset($new_words, $sql_ary);
- }
- else
- {
- $this->db->sql_transaction('begin');
- }
-
- // now update the search match table, remove links to removed words and add links to new words
- foreach ($words['del'] as $word_in => $word_ary)
- {
- $title_match = ($word_in == 'title') ? 1 : 0;
-
- if (sizeof($word_ary))
- {
- $sql_in = array();
- foreach ($word_ary as $word)
- {
- $sql_in[] = $cur_words[$word_in][$word];
- }
-
- $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . '
- WHERE ' . $this->db->sql_in_set('word_id', $sql_in) . '
- AND post_id = ' . intval($post_id) . "
- AND title_match = $title_match";
- $this->db->sql_query($sql);
-
- $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . '
- SET word_count = word_count - 1
- WHERE ' . $this->db->sql_in_set('word_id', $sql_in) . '
- AND word_count > 0';
- $this->db->sql_query($sql);
-
- unset($sql_in);
- }
- }
-
- $this->db->sql_return_on_error(true);
- foreach ($words['add'] as $word_in => $word_ary)
- {
- $title_match = ($word_in == 'title') ? 1 : 0;
-
- if (sizeof($word_ary))
- {
- $sql = 'INSERT INTO ' . SEARCH_WORDMATCH_TABLE . ' (post_id, word_id, title_match)
- SELECT ' . (int) $post_id . ', word_id, ' . (int) $title_match . '
- FROM ' . SEARCH_WORDLIST_TABLE . '
- WHERE ' . $this->db->sql_in_set('word_text', $word_ary);
- $this->db->sql_query($sql);
-
- $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . '
- SET word_count = word_count + 1
- WHERE ' . $this->db->sql_in_set('word_text', $word_ary);
- $this->db->sql_query($sql);
- }
- }
- $this->db->sql_return_on_error(false);
-
- $this->db->sql_transaction('commit');
-
- // destroy cached search results containing any of the words removed or added
- $this->destroy_cache(array_unique(array_merge($words['add']['post'], $words['add']['title'], $words['del']['post'], $words['del']['title'])), array($poster_id));
-
- unset($unique_add_words);
- unset($words);
- unset($cur_words);
- }
-
- /**
- * Removes entries from the wordmatch table for the specified post_ids
- */
- public function index_remove($post_ids, $author_ids, $forum_ids)
- {
- if (sizeof($post_ids))
- {
- $sql = 'SELECT w.word_id, w.word_text, m.title_match
- FROM ' . SEARCH_WORDMATCH_TABLE . ' m, ' . SEARCH_WORDLIST_TABLE . ' w
- WHERE ' . $this->db->sql_in_set('m.post_id', $post_ids) . '
- AND w.word_id = m.word_id';
- $result = $this->db->sql_query($sql);
-
- $message_word_ids = $title_word_ids = $word_texts = array();
- while ($row = $this->db->sql_fetchrow($result))
- {
- if ($row['title_match'])
- {
- $title_word_ids[] = $row['word_id'];
- }
- else
- {
- $message_word_ids[] = $row['word_id'];
- }
- $word_texts[] = $row['word_text'];
- }
- $this->db->sql_freeresult($result);
-
- if (sizeof($title_word_ids))
- {
- $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . '
- SET word_count = word_count - 1
- WHERE ' . $this->db->sql_in_set('word_id', $title_word_ids) . '
- AND word_count > 0';
- $this->db->sql_query($sql);
- }
-
- if (sizeof($message_word_ids))
- {
- $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . '
- SET word_count = word_count - 1
- WHERE ' . $this->db->sql_in_set('word_id', $message_word_ids) . '
- AND word_count > 0';
- $this->db->sql_query($sql);
- }
-
- unset($title_word_ids);
- unset($message_word_ids);
-
- $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . '
- WHERE ' . $this->db->sql_in_set('post_id', $post_ids);
- $this->db->sql_query($sql);
- }
-
- $this->destroy_cache(array_unique($word_texts), array_unique($author_ids));
- }
-
- /**
- * Tidy up indexes: Tag 'common words' and remove
- * words no longer referenced in the match table
- */
- public function tidy()
- {
- // Is the fulltext indexer disabled? If yes then we need not
- // carry on ... it's okay ... I know when I'm not wanted boo hoo
- if (!$this->config['fulltext_native_load_upd'])
- {
- set_config('search_last_gc', time(), true);
- return;
- }
-
- $destroy_cache_words = array();
-
- // Remove common words
- if ($this->config['num_posts'] >= 100 && $this->config['fulltext_native_common_thres'])
- {
- $common_threshold = ((double) $this->config['fulltext_native_common_thres']) / 100.0;
- // First, get the IDs of common words
- $sql = 'SELECT word_id, word_text
- FROM ' . SEARCH_WORDLIST_TABLE . '
- WHERE word_count > ' . floor($this->config['num_posts'] * $common_threshold) . '
- OR word_common = 1';
- $result = $this->db->sql_query($sql);
-
- $sql_in = array();
- while ($row = $this->db->sql_fetchrow($result))
- {
- $sql_in[] = $row['word_id'];
- $destroy_cache_words[] = $row['word_text'];
- }
- $this->db->sql_freeresult($result);
-
- if (sizeof($sql_in))
- {
- // Flag the words
- $sql = 'UPDATE ' . SEARCH_WORDLIST_TABLE . '
- SET word_common = 1
- WHERE ' . $this->db->sql_in_set('word_id', $sql_in);
- $this->db->sql_query($sql);
-
- // by setting search_last_gc to the new time here we make sure that if a user reloads because the
- // following query takes too long, he won't run into it again
- set_config('search_last_gc', time(), true);
-
- // Delete the matches
- $sql = 'DELETE FROM ' . SEARCH_WORDMATCH_TABLE . '
- WHERE ' . $this->db->sql_in_set('word_id', $sql_in);
- $this->db->sql_query($sql);
- }
- unset($sql_in);
- }
-
- if (sizeof($destroy_cache_words))
- {
- // destroy cached search results containing any of the words that are now common or were removed
- $this->destroy_cache(array_unique($destroy_cache_words));
- }
-
- set_config('search_last_gc', time(), true);
- }
-
- /**
- * Deletes all words from the index
- */
- public function delete_index($acp_module, $u_action)
- {
- switch ($this->db->sql_layer)
- {
- case 'sqlite':
- case 'firebird':
- $this->db->sql_query('DELETE FROM ' . SEARCH_WORDLIST_TABLE);
- $this->db->sql_query('DELETE FROM ' . SEARCH_WORDMATCH_TABLE);
- $this->db->sql_query('DELETE FROM ' . SEARCH_RESULTS_TABLE);
- break;
-
- default:
- $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_WORDLIST_TABLE);
- $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_WORDMATCH_TABLE);
- $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);
- break;
- }
- }
-
- /**
- * Returns true if both FULLTEXT indexes exist
- */
- public function index_created()
- {
- if (!sizeof($this->stats))
- {
- $this->get_stats();
- }
-
- return ($this->stats['total_words'] && $this->stats['total_matches']) ? true : false;
- }
-
- /**
- * Returns an associative array containing information about the indexes
- */
- public function index_stats()
- {
- if (!sizeof($this->stats))
- {
- $this->get_stats();
- }
-
- return array(
- $this->user->lang['TOTAL_WORDS'] => $this->stats['total_words'],
- $this->user->lang['TOTAL_MATCHES'] => $this->stats['total_matches']);
- }
-
- protected function get_stats()
- {
- $this->stats['total_words'] = $this->db->get_estimated_row_count(SEARCH_WORDLIST_TABLE);
- $this->stats['total_matches'] = $this->db->get_estimated_row_count(SEARCH_WORDMATCH_TABLE);
- }
-
- /**
- * Clean up a text to remove non-alphanumeric characters
- *
- * This method receives a UTF-8 string, normalizes and validates it, replaces all
- * non-alphanumeric characters with strings then returns the result.
- *
- * Any number of "allowed chars" can be passed as a UTF-8 string in NFC.
- *
- * @param string $text Text to split, in UTF-8 (not normalized or sanitized)
- * @param string $allowed_chars String of special chars to allow
- * @param string $encoding Text encoding
- * @return string Cleaned up text, only alphanumeric chars are left
- *
- * @todo normalizer::cleanup being able to be used?
- */
- protected function cleanup($text, $allowed_chars = null, $encoding = 'utf-8')
- {
- static $conv = array(), $conv_loaded = array();
- $words = $allow = array();
-
- // Convert the text to UTF-8
- $encoding = strtolower($encoding);
- if ($encoding != 'utf-8')
- {
- $text = utf8_recode($text, $encoding);
- }
-
- $utf_len_mask = array(
- "\xC0" => 2,
- "\xD0" => 2,
- "\xE0" => 3,
- "\xF0" => 4
- );
-
- /**
- * Replace HTML entities and NCRs
- */
- $text = htmlspecialchars_decode(utf8_decode_ncr($text), ENT_QUOTES);
-
- /**
- * Load the UTF-8 normalizer
- *
- * If we use it more widely, an instance of that class should be held in a
- * a global variable instead
- */
- utf_normalizer::nfc($text);
-
- /**
- * The first thing we do is:
- *
- * - convert ASCII-7 letters to lowercase
- * - remove the ASCII-7 non-alpha characters
- * - remove the bytes that should not appear in a valid UTF-8 string: 0xC0,
- * 0xC1 and 0xF5-0xFF
- *
- * @todo in theory, the third one is already taken care of during normalization and those chars should have been replaced by Unicode replacement chars
- */
- $sb_match = "ISTCPAMELRDOJBNHFGVWUQKYXZ\r\n\t!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\xC0\xC1\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF";
- $sb_replace = 'istcpamelrdojbnhfgvwuqkyxz ';
-
- /**
- * This is the list of legal ASCII chars, it is automatically extended
- * with ASCII chars from $allowed_chars
- */
- $legal_ascii = ' eaisntroludcpmghbfvq10xy2j9kw354867z';
-
- /**
- * Prepare an array containing the extra chars to allow
- */
- if (isset($allowed_chars[0]))
- {
- $pos = 0;
- $len = strlen($allowed_chars);
- do
- {
- $c = $allowed_chars[$pos];
-
- if ($c < "\x80")
- {
- /**
- * ASCII char
- */
- $sb_pos = strpos($sb_match, $c);
- if (is_int($sb_pos))
- {
- /**
- * Remove the char from $sb_match and its corresponding
- * replacement in $sb_replace
- */
- $sb_match = substr($sb_match, 0, $sb_pos) . substr($sb_match, $sb_pos + 1);
- $sb_replace = substr($sb_replace, 0, $sb_pos) . substr($sb_replace, $sb_pos + 1);
- $legal_ascii .= $c;
- }
-
- ++$pos;
- }
- else
- {
- /**
- * UTF-8 char
- */
- $utf_len = $utf_len_mask[$c & "\xF0"];
- $allow[substr($allowed_chars, $pos, $utf_len)] = 1;
- $pos += $utf_len;
- }
- }
- while ($pos < $len);
- }
-
- $text = strtr($text, $sb_match, $sb_replace);
- $ret = '';
-
- $pos = 0;
- $len = strlen($text);
-
- do
- {
- /**
- * Do all consecutive ASCII chars at once
- */
- if ($spn = strspn($text, $legal_ascii, $pos))
- {
- $ret .= substr($text, $pos, $spn);
- $pos += $spn;
- }
-
- if ($pos >= $len)
- {
- return $ret;
- }
-
- /**
- * Capture the UTF char
- */
- $utf_len = $utf_len_mask[$text[$pos] & "\xF0"];
- $utf_char = substr($text, $pos, $utf_len);
- $pos += $utf_len;
-
- if (($utf_char >= UTF8_HANGUL_FIRST && $utf_char <= UTF8_HANGUL_LAST)
- || ($utf_char >= UTF8_CJK_FIRST && $utf_char <= UTF8_CJK_LAST)
- || ($utf_char >= UTF8_CJK_B_FIRST && $utf_char <= UTF8_CJK_B_LAST))
- {
- /**
- * All characters within these ranges are valid
- *
- * We separate them with a space in order to index each character
- * individually
- */
- $ret .= ' ' . $utf_char . ' ';
- continue;
- }
-
- if (isset($allow[$utf_char]))
- {
- /**
- * The char is explicitly allowed
- */
- $ret .= $utf_char;
- continue;
- }
-
- if (isset($conv[$utf_char]))
- {
- /**
- * The char is mapped to something, maybe to itself actually
- */
- $ret .= $conv[$utf_char];
- continue;
- }
-
- /**
- * The char isn't mapped, but did we load its conversion table?
- *
- * The search indexer table is split into blocks. The block number of
- * each char is equal to its codepoint right-shifted for 11 bits. It
- * means that out of the 11, 16 or 21 meaningful bits of a 2-, 3- or
- * 4- byte sequence we only keep the leftmost 0, 5 or 10 bits. Thus,
- * all UTF chars encoded in 2 bytes are in the same first block.
- */
- if (isset($utf_char[2]))
- {
- if (isset($utf_char[3]))
- {
- /**
- * 1111 0nnn 10nn nnnn 10nx xxxx 10xx xxxx
- * 0000 0111 0011 1111 0010 0000
- */
- $idx = ((ord($utf_char[0]) & 0x07) << 7) | ((ord($utf_char[1]) & 0x3F) << 1) | ((ord($utf_char[2]) & 0x20) >> 5);
- }
- else
- {
- /**
- * 1110 nnnn 10nx xxxx 10xx xxxx
- * 0000 0111 0010 0000
- */
- $idx = ((ord($utf_char[0]) & 0x07) << 1) | ((ord($utf_char[1]) & 0x20) >> 5);
- }
- }
- else
- {
- /**
- * 110x xxxx 10xx xxxx
- * 0000 0000 0000 0000
- */
- $idx = 0;
- }
-
- /**
- * Check if the required conv table has been loaded already
- */
- if (!isset($conv_loaded[$idx]))
- {
- $conv_loaded[$idx] = 1;
- $file = $this->phpbb_root_path . 'includes/utf/data/search_indexer_' . $idx . '.' . $this->php_ext;
-
- if (file_exists($file))
- {
- $conv += include($file);
- }
- }
-
- if (isset($conv[$utf_char]))
- {
- $ret .= $conv[$utf_char];
- }
- else
- {
- /**
- * We add an entry to the conversion table so that we
- * don't have to convert to codepoint and perform the checks
- * that are above this block
- */
- $conv[$utf_char] = ' ';
- $ret .= ' ';
- }
- }
- while (1);
-
- return $ret;
- }
-
- /**
- * Returns a list of options for the ACP to display
- */
- public function acp()
- {
- /**
- * if we need any options, copied from fulltext_native for now, will have to be adjusted or removed
- */
-
- $tpl = '
- <dl>
- <dt><label for="fulltext_native_load_upd">' . $this->user->lang['YES_SEARCH_UPDATE'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['YES_SEARCH_UPDATE_EXPLAIN'] . '</span></dt>
- <dd><label><input type="radio" id="fulltext_native_load_upd" name="config[fulltext_native_load_upd]" value="1"' . (($this->config['fulltext_native_load_upd']) ? ' checked="checked"' : '') . ' class="radio" /> ' . $this->user->lang['YES'] . '</label><label><input type="radio" name="config[fulltext_native_load_upd]" value="0"' . ((!$this->config['fulltext_native_load_upd']) ? ' checked="checked"' : '') . ' class="radio" /> ' . $this->user->lang['NO'] . '</label></dd>
- </dl>
- <dl>
- <dt><label for="fulltext_native_min_chars">' . $this->user->lang['MIN_SEARCH_CHARS'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['MIN_SEARCH_CHARS_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_native_min_chars" type="text" size="3" maxlength="3" name="config[fulltext_native_min_chars]" value="' . (int) $this->config['fulltext_native_min_chars'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="fulltext_native_max_chars">' . $this->user->lang['MAX_SEARCH_CHARS'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['MAX_SEARCH_CHARS_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_native_max_chars" type="text" size="3" maxlength="3" name="config[fulltext_native_max_chars]" value="' . (int) $this->config['fulltext_native_max_chars'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="fulltext_native_common_thres">' . $this->user->lang['COMMON_WORD_THRESHOLD'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['COMMON_WORD_THRESHOLD_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_native_common_thres" type="text" size="3" maxlength="3" name="config[fulltext_native_common_thres]" value="' . (double) $this->config['fulltext_native_common_thres'] . '" /> %</dd>
- </dl>
- ';
-
- // These are fields required in the config table
- return array(
- 'tpl' => $tpl,
- 'config' => array('fulltext_native_load_upd' => 'bool', 'fulltext_native_min_chars' => 'integer:0:255', 'fulltext_native_max_chars' => 'integer:0:255', 'fulltext_native_common_thres' => 'double:0:100')
- );
- }
-}
diff --git a/phpBB/includes/search/fulltext_postgres.php b/phpBB/includes/search/fulltext_postgres.php
deleted file mode 100644
index 2880610655..0000000000
--- a/phpBB/includes/search/fulltext_postgres.php
+++ /dev/null
@@ -1,910 +0,0 @@
-<?php
-/**
-*
-* @package search
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* fulltext_postgres
-* Fulltext search for PostgreSQL
-* @package search
-*/
-class phpbb_search_fulltext_postgres extends phpbb_search_base
-{
- /**
- * Associative array holding index stats
- * @var array
- */
- protected $stats = array();
-
- /**
- * Holds the words entered by user, obtained by splitting the entered query on whitespace
- * @var array
- */
- protected $split_words = array();
-
- /**
- * True if PostgreSQL version supports tsearch
- * @var boolean
- */
- protected $tsearch_usable = false;
-
- /**
- * Stores the PostgreSQL version
- * @var string
- */
- protected $version;
-
- /**
- * Stores the tsearch query
- * @var string
- */
- protected $tsearch_query;
-
- /**
- * True if phrase search is supported.
- * PostgreSQL fulltext currently doesn't support it
- * @var boolean
- */
- protected $phrase_search = false;
-
- /**
- * Config object
- * @var phpbb_config
- */
- protected $config;
-
- /**
- * DBAL object
- * @var dbal
- */
- protected $db;
-
- /**
- * User object
- * @var phpbb_user
- */
- protected $user;
-
- /**
- * Contains tidied search query.
- * Operators are prefixed in search query and common words excluded
- * @var string
- */
- protected $search_query;
-
- /**
- * Contains common words.
- * Common words are words with length less/more than min/max length
- * @var array
- */
- protected $common_words = array();
-
- /**
- * Associative array stores the min and max word length to be searched
- * @var array
- */
- protected $word_length = array();
-
- /**
- * Constructor
- * Creates a new phpbb_search_fulltext_postgres, which is used as a search backend
- *
- * @param string|bool $error Any error that occurs is passed on through this reference variable otherwise false
- */
- public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user)
- {
- $this->config = $config;
- $this->db = $db;
- $this->user = $user;
-
- $this->word_length = array('min' => $this->config['fulltext_postgres_min_word_len'], 'max' => $this->config['fulltext_postgres_max_word_len']);
-
- if ($this->db->sql_layer == 'postgres')
- {
- $pgsql_version = explode(',', substr($this->db->sql_server_info(), 10));
- $this->version = trim($pgsql_version[0]);
- if (version_compare($this->version, '8.3', '>='))
- {
- $this->tsearch_usable = true;
- }
- }
-
- /**
- * Load the UTF tools
- */
- if (!function_exists('utf8_strlen'))
- {
- include($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
- }
-
- $error = false;
- }
-
- /**
- * Returns the name of this search backend to be displayed to administrators
- *
- * @return string Name
- */
- public function get_name()
- {
- return 'PostgreSQL Fulltext';
- }
-
- /**
- * Returns the search_query
- *
- * @return string search query
- */
- public function get_search_query()
- {
- return $this->search_query;
- }
-
- /**
- * Returns the common_words array
- *
- * @return array common words that are ignored by search backend
- */
- public function get_common_words()
- {
- return $this->common_words;
- }
-
- /**
- * Returns the word_length array
- *
- * @return array min and max word length for searching
- */
- public function get_word_length()
- {
- return $this->word_length;
- }
-
- /**
- * Returns if phrase search is supported or not
- *
- * @return bool
- */
- public function supports_phrase_search()
- {
- return $this->phrase_search;
- }
-
- /**
- * Checks for correct PostgreSQL version and stores min/max word length in the config
- *
- * @return string|bool Language key of the error/incompatiblity occured
- */
- public function init()
- {
- if ($this->db->sql_layer != 'postgres')
- {
- return $this->user->lang['FULLTEXT_POSTGRES_INCOMPATIBLE_DATABASE'];
- }
-
- if (!$this->tsearch_usable)
- {
- return $this->user->lang['FULLTEXT_POSTGRES_TS_NOT_USABLE'];
- }
-
- return false;
- }
-
- /**
- * Splits keywords entered by a user into an array of words stored in $this->split_words
- * Stores the tidied search query in $this->search_query
- *
- * @param string &$keywords Contains the keyword as entered by the user
- * @param string $terms is either 'all' or 'any'
- * @return bool false if no valid keywords were found and otherwise true
- */
- public function split_keywords(&$keywords, $terms)
- {
- if ($terms == 'all')
- {
- $match = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#\+#', '#-#', '#\|#');
- $replace = array(' +', ' |', ' -', ' +', ' -', ' |');
-
- $keywords = preg_replace($match, $replace, $keywords);
- }
-
- // Filter out as above
- $split_keywords = preg_replace("#[\"\n\r\t]+#", ' ', trim(htmlspecialchars_decode($keywords)));
-
- // Split words
- $split_keywords = preg_replace('#([^\p{L}\p{N}\'*"()])#u', '$1$1', str_replace('\'\'', '\' \'', trim($split_keywords)));
- $matches = array();
- preg_match_all('#(?:[^\p{L}\p{N}*"()]|^)([+\-|]?(?:[\p{L}\p{N}*"()]+\'?)*[\p{L}\p{N}*"()])(?:[^\p{L}\p{N}*"()]|$)#u', $split_keywords, $matches);
- $this->split_words = $matches[1];
-
- foreach ($this->split_words as $i => $word)
- {
- $clean_word = preg_replace('#^[+\-|"]#', '', $word);
-
- // check word length
- $clean_len = utf8_strlen(str_replace('*', '', $clean_word));
- if (($clean_len < $this->config['fulltext_postgres_min_word_len']) || ($clean_len > $this->config['fulltext_postgres_max_word_len']))
- {
- $this->common_words[] = $word;
- unset($this->split_words[$i]);
- }
- }
-
- if ($terms == 'any')
- {
- $this->search_query = '';
- $this->tsearch_query = '';
- foreach ($this->split_words as $word)
- {
- if ((strpos($word, '+') === 0) || (strpos($word, '-') === 0) || (strpos($word, '|') === 0))
- {
- $word = substr($word, 1);
- }
- $this->search_query .= $word . ' ';
- $this->tsearch_query .= '|' . $word . ' ';
- }
- }
- else
- {
- $this->search_query = '';
- $this->tsearch_query = '';
- foreach ($this->split_words as $word)
- {
- if (strpos($word, '+') === 0)
- {
- $this->search_query .= $word . ' ';
- $this->tsearch_query .= '&' . substr($word, 1) . ' ';
- }
- elseif (strpos($word, '-') === 0)
- {
- $this->search_query .= $word . ' ';
- $this->tsearch_query .= '&!' . substr($word, 1) . ' ';
- }
- elseif (strpos($word, '|') === 0)
- {
- $this->search_query .= $word . ' ';
- $this->tsearch_query .= '|' . substr($word, 1) . ' ';
- }
- else
- {
- $this->search_query .= '+' . $word . ' ';
- $this->tsearch_query .= '&' . $word . ' ';
- }
- }
- }
-
- $this->tsearch_query = substr($this->tsearch_query, 1);
- $this->search_query = utf8_htmlspecialchars($this->search_query);
-
- if ($this->search_query)
- {
- $this->split_words = array_values($this->split_words);
- sort($this->split_words);
- return true;
- }
- return false;
- }
-
- /**
- * Turns text into an array of words
- * @param string $text contains post text/subject
- */
- public function split_message($text)
- {
- // Split words
- $text = preg_replace('#([^\p{L}\p{N}\'*])#u', '$1$1', str_replace('\'\'', '\' \'', trim($text)));
- $matches = array();
- preg_match_all('#(?:[^\p{L}\p{N}*]|^)([+\-|]?(?:[\p{L}\p{N}*]+\'?)*[\p{L}\p{N}*])(?:[^\p{L}\p{N}*]|$)#u', $text, $matches);
- $text = $matches[1];
-
- // remove too short or too long words
- $text = array_values($text);
- for ($i = 0, $n = sizeof($text); $i < $n; $i++)
- {
- $text[$i] = trim($text[$i]);
- if (utf8_strlen($text[$i]) < $this->config['fulltext_postgres_min_word_len'] || utf8_strlen($text[$i]) > $this->config['fulltext_postgres_max_word_len'])
- {
- unset($text[$i]);
- }
- }
-
- return array_values($text);
- }
-
- /**
- * 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 $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
- */
- 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, $author_name, &$id_ary, $start, $per_page)
- {
- // No keywords? No posts
- if (!$this->search_query)
- {
- return false;
- }
-
- // When search query contains queries like -foo
- if (strpos($this->search_query, '+') === false)
- {
- return false;
- }
-
- // generate a search_key from all the options to identify the results
- $search_key = md5(implode('#', array(
- implode(', ', $this->split_words),
- $type,
- $fields,
- $terms,
- $sort_days,
- $sort_key,
- $topic_id,
- implode(',', $ex_fid_ary),
- implode(',', $m_approve_fid_ary),
- implode(',', $author_ary)
- )));
-
- // try reading the results from cache
- $result_count = 0;
- if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE)
- {
- return $result_count;
- }
-
- $id_ary = array();
-
- $join_topic = ($type == 'posts') ? false : true;
-
- // Build sql strings for sorting
- $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
- $sql_sort_table = $sql_sort_join = '';
-
- switch ($sql_sort[0])
- {
- case 'u':
- $sql_sort_table = USERS_TABLE . ' u, ';
- $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster ';
- break;
-
- case 't':
- $join_topic = true;
- break;
-
- case 'f':
- $sql_sort_table = FORUMS_TABLE . ' f, ';
- $sql_sort_join = ' AND f.forum_id = p.forum_id ';
- break;
- }
-
- // Build some display specific sql strings
- switch ($fields)
- {
- case 'titleonly':
- $sql_match = 'p.post_subject';
- $sql_match_where = ' AND p.post_id = t.topic_first_post_id';
- $join_topic = true;
- break;
-
- case 'msgonly':
- $sql_match = 'p.post_text';
- $sql_match_where = '';
- break;
-
- case 'firstpost':
- $sql_match = 'p.post_subject, p.post_text';
- $sql_match_where = ' AND p.post_id = t.topic_first_post_id';
- $join_topic = true;
- break;
-
- default:
- $sql_match = 'p.post_subject, p.post_text';
- $sql_match_where = '';
- break;
- }
-
- if (!sizeof($m_approve_fid_ary))
- {
- $m_approve_fid_sql = ' AND p.post_approved = 1';
- }
- else if ($m_approve_fid_ary === array(-1))
- {
- $m_approve_fid_sql = '';
- }
- else
- {
- $m_approve_fid_sql = ' AND (p.post_approved = 1 OR ' . $this->db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')';
- }
-
- $sql_select = ($type == 'posts') ? 'p.post_id' : 'DISTINCT 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 = '(' . $this->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 ' . $this->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 ' . $this->db->sql_in_set('p.forum_id', $ex_fid_ary, true) : '';
- $sql_where_options .= $m_approve_fid_sql;
- $sql_where_options .= $sql_author;
- $sql_where_options .= ($sort_days) ? ' AND p.post_time >= ' . (time() - ($sort_days * 86400)) : '';
- $sql_where_options .= $sql_match_where;
-
- $tmp_sql_match = array();
- foreach (explode(',', $sql_match) as $sql_match_column)
- {
- $tmp_sql_match[] = "to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', " . $sql_match_column . ") @@ to_tsquery ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', '" . $this->db->sql_escape($this->tsearch_query) . "')";
- }
-
- $sql = "SELECT $sql_select
- FROM $sql_from$sql_sort_table" . POSTS_TABLE . " p
- WHERE (" . implode(' OR ', $tmp_sql_match) . ")
- $sql_where_options
- ORDER BY $sql_sort";
- $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $id_ary[] = $row[$field];
- }
- $this->db->sql_freeresult($result);
-
- $id_ary = array_unique($id_ary);
-
- if (!sizeof($id_ary))
- {
- return false;
- }
-
- // if the total result count is not cached yet, retrieve it from the db
- if (!$result_count)
- {
- $result_count = sizeof ($id_ary);
-
- if (!$result_count)
- {
- return false;
- }
- }
-
- // store the ids, from start on then delete anything that isn't on the current page because we only need ids for one page
- $this->save_ids($search_key, implode(' ', $this->split_words), $author_ary, $result_count, $id_ary, $start, $sort_dir);
- $id_ary = array_slice($id_ary, 0, (int) $per_page);
-
- return $result_count;
- }
-
- /**
- * Performs a search on an author's posts without caring about message contents. Depends on display specific params
- *
- * @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
- */
- 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, $author_name, &$id_ary, $start, $per_page)
- {
- // No author? No posts
- if (!sizeof($author_ary))
- {
- return 0;
- }
-
- // generate a search_key from all the options to identify the results
- $search_key = md5(implode('#', array(
- '',
- $type,
- ($firstpost_only) ? 'firstpost' : '',
- '',
- '',
- $sort_days,
- $sort_key,
- $topic_id,
- implode(',', $ex_fid_ary),
- implode(',', $m_approve_fid_ary),
- implode(',', $author_ary),
- $author_name,
- )));
-
- // try reading the results from cache
- $result_count = 0;
- if ($this->obtain_ids($search_key, $result_count, $id_ary, $start, $per_page, $sort_dir) == SEARCH_RESULT_IN_CACHE)
- {
- return $result_count;
- }
-
- $id_ary = array();
-
- // Create some display specific sql strings
- if ($author_name)
- {
- // first one matches post of registered users, second one guests and deleted users
- $sql_author = '(' . $this->db->sql_in_set('p.poster_id', array_diff($author_ary, array(ANONYMOUS)), false, true) . ' OR p.post_username ' . $author_name . ')';
- }
- else
- {
- $sql_author = $this->db->sql_in_set('p.poster_id', $author_ary);
- }
- $sql_fora = (sizeof($ex_fid_ary)) ? ' AND ' . $this->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)) : '';
- $sql_firstpost = ($firstpost_only) ? ' AND p.post_id = t.topic_first_post_id' : '';
-
- // Build sql strings for sorting
- $sql_sort = $sort_by_sql[$sort_key] . (($sort_dir == 'a') ? ' ASC' : ' DESC');
- $sql_sort_table = $sql_sort_join = '';
- switch ($sql_sort[0])
- {
- case 'u':
- $sql_sort_table = USERS_TABLE . ' u, ';
- $sql_sort_join = ($type == 'posts') ? ' AND u.user_id = p.poster_id ' : ' AND u.user_id = t.topic_poster ';
- break;
-
- case 't':
- $sql_sort_table = ($type == 'posts' && !$firstpost_only) ? TOPICS_TABLE . ' t, ' : '';
- $sql_sort_join = ($type == 'posts' && !$firstpost_only) ? ' AND t.topic_id = p.topic_id ' : '';
- break;
-
- case 'f':
- $sql_sort_table = FORUMS_TABLE . ' f, ';
- $sql_sort_join = ' AND f.forum_id = p.forum_id ';
- break;
- }
-
- if (!sizeof($m_approve_fid_ary))
- {
- $m_approve_fid_sql = ' AND p.post_approved = 1';
- }
- else if ($m_approve_fid_ary == array(-1))
- {
- $m_approve_fid_sql = '';
- }
- else
- {
- $m_approve_fid_sql = ' AND (p.post_approved = 1 OR ' . $this->db->sql_in_set('p.forum_id', $m_approve_fid_ary, true) . ')';
- }
-
- // Build the query for really selecting the post_ids
- if ($type == 'posts')
- {
- $sql = "SELECT p.post_id
- FROM " . $sql_sort_table . POSTS_TABLE . ' p' . (($firstpost_only) ? ', ' . TOPICS_TABLE . ' t ' : ' ') . "
- WHERE $sql_author
- $sql_topic_id
- $sql_firstpost
- $m_approve_fid_sql
- $sql_fora
- $sql_sort_join
- $sql_time
- ORDER BY $sql_sort";
- $field = 'post_id';
- }
- else
- {
- $sql = "SELECT t.topic_id
- FROM " . $sql_sort_table . TOPICS_TABLE . ' t, ' . POSTS_TABLE . " p
- WHERE $sql_author
- $sql_topic_id
- $sql_firstpost
- $m_approve_fid_sql
- $sql_fora
- AND t.topic_id = p.topic_id
- $sql_sort_join
- $sql_time
- GROUP BY t.topic_id, $sort_by_sql[$sort_key]
- ORDER BY $sql_sort";
- $field = 'topic_id';
- }
-
- // Only read one block of posts from the db and then cache it
- $result = $this->db->sql_query_limit($sql, $this->config['search_block_size'], $start);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $id_ary[] = $row[$field];
- }
- $this->db->sql_freeresult($result);
-
- // retrieve the total result count if needed
- if (!$result_count)
- {
- $result_count = sizeof ($id_ary);
-
- if (!$result_count)
- {
- return false;
- }
- }
-
- if (sizeof($id_ary))
- {
- $this->save_ids($search_key, '', $author_ary, $result_count, $id_ary, $start, $sort_dir);
- $id_ary = array_slice($id_ary, 0, $per_page);
-
- return $result_count;
- }
- return false;
- }
-
- /**
- * Destroys cached search results, that contained one of the new words in a post so the results won't be outdated
- *
- * @param string $mode contains the post mode: edit, post, reply, quote ...
- * @param int $post_id contains the post id of the post to index
- * @param string $message contains the post text of the post
- * @param string $subject contains the subject of the post to index
- * @param int $poster_id contains the user id of the poster
- * @param int $forum_id contains the forum id of parent forum of the post
- */
- public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id)
- {
- // Split old and new post/subject to obtain array of words
- $split_text = $this->split_message($message);
- $split_title = ($subject) ? $this->split_message($subject) : array();
-
- $words = array_unique(array_merge($split_text, $split_title));
-
- unset($split_text);
- unset($split_title);
-
- // destroy cached search results containing any of the words removed or added
- $this->destroy_cache($words, array($poster_id));
-
- unset($words);
- }
-
- /**
- * Destroy cached results, that might be outdated after deleting a post
- */
- public function index_remove($post_ids, $author_ids, $forum_ids)
- {
- $this->destroy_cache(array(), $author_ids);
- }
-
- /**
- * Destroy old cache entries
- */
- public function tidy()
- {
- // destroy too old cached search results
- $this->destroy_cache(array());
-
- set_config('search_last_gc', time(), true);
- }
-
- /**
- * Create fulltext index
- *
- * @return string|bool error string is returned incase of errors otherwise false
- */
- public function create_index($acp_module, $u_action)
- {
- // Make sure we can actually use PostgreSQL with fulltext indexes
- if ($error = $this->init())
- {
- return $error;
- }
-
- if (empty($this->stats))
- {
- $this->get_stats();
- }
-
- if (!isset($this->stats['post_subject']))
- {
- $this->db->sql_query("CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_subject ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_subject))");
- }
-
- if (!isset($this->stats['post_text']))
- {
- $this->db->sql_query("CREATE INDEX " . POSTS_TABLE . "_" . $this->config['fulltext_postgres_ts_name'] . "_post_text ON " . POSTS_TABLE . " USING gin (to_tsvector ('" . $this->db->sql_escape($this->config['fulltext_postgres_ts_name']) . "', post_text))");
- }
-
- $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);
-
- return false;
- }
-
- /**
- * Drop fulltext index
- *
- * @return string|bool error string is returned incase of errors otherwise false
- */
- public function delete_index($acp_module, $u_action)
- {
- // Make sure we can actually use PostgreSQL with fulltext indexes
- if ($error = $this->init())
- {
- return $error;
- }
-
- if (empty($this->stats))
- {
- $this->get_stats();
- }
-
- if (isset($this->stats['post_subject']))
- {
- $this->db->sql_query('DROP INDEX ' . $this->stats['post_subject']['relname']);
- }
-
- if (isset($this->stats['post_text']))
- {
- $this->db->sql_query('DROP INDEX ' . $this->stats['post_text']['relname']);
- }
-
- $this->db->sql_query('TRUNCATE TABLE ' . SEARCH_RESULTS_TABLE);
-
- return false;
- }
-
- /**
- * Returns true if both FULLTEXT indexes exist
- */
- public function index_created()
- {
- if (empty($this->stats))
- {
- $this->get_stats();
- }
-
- return (isset($this->stats['post_text']) && isset($this->stats['post_subject'])) ? true : false;
- }
-
- /**
- * Returns an associative array containing information about the indexes
- */
- public function index_stats()
- {
- if (empty($this->stats))
- {
- $this->get_stats();
- }
-
- return array(
- $this->user->lang['FULLTEXT_POSTGRES_TOTAL_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] : 0,
- );
- }
-
- /**
- * Computes the stats and store them in the $this->stats associative array
- */
- protected function get_stats()
- {
- if ($this->db->sql_layer != 'postgres')
- {
- $this->stats = array();
- return;
- }
-
- $sql = "SELECT c2.relname, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true) AS indexdef
- FROM pg_catalog.pg_class c1, pg_catalog.pg_index i, pg_catalog.pg_class c2
- WHERE c1.relname = '" . POSTS_TABLE . "'
- AND pg_catalog.pg_table_is_visible(c1.oid)
- AND c1.oid = i.indrelid
- AND i.indexrelid = c2.oid";
- $result = $this->db->sql_query($sql);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- // deal with older PostgreSQL versions which didn't use Index_type
- if (strpos($row['indexdef'], 'to_tsvector') !== false)
- {
- if ($row['relname'] == POSTS_TABLE . '_' . $this->config['fulltext_postgres_ts_name'] . '_post_text' || $row['relname'] == POSTS_TABLE . '_post_text')
- {
- $this->stats['post_text'] = $row;
- }
- else if ($row['relname'] == POSTS_TABLE . '_' . $this->config['fulltext_postgres_ts_name'] . '_post_subject' || $row['relname'] == POSTS_TABLE . '_post_subject')
- {
- $this->stats['post_subject'] = $row;
- }
- }
- }
- $this->db->sql_freeresult($result);
-
- $this->stats['total_posts'] = $this->config['num_posts'];
- }
-
- /**
- * Display various options that can be configured for the backend from the acp
- *
- * @return associative array containing template and config variables
- */
- public function acp()
- {
- $tpl = '
- <dl>
- <dt><label>' . $this->user->lang['FULLTEXT_POSTGRES_VERSION_CHECK'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_POSTGRES_VERSION_CHECK_EXPLAIN'] . '</span></dt>
- <dd>' . (($this->tsearch_usable) ? $this->user->lang['YES'] : $this->user->lang['NO']) . ' (PostgreSQL ' . $this->version . ')</dd>
- </dl>
- <dl>
- <dt><label>' . $this->user->lang['FULLTEXT_POSTGRES_TS_NAME'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_POSTGRES_TS_NAME_EXPLAIN'] . '</span></dt>
- <dd><select name="config[fulltext_postgres_ts_name]">';
-
- if ($this->db->sql_layer == 'postgres' && $this->tsearch_usable)
- {
- $sql = 'SELECT cfgname AS ts_name
- FROM pg_ts_config';
- $result = $this->db->sql_query($sql);
-
- while ($row = $this->db->sql_fetchrow($result))
- {
- $tpl .= '<option value="' . $row['ts_name'] . '"' . ($row['ts_name'] === $this->config['fulltext_postgres_ts_name'] ? ' selected="selected"' : '') . '>' . $row['ts_name'] . '</option>';
- }
- $this->db->sql_freeresult($result);
- }
- else
- {
- $tpl .= '<option value="' . $this->config['fulltext_postgres_ts_name'] . '" selected="selected">' . $this->config['fulltext_postgres_ts_name'] . '</option>';
- }
-
- $tpl .= '</select></dd>
- </dl>
- <dl>
- <dt><label for="fulltext_postgres_min_word_len">' . $this->user->lang['FULLTEXT_POSTGRES_MIN_WORD_LEN'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_POSTGRES_MIN_WORD_LEN_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_postgres_min_word_len" type="text" size="3" maxlength="3" name="config[fulltext_postgres_min_word_len]" value="' . (int) $this->config['fulltext_postgres_min_word_len'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="fulltext_postgres_max_word_len">' . $this->user->lang['FULLTEXT_POSTGRES_MAX_WORD_LEN'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_POSTGRES_MAX_WORD_LEN_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_postgres_max_word_len" type="text" size="3" maxlength="3" name="config[fulltext_postgres_max_word_len]" value="' . (int) $this->config['fulltext_postgres_max_word_len'] . '" /></dd>
- </dl>
- ';
-
- // These are fields required in the config table
- return array(
- 'tpl' => $tpl,
- 'config' => array('fulltext_postgres_ts_name' => 'string', 'fulltext_postgres_min_word_len' => 'integer:0:255', 'fulltext_postgres_max_word_len' => 'integer:0:255')
- );
- }
-}
diff --git a/phpBB/includes/search/fulltext_sphinx.php b/phpBB/includes/search/fulltext_sphinx.php
deleted file mode 100644
index dd5634b623..0000000000
--- a/phpBB/includes/search/fulltext_sphinx.php
+++ /dev/null
@@ -1,892 +0,0 @@
-<?php
-/**
-*
-* @package search
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* @ignore
-*/
-define('SPHINX_MAX_MATCHES', 20000);
-define('SPHINX_CONNECT_RETRIES', 3);
-define('SPHINX_CONNECT_WAIT_TIME', 300);
-
-/**
-* fulltext_sphinx
-* Fulltext search based on the sphinx search deamon
-* @package search
-*/
-class phpbb_search_fulltext_sphinx
-{
- /**
- * Associative array holding index stats
- * @var array
- */
- protected $stats = array();
-
- /**
- * Holds the words entered by user, obtained by splitting the entered query on whitespace
- * @var array
- */
- protected $split_words = array();
-
- /**
- * Holds unique sphinx id
- * @var string
- */
- protected $id;
-
- /**
- * Stores the names of both main and delta sphinx indexes
- * separated by a semicolon
- * @var string
- */
- protected $indexes;
-
- /**
- * Sphinx searchd client object
- * @var SphinxClient
- */
- protected $sphinx;
-
- /**
- * Relative path to board root
- * @var string
- */
- protected $phpbb_root_path;
-
- /**
- * PHP Extension
- * @var string
- */
- protected $php_ext;
-
- /**
- * Auth object
- * @var phpbb_auth
- */
- protected $auth;
-
- /**
- * Config object
- * @var phpbb_config
- */
- protected $config;
-
- /**
- * DBAL object
- * @var dbal
- */
- protected $db;
-
- /**
- * Database Tools object
- * @var phpbb_db_tools
- */
- protected $db_tools;
-
- /**
- * Stores the database type if supported by sphinx
- * @var string
- */
- protected $dbtype;
-
- /**
- * User object
- * @var phpbb_user
- */
- protected $user;
-
- /**
- * Stores the generated content of the sphinx config file
- * @var string
- */
- protected $config_file_data = '';
-
- /**
- * Contains tidied search query.
- * Operators are prefixed in search query and common words excluded
- * @var string
- */
- protected $search_query;
-
- /**
- * Constructor
- * Creates a new phpbb_search_fulltext_postgres, which is used as a search backend
- *
- * @param string|bool $error Any error that occurs is passed on through this reference variable otherwise false
- */
- public function __construct(&$error, $phpbb_root_path, $phpEx, $auth, $config, $db, $user)
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $phpEx;
- $this->config = $config;
- $this->user = $user;
- $this->db = $db;
- $this->auth = $auth;
-
- if (!class_exists('phpbb_db_tools'))
- {
- require($this->phpbb_root_path . 'includes/db/db_tools.' . $this->php_ext);
- }
-
- // Initialize phpbb_db_tools object
- $this->db_tools = new phpbb_db_tools($this->db);
-
- if(!$this->config['fulltext_sphinx_id'])
- {
- set_config('fulltext_sphinx_id', unique_id());
- }
- $this->id = $this->config['fulltext_sphinx_id'];
- $this->indexes = 'index_phpbb_' . $this->id . '_delta;index_phpbb_' . $this->id . '_main';
-
- if (!class_exists('SphinxClient'))
- {
- require($this->phpbb_root_path . 'includes/sphinxapi.' . $this->php_ext);
- }
-
- // Initialize sphinx client
- $this->sphinx = new SphinxClient();
-
- $this->sphinx->SetServer(($this->config['fulltext_sphinx_host'] ? $this->config['fulltext_sphinx_host'] : 'localhost'), ($this->config['fulltext_sphinx_port'] ? (int) $this->config['fulltext_sphinx_port'] : 9312));
-
- $error = false;
- }
-
- /**
- * Returns the name of this search backend to be displayed to administrators
- *
- * @return string Name
- */
- public function get_name()
- {
- return 'Sphinx Fulltext';
- }
-
- /**
- * Returns the search_query
- *
- * @return string search query
- */
- public function get_search_query()
- {
- return $this->search_query;
- }
-
- /**
- * Returns false as there is no word_len array
- *
- * @return false
- */
- public function get_word_length()
- {
- return false;
- }
-
- /**
- * Returns an empty array as there are no common_words
- *
- * @return array common words that are ignored by search backend
- */
- public function get_common_words()
- {
- return array();
- }
-
- /**
- * Checks permissions and paths, if everything is correct it generates the config file
- *
- * @return string|bool Language key of the error/incompatiblity encountered, or false if successful
- */
- public function init()
- {
- if ($this->db->sql_layer != 'mysql' && $this->db->sql_layer != 'mysql4' && $this->db->sql_layer != 'mysqli' && $this->db->sql_layer != 'postgres')
- {
- return $this->user->lang['FULLTEXT_SPHINX_WRONG_DATABASE'];
- }
-
- // Move delta to main index each hour
- set_config('search_gc', 3600);
-
- return false;
- }
-
- /**
- * Generates content of sphinx.conf
- *
- * @return bool True if sphinx.conf content is correctly generated, false otherwise
- */
- protected function config_generate()
- {
- // Check if Database is supported by Sphinx
- if ($this->db->sql_layer =='mysql' || $this->db->sql_layer == 'mysql4' || $this->db->sql_layer == 'mysqli')
- {
- $this->dbtype = 'mysql';
- }
- else if ($this->db->sql_layer == 'postgres')
- {
- $this->dbtype = 'pgsql';
- }
- else
- {
- $this->config_file_data = $this->user->lang('FULLTEXT_SPHINX_WRONG_DATABASE');
- return false;
- }
-
- // Check if directory paths have been filled
- if (!$this->config['fulltext_sphinx_data_path'])
- {
- $this->config_file_data = $this->user->lang('FULLTEXT_SPHINX_NO_CONFIG_DATA');
- return false;
- }
-
- include($this->phpbb_root_path . 'config.' . $this->php_ext);
-
- /* Now that we're sure everything was entered correctly,
- generate a config for the index. We use a config value
- fulltext_sphinx_id for this, as it should be unique. */
- $config_object = new phpbb_search_sphinx_config($this->config_file_data);
- $config_data = array(
- 'source source_phpbb_' . $this->id . '_main' => array(
- array('type', $this->dbtype),
- // This config value sql_host needs to be changed incase sphinx and sql are on different servers
- array('sql_host', $dbhost),
- array('sql_user', $dbuser),
- array('sql_pass', $dbpasswd),
- array('sql_db', $dbname),
- array('sql_port', $dbport),
- array('sql_query_pre', 'SET NAMES \'utf8\''),
- array('sql_query_pre', 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = (SELECT MAX(post_id) FROM ' . POSTS_TABLE . ') WHERE counter_id = 1'),
- array('sql_query_range', 'SELECT MIN(post_id), MAX(post_id) FROM ' . POSTS_TABLE . ''),
- array('sql_range_step', '5000'),
- array('sql_query', 'SELECT
- p.post_id AS id,
- p.forum_id,
- p.topic_id,
- p.poster_id,
- CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post,
- p.post_time,
- p.post_subject,
- p.post_subject as title,
- p.post_text as data,
- t.topic_last_post_time,
- 0 as deleted
- FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t
- WHERE
- p.topic_id = t.topic_id
- AND p.post_id >= $start AND p.post_id <= $end'),
- array('sql_query_post', ''),
- array('sql_query_post_index', 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = $maxid WHERE counter_id = 1'),
- array('sql_query_info', 'SELECT * FROM ' . POSTS_TABLE . ' WHERE post_id = $id'),
- array('sql_attr_uint', 'forum_id'),
- array('sql_attr_uint', 'topic_id'),
- array('sql_attr_uint', 'poster_id'),
- array('sql_attr_bool', 'topic_first_post'),
- array('sql_attr_bool', 'deleted'),
- array('sql_attr_timestamp' , 'post_time'),
- array('sql_attr_timestamp' , 'topic_last_post_time'),
- array('sql_attr_str2ordinal', 'post_subject'),
- ),
- 'source source_phpbb_' . $this->id . '_delta : source_phpbb_' . $this->id . '_main' => array(
- array('sql_query_pre', ''),
- array('sql_query_range', ''),
- array('sql_range_step', ''),
- array('sql_query', 'SELECT
- p.post_id AS id,
- p.forum_id,
- p.topic_id,
- p.poster_id,
- CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post,
- p.post_time,
- p.post_subject,
- p.post_subject as title,
- p.post_text as data,
- t.topic_last_post_time,
- 0 as deleted
- FROM ' . POSTS_TABLE . ' p, ' . TOPICS_TABLE . ' t
- WHERE
- p.topic_id = t.topic_id
- AND p.post_id >= ( SELECT max_doc_id FROM ' . SPHINX_TABLE . ' WHERE counter_id=1 )'),
- ),
- 'index index_phpbb_' . $this->id . '_main' => array(
- array('path', $this->config['fulltext_sphinx_data_path'] . 'index_phpbb_' . $this->id . '_main'),
- array('source', 'source_phpbb_' . $this->id . '_main'),
- array('docinfo', 'extern'),
- array('morphology', 'none'),
- array('stopwords', ''),
- array('min_word_len', '2'),
- array('charset_type', 'utf-8'),
- array('charset_table', 'U+FF10..U+FF19->0..9, 0..9, U+FF41..U+FF5A->a..z, U+FF21..U+FF3A->a..z, A..Z->a..z, a..z, U+0149, U+017F, U+0138, U+00DF, U+00FF, U+00C0..U+00D6->U+00E0..U+00F6, U+00E0..U+00F6, U+00D8..U+00DE->U+00F8..U+00FE, U+00F8..U+00FE, U+0100->U+0101, U+0101, U+0102->U+0103, U+0103, U+0104->U+0105, U+0105, U+0106->U+0107, U+0107, U+0108->U+0109, U+0109, U+010A->U+010B, U+010B, U+010C->U+010D, U+010D, U+010E->U+010F, U+010F, U+0110->U+0111, U+0111, U+0112->U+0113, U+0113, U+0114->U+0115, U+0115, U+0116->U+0117, U+0117, U+0118->U+0119, U+0119, U+011A->U+011B, U+011B, U+011C->U+011D, U+011D, U+011E->U+011F, U+011F, U+0130->U+0131, U+0131, U+0132->U+0133, U+0133, U+0134->U+0135, U+0135, U+0136->U+0137, U+0137, U+0139->U+013A, U+013A, U+013B->U+013C, U+013C, U+013D->U+013E, U+013E, U+013F->U+0140, U+0140, U+0141->U+0142, U+0142, U+0143->U+0144, U+0144, U+0145->U+0146, U+0146, U+0147->U+0148, U+0148, U+014A->U+014B, U+014B, U+014C->U+014D, U+014D, U+014E->U+014F, U+014F, U+0150->U+0151, U+0151, U+0152->U+0153, U+0153, U+0154->U+0155, U+0155, U+0156->U+0157, U+0157, U+0158->U+0159, U+0159, U+015A->U+015B, U+015B, U+015C->U+015D, U+015D, U+015E->U+015F, U+015F, U+0160->U+0161, U+0161, U+0162->U+0163, U+0163, U+0164->U+0165, U+0165, U+0166->U+0167, U+0167, U+0168->U+0169, U+0169, U+016A->U+016B, U+016B, U+016C->U+016D, U+016D, U+016E->U+016F, U+016F, U+0170->U+0171, U+0171, U+0172->U+0173, U+0173, U+0174->U+0175, U+0175, U+0176->U+0177, U+0177, U+0178->U+00FF, U+00FF, U+0179->U+017A, U+017A, U+017B->U+017C, U+017C, U+017D->U+017E, U+017E, U+0410..U+042F->U+0430..U+044F, U+0430..U+044F, U+4E00..U+9FFF'),
- array('min_prefix_len', '0'),
- array('min_infix_len', '0'),
- ),
- 'index index_phpbb_' . $this->id . '_delta : index_phpbb_' . $this->id . '_main' => array(
- array('path', $this->config['fulltext_sphinx_data_path'] . 'index_phpbb_' . $this->id . '_delta'),
- array('source', 'source_phpbb_' . $this->id . '_delta'),
- ),
- 'indexer' => array(
- array('mem_limit', $this->config['fulltext_sphinx_indexer_mem_limit'] . 'M'),
- ),
- 'searchd' => array(
- array('compat_sphinxql_magics' , '0'),
- array('listen' , ($this->config['fulltext_sphinx_host'] ? $this->config['fulltext_sphinx_host'] : 'localhost') . ':' . ($this->config['fulltext_sphinx_port'] ? $this->config['fulltext_sphinx_port'] : '9312')),
- array('log', $this->config['fulltext_sphinx_data_path'] . 'log/searchd.log'),
- array('query_log', $this->config['fulltext_sphinx_data_path'] . 'log/sphinx-query.log'),
- array('read_timeout', '5'),
- array('max_children', '30'),
- array('pid_file', $this->config['fulltext_sphinx_data_path'] . 'searchd.pid'),
- array('max_matches', (string) SPHINX_MAX_MATCHES),
- array('binlog_path', $this->config['fulltext_sphinx_data_path']),
- ),
- );
-
- $non_unique = array('sql_query_pre' => true, 'sql_attr_uint' => true, 'sql_attr_timestamp' => true, 'sql_attr_str2ordinal' => true, 'sql_attr_bool' => true);
- $delete = array('sql_group_column' => true, 'sql_date_column' => true, 'sql_str2ordinal_column' => true);
- foreach ($config_data as $section_name => $section_data)
- {
- $section = $config_object->get_section_by_name($section_name);
- if (!$section)
- {
- $section = $config_object->add_section($section_name);
- }
-
- foreach ($delete as $key => $void)
- {
- $section->delete_variables_by_name($key);
- }
-
- foreach ($non_unique as $key => $void)
- {
- $section->delete_variables_by_name($key);
- }
-
- foreach ($section_data as $entry)
- {
- $key = $entry[0];
- $value = $entry[1];
-
- if (!isset($non_unique[$key]))
- {
- $variable = $section->get_variable_by_name($key);
- if (!$variable)
- {
- $variable = $section->create_variable($key, $value);
- }
- else
- {
- $variable->set_value($value);
- }
- }
- else
- {
- $variable = $section->create_variable($key, $value);
- }
- }
- }
- $this->config_file_data = $config_object->get_data();
-
- return true;
- }
-
- /**
- * Splits keywords entered by a user into an array of words stored in $this->split_words
- * Stores the tidied search query in $this->search_query
- *
- * @param string $keywords Contains the keyword as entered by the user
- * @param string $terms is either 'all' or 'any'
- * @return false if no valid keywords were found and otherwise true
- */
- public function split_keywords(&$keywords, $terms)
- {
- if ($terms == 'all')
- {
- $match = array('#\sand\s#i', '#\sor\s#i', '#\snot\s#i', '#\+#', '#-#', '#\|#', '#@#');
- $replace = array(' & ', ' | ', ' - ', ' +', ' -', ' |', '');
-
- $replacements = 0;
- $keywords = preg_replace($match, $replace, $keywords);
- $this->sphinx->SetMatchMode(SPH_MATCH_EXTENDED);
- }
- else
- {
- $this->sphinx->SetMatchMode(SPH_MATCH_ANY);
- }
-
- // Keep quotes and new lines
- $keywords = str_replace(array('&quot;', "\n"), array('"', ' '), trim($keywords));
-
- if (strlen($keywords) > 0)
- {
- $this->search_query = str_replace('"', '&quot;', $keywords);
- return true;
- }
-
- return false;
- }
-
- /**
- * 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 $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
- */
- 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, $author_name, &$id_ary, $start, $per_page)
- {
- // No keywords? No posts.
- if (!strlen($this->search_query) && !sizeof($author_ary))
- {
- return false;
- }
-
- $id_ary = array();
-
- $join_topic = ($type != 'posts');
-
- // Sorting
-
- if ($type == 'topics')
- {
- switch ($sort_key)
- {
- case 'a':
- $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'poster_id ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'));
- break;
-
- case 'f':
- $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'forum_id ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'));
- break;
-
- case 'i':
-
- case 's':
- $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'post_subject ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'));
- break;
-
- case 't':
-
- default:
- $this->sphinx->SetGroupBy('topic_id', SPH_GROUPBY_ATTR, 'topic_last_post_time ' . (($sort_dir == 'a') ? 'ASC' : 'DESC'));
- break;
- }
- }
- else
- {
- switch ($sort_key)
- {
- case 'a':
- $this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'poster_id');
- break;
-
- case 'f':
- $this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'forum_id');
- break;
-
- case 'i':
-
- case 's':
- $this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'post_subject');
- break;
-
- case 't':
-
- default:
- $this->sphinx->SetSortMode(($sort_dir == 'a') ? SPH_SORT_ATTR_ASC : SPH_SORT_ATTR_DESC, 'post_time');
- break;
- }
- }
-
- // Most narrow filters first
- if ($topic_id)
- {
- $this->sphinx->SetFilter('topic_id', array($topic_id));
- }
-
- $search_query_prefix = '';
-
- switch ($fields)
- {
- case 'titleonly':
- // Only search the title
- if ($terms == 'all')
- {
- $search_query_prefix = '@title ';
- }
- // Weight for the title
- $this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1));
- // 1 is first_post, 0 is not first post
- $this->sphinx->SetFilter('topic_first_post', array(1));
- break;
-
- case 'msgonly':
- // Only search the body
- if ($terms == 'all')
- {
- $search_query_prefix = '@data ';
- }
- // Weight for the body
- $this->sphinx->SetFieldWeights(array("title" => 1, "data" => 5));
- break;
-
- case 'firstpost':
- // More relative weight for the title, also search the body
- $this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1));
- // 1 is first_post, 0 is not first post
- $this->sphinx->SetFilter('topic_first_post', array(1));
- break;
-
- default:
- // More relative weight for the title, also search the body
- $this->sphinx->SetFieldWeights(array("title" => 5, "data" => 1));
- break;
- }
-
- if (sizeof($author_ary))
- {
- $this->sphinx->SetFilter('poster_id', $author_ary);
- }
-
- if (sizeof($ex_fid_ary))
- {
- // All forums that a user is allowed to access
- $fid_ary = array_unique(array_intersect(array_keys($this->auth->acl_getf('f_read', true)), array_keys($this->auth->acl_getf('f_search', true))));
- // All forums that the user wants to and can search in
- $search_forums = array_diff($fid_ary, $ex_fid_ary);
-
- if (sizeof($search_forums))
- {
- $this->sphinx->SetFilter('forum_id', $search_forums);
- }
- }
-
- $this->sphinx->SetFilter('deleted', array(0));
-
- $this->sphinx->SetLimits($start, (int) $per_page, SPHINX_MAX_MATCHES);
- $result = $this->sphinx->Query($search_query_prefix . str_replace('&quot;', '"', $this->search_query), $this->indexes);
-
- // Could be connection to localhost:9312 failed (errno=111,
- // msg=Connection refused) during rotate, retry if so
- $retries = SPHINX_CONNECT_RETRIES;
- while (!$result && (strpos($this->sphinx->GetLastError(), "errno=111,") !== false) && $retries--)
- {
- usleep(SPHINX_CONNECT_WAIT_TIME);
- $result = $this->sphinx->Query($search_query_prefix . str_replace('&quot;', '"', $this->search_query), $this->indexes);
- }
-
- if ($this->sphinx->GetLastError())
- {
- add_log('critical', 'LOG_SPHINX_ERROR', $this->sphinx->GetLastError());
- if ($this->auth->acl_get('a_'))
- {
- trigger_error($this->user->lang('SPHINX_SEARCH_FAILED', $this->sphinx->GetLastError()));
- }
- else
- {
- trigger_error($this->user->lang('SPHINX_SEARCH_FAILED_LOG'));
- }
- }
-
- $id_ary = array();
- if (isset($result['matches']))
- {
- if ($type == 'posts')
- {
- $id_ary = array_keys($result['matches']);
- }
- else
- {
- foreach ($result['matches'] as $key => $value)
- {
- $id_ary[] = $value['attrs']['topic_id'];
- }
- }
- }
- else
- {
- return false;
- }
-
- $result_count = $result['total_found'];
-
- $id_ary = array_slice($id_ary, 0, (int) $per_page);
-
- return $result_count;
- }
-
- /**
- * Performs a search on an author's posts without caring about message contents. Depends on display specific params
- *
- * @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
- */
- 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, $author_name, &$id_ary, $start, $per_page)
- {
- $this->search_query = '';
-
- $this->sphinx->SetMatchMode(SPH_MATCH_FULLSCAN);
- $fields = ($firstpost_only) ? 'firstpost' : 'all';
- $terms = 'all';
- return $this->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);
- }
-
- /**
- * Updates wordlist and wordmatch tables when a message is posted or changed
- *
- * @param string $mode Contains the post mode: edit, post, reply, quote
- * @param int $post_id The id of the post which is modified/created
- * @param string &$message New or updated post content
- * @param string &$subject New or updated post subject
- * @param int $poster_id Post author's user id
- * @param int $forum_id The id of the forum in which the post is located
- */
- public function index($mode, $post_id, &$message, &$subject, $poster_id, $forum_id)
- {
- if ($mode == 'edit')
- {
- $this->sphinx->UpdateAttributes($this->indexes, array('forum_id', 'poster_id'), array((int)$post_id => array((int)$forum_id, (int)$poster_id)));
- }
- else if ($mode != 'post' && $post_id)
- {
- // Update topic_last_post_time for full topic
- $sql_array = array(
- 'SELECT' => 'p1.post_id',
- 'FROM' => array(
- POSTS_TABLE => 'p1',
- ),
- 'LEFT_JOIN' => array(array(
- 'FROM' => array(
- POSTS_TABLE => 'p2'
- ),
- 'ON' => 'p1.topic_id = p2.topic_id',
- )),
- );
-
- $sql = $this->db->sql_build_query('SELECT', $sql_array);
- $result = $this->db->sql_query($sql);
-
- $post_updates = array();
- $post_time = time();
- while ($row = $this->db->sql_fetchrow($result))
- {
- $post_updates[(int)$row['post_id']] = array($post_time);
- }
- $this->db->sql_freeresult($result);
-
- if (sizeof($post_updates))
- {
- $this->sphinx->UpdateAttributes($this->indexes, array('topic_last_post_time'), $post_updates);
- }
- }
- }
-
- /**
- * Delete a post from the index after it was deleted
- */
- public function index_remove($post_ids, $author_ids, $forum_ids)
- {
- $values = array();
- foreach ($post_ids as $post_id)
- {
- $values[$post_id] = array(1);
- }
-
- $this->sphinx->UpdateAttributes($this->indexes, array('deleted'), $values);
- }
-
- /**
- * Nothing needs to be destroyed
- */
- public function tidy($create = false)
- {
- set_config('search_last_gc', time(), true);
- }
-
- /**
- * Create sphinx table
- *
- * @return string|bool error string is returned incase of errors otherwise false
- */
- public function create_index($acp_module, $u_action)
- {
- if (!$this->index_created())
- {
- $table_data = array(
- 'COLUMNS' => array(
- 'counter_id' => array('UINT', 0),
- 'max_doc_id' => array('UINT', 0),
- ),
- 'PRIMARY_KEY' => 'counter_id',
- );
- $this->db_tools->sql_create_table(SPHINX_TABLE, $table_data);
-
- $sql = 'TRUNCATE TABLE ' . SPHINX_TABLE;
- $this->db->sql_query($sql);
-
- $data = array(
- 'counter_id' => '1',
- 'max_doc_id' => '0',
- );
- $sql = 'INSERT INTO ' . SPHINX_TABLE . ' ' . $this->db->sql_build_array('INSERT', $data);
- $this->db->sql_query($sql);
- }
-
- return false;
- }
-
- /**
- * Drop sphinx table
- *
- * @return string|bool error string is returned incase of errors otherwise false
- */
- public function delete_index($acp_module, $u_action)
- {
- if (!$this->index_created())
- {
- return false;
- }
-
- $this->db_tools->sql_table_drop(SPHINX_TABLE);
-
- return false;
- }
-
- /**
- * Returns true if the sphinx table was created
- *
- * @return bool true if sphinx table was created
- */
- public function index_created($allow_new_files = true)
- {
- $created = false;
-
- if ($this->db_tools->sql_table_exists(SPHINX_TABLE))
- {
- $created = true;
- }
-
- return $created;
- }
-
- /**
- * Returns an associative array containing information about the indexes
- *
- * @return string|bool Language string of error false otherwise
- */
- public function index_stats()
- {
- if (empty($this->stats))
- {
- $this->get_stats();
- }
-
- return array(
- $this->user->lang['FULLTEXT_SPHINX_MAIN_POSTS'] => ($this->index_created()) ? $this->stats['main_posts'] : 0,
- $this->user->lang['FULLTEXT_SPHINX_DELTA_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] - $this->stats['main_posts'] : 0,
- $this->user->lang['FULLTEXT_MYSQL_TOTAL_POSTS'] => ($this->index_created()) ? $this->stats['total_posts'] : 0,
- );
- }
-
- /**
- * Collects stats that can be displayed on the index maintenance page
- */
- protected function get_stats()
- {
- if ($this->index_created())
- {
- $sql = 'SELECT COUNT(post_id) as total_posts
- FROM ' . POSTS_TABLE;
- $result = $this->db->sql_query($sql);
- $this->stats['total_posts'] = (int) $this->db->sql_fetchfield('total_posts');
- $this->db->sql_freeresult($result);
-
- $sql = 'SELECT COUNT(p.post_id) as main_posts
- FROM ' . POSTS_TABLE . ' p, ' . SPHINX_TABLE . ' m
- WHERE p.post_id <= m.max_doc_id
- AND m.counter_id = 1';
- $result = $this->db->sql_query($sql);
- $this->stats['main_posts'] = (int) $this->db->sql_fetchfield('main_posts');
- $this->db->sql_freeresult($result);
- }
- }
-
- /**
- * Returns a list of options for the ACP to display
- *
- * @return associative array containing template and config variables
- */
- public function acp()
- {
- $config_vars = array(
- 'fulltext_sphinx_data_path' => 'string',
- 'fulltext_sphinx_host' => 'string',
- 'fulltext_sphinx_port' => 'string',
- 'fulltext_sphinx_indexer_mem_limit' => 'int',
- );
-
- $tpl = '
- <span class="error">' . $this->user->lang['FULLTEXT_SPHINX_CONFIGURE']. '</span>
- <dl>
- <dt><label for="fulltext_sphinx_data_path">' . $this->user->lang['FULLTEXT_SPHINX_DATA_PATH'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_DATA_PATH_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_sphinx_data_path" type="text" size="40" maxlength="255" name="config[fulltext_sphinx_data_path]" value="' . $this->config['fulltext_sphinx_data_path'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="fulltext_sphinx_host">' . $this->user->lang['FULLTEXT_SPHINX_HOST'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_HOST_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_sphinx_host" type="text" size="40" maxlength="255" name="config[fulltext_sphinx_host]" value="' . $this->config['fulltext_sphinx_host'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="fulltext_sphinx_port">' . $this->user->lang['FULLTEXT_SPHINX_PORT'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_PORT_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_sphinx_port" type="text" size="4" maxlength="10" name="config[fulltext_sphinx_port]" value="' . $this->config['fulltext_sphinx_port'] . '" /></dd>
- </dl>
- <dl>
- <dt><label for="fulltext_sphinx_indexer_mem_limit">' . $this->user->lang['FULLTEXT_SPHINX_INDEXER_MEM_LIMIT'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_INDEXER_MEM_LIMIT_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_sphinx_indexer_mem_limit" type="text" size="4" maxlength="10" name="config[fulltext_sphinx_indexer_mem_limit]" value="' . $this->config['fulltext_sphinx_indexer_mem_limit'] . '" />' . $this->user->lang['MIB'] . '</dd>
- </dl>
- <dl>
- <dt><label for="fulltext_sphinx_config_file">' . $this->user->lang['FULLTEXT_SPHINX_CONFIG_FILE'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_CONFIG_FILE_EXPLAIN'] . '</dt>
- <dd>' . (($this->config_generate()) ? '<textarea readonly="readonly" rows="6">' . $this->config_file_data . '</textarea>' : $this->config_file_data) . '</dd>
- <dl>
- ';
-
- // These are fields required in the config table
- return array(
- 'tpl' => $tpl,
- 'config' => $config_vars
- );
- }
-}
diff --git a/phpBB/includes/search/index.htm b/phpBB/includes/search/index.htm
deleted file mode 100644
index ee1f723a7d..0000000000
--- a/phpBB/includes/search/index.htm
+++ /dev/null
@@ -1,10 +0,0 @@
-<html>
-<head>
-<title></title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-</head>
-
-<body bgcolor="#FFFFFF" text="#000000">
-
-</body>
-</html>
diff --git a/phpBB/includes/search/sphinx/config.php b/phpBB/includes/search/sphinx/config.php
deleted file mode 100644
index f1864f0c8c..0000000000
--- a/phpBB/includes/search/sphinx/config.php
+++ /dev/null
@@ -1,288 +0,0 @@
-<?php
-/**
-*
-* @package search
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* phpbb_search_sphinx_config
-* An object representing the sphinx configuration
-* Can read it from file and write it back out after modification
-* @package search
-*/
-class phpbb_search_sphinx_config
-{
- private $sections = array();
-
- /**
- * Constructor which optionally loads data from a variable
- *
- * @param string $config_data Variable containing the sphinx configuration data
- *
- * @access public
- */
- function __construct($config_data)
- {
- if ($config_data != '')
- {
- $this->read($config_data);
- }
- }
-
- /**
- * Get a section object by its name
- *
- * @param string $name The name of the section that shall be returned
- * @return phpbb_search_sphinx_config_section The section object or null if none was found
- *
- * @access public
- */
- function get_section_by_name($name)
- {
- for ($i = 0, $size = sizeof($this->sections); $i < $size; $i++)
- {
- // Make sure this is really a section object and not a comment
- if (($this->sections[$i] instanceof phpbb_search_sphinx_config_section) && $this->sections[$i]->get_name() == $name)
- {
- return $this->sections[$i];
- }
- }
- }
-
- /**
- * Appends a new empty section to the end of the config
- *
- * @param string $name The name for the new section
- * @return phpbb_search_sphinx_config_section The newly created section object
- *
- * @access public
- */
- function add_section($name)
- {
- $this->sections[] = new phpbb_search_sphinx_config_section($name, '');
- return $this->sections[sizeof($this->sections) - 1];
- }
-
- /**
- * Reads the config file data
- *
- * @param string $config_data The config file data
- *
- * @access private
- */
- function read($config_data)
- {
- $this->sections = array();
-
- $section = null;
- $found_opening_bracket = false;
- $in_value = false;
-
- foreach ($config_data as $i => $line)
- {
- // If the value of a variable continues to the next line because the line
- // break was escaped then we don't trim leading space but treat it as a part of the value
- if ($in_value)
- {
- $line = rtrim($line);
- }
- else
- {
- $line = trim($line);
- }
-
- // If we're not inside a section look for one
- if (!$section)
- {
- // Add empty lines and comments as comment objects to the section list
- // that way they're not deleted when reassembling the file from the sections
- if (!$line || $line[0] == '#')
- {
- $this->sections[] = new phpbb_search_sphinx_config_comment($config_file[$i]);
- continue;
- }
- else
- {
- // Otherwise we scan the line reading the section name until we find
- // an opening curly bracket or a comment
- $section_name = '';
- $section_name_comment = '';
- $found_opening_bracket = false;
- for ($j = 0, $length = strlen($line); $j < $length; $j++)
- {
- if ($line[$j] == '#')
- {
- $section_name_comment = substr($line, $j);
- break;
- }
-
- if ($found_opening_bracket)
- {
- continue;
- }
-
- if ($line[$j] == '{')
- {
- $found_opening_bracket = true;
- continue;
- }
-
- $section_name .= $line[$j];
- }
-
- // And then we create the new section object
- $section_name = trim($section_name);
- $section = new phpbb_search_sphinx_config_section($section_name, $section_name_comment);
- }
- }
- else
- {
- // If we're looking for variables inside a section
- $skip_first = false;
-
- // If we're not in a value continuing over the line feed
- if (!$in_value)
- {
- // Then add empty lines and comments as comment objects to the variable list
- // of this section so they're not deleted on reassembly
- if (!$line || $line[0] == '#')
- {
- $section->add_variable(new phpbb_search_sphinx_config_comment($config_file[$i]));
- continue;
- }
-
- // As long as we haven't yet actually found an opening bracket for this section
- // we treat everything as comments so it's not deleted either
- if (!$found_opening_bracket)
- {
- if ($line[0] == '{')
- {
- $skip_first = true;
- $line = substr($line, 1);
- $found_opening_bracket = true;
- }
- else
- {
- $section->add_variable(new phpbb_search_sphinx_config_comment($config_file[$i]));
- continue;
- }
- }
- }
-
- // If we did not find a comment in this line or still add to the previous
- // line's value ...
- if ($line || $in_value)
- {
- if (!$in_value)
- {
- $name = '';
- $value = '';
- $comment = '';
- $found_assignment = false;
- }
- $in_value = false;
- $end_section = false;
-
- /* ... then we should prase this line char by char:
- - first there's the variable name
- - then an equal sign
- - the variable value
- - possibly a backslash before the linefeed in this case we need to continue
- parsing the value in the next line
- - a # indicating that the rest of the line is a comment
- - a closing curly bracket indicating the end of this section*/
- for ($j = 0, $length = strlen($line); $j < $length; $j++)
- {
- if ($line[$j] == '#')
- {
- $comment = substr($line, $j);
- break;
- }
- else if ($line[$j] == '}')
- {
- $comment = substr($line, $j + 1);
- $end_section = true;
- break;
- }
- else if (!$found_assignment)
- {
- if ($line[$j] == '=')
- {
- $found_assignment = true;
- }
- else
- {
- $name .= $line[$j];
- }
- }
- else
- {
- if ($line[$j] == '\\' && $j == $length - 1)
- {
- $value .= "\n";
- $in_value = true;
- // Go to the next line and keep processing the value in there
- continue 2;
- }
- $value .= $line[$j];
- }
- }
-
- // If a name and an equal sign were found then we have append a
- // new variable object to the section
- if ($name && $found_assignment)
- {
- $section->add_variable(new phpbb_search_sphinx_config_variable(trim($name), trim($value), ($end_section) ? '' : $comment));
- continue;
- }
-
- /* If we found a closing curly bracket this section has been completed
- and we can append it to the section list and continue with looking for
- the next section */
- if ($end_section)
- {
- $section->set_end_comment($comment);
- $this->sections[] = $section;
- $section = null;
- continue;
- }
- }
-
- // If we did not find anything meaningful up to here, then just treat it
- // as a comment
- $comment = ($skip_first) ? "\t" . substr(ltrim($config_file[$i]), 1) : $config_file[$i];
- $section->add_variable(new phpbb_search_sphinx_config_comment($comment));
- }
- }
-
- }
-
- /**
- * Returns the config data
- *
- * @return string $data The config data that is generated
- *
- * @access public
- */
- function get_data()
- {
- $data = "";
- foreach ($this->sections as $section)
- {
- $data .= $section->to_string();
- }
-
- return $data;
- }
-}
diff --git a/phpBB/includes/search/sphinx/config_comment.php b/phpBB/includes/search/sphinx/config_comment.php
deleted file mode 100644
index 7f695dbf0c..0000000000
--- a/phpBB/includes/search/sphinx/config_comment.php
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-/**
-*
-* @package search
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* phpbb_search_sphinx_config_comment
-* Represents a comment inside the sphinx configuration
-*/
-class phpbb_search_sphinx_config_comment
-{
- private $exact_string;
-
- /**
- * Create a new comment
- *
- * @param string $exact_string The content of the comment including newlines, leading whitespace, etc.
- *
- * @access public
- */
- function __construct($exact_string)
- {
- $this->exact_string = $exact_string;
- }
-
- /**
- * Simply returns the comment as it was created
- *
- * @return string The exact string that was specified in the constructor
- *
- * @access public
- */
- function to_string()
- {
- return $this->exact_string;
- }
-}
diff --git a/phpBB/includes/search/sphinx/config_section.php b/phpBB/includes/search/sphinx/config_section.php
deleted file mode 100644
index 79c9c8563d..0000000000
--- a/phpBB/includes/search/sphinx/config_section.php
+++ /dev/null
@@ -1,162 +0,0 @@
-<?php
-/**
-*
-* @package search
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* phpbb_search_sphinx_config_section
-* Represents a single section inside the sphinx configuration
-*/
-class phpbb_search_sphinx_config_section
-{
- private $name;
- private $comment;
- private $end_comment;
- private $variables = array();
-
- /**
- * Construct a new section
- *
- * @param string $name Name of the section
- * @param string $comment Comment that should be appended after the name in the
- * textual format.
- *
- * @access public
- */
- function __construct($name, $comment)
- {
- $this->name = $name;
- $this->comment = $comment;
- $this->end_comment = '';
- }
-
- /**
- * Add a variable object to the list of variables in this section
- *
- * @param phpbb_search_sphinx_config_variable $variable The variable object
- *
- * @access public
- */
- function add_variable($variable)
- {
- $this->variables[] = $variable;
- }
-
- /**
- * Adds a comment after the closing bracket in the textual representation
- *
- * @param string $end_comment
- *
- * @access public
- */
- function set_end_comment($end_comment)
- {
- $this->end_comment = $end_comment;
- }
-
- /**
- * Getter for the name of this section
- *
- * @return string Section's name
- *
- * @access public
- */
- function get_name()
- {
- return $this->name;
- }
-
- /**
- * Get a variable object by its name
- *
- * @param string $name The name of the variable that shall be returned
- * @return phpbb_search_sphinx_config_section The first variable object from this section with the
- * given name or null if none was found
- *
- * @access public
- */
- function get_variable_by_name($name)
- {
- for ($i = 0, $size = sizeof($this->variables); $i < $size; $i++)
- {
- // Make sure this is a variable object and not a comment
- if (($this->variables[$i] instanceof phpbb_search_sphinx_config_variable) && $this->variables[$i]->get_name() == $name)
- {
- return $this->variables[$i];
- }
- }
- }
-
- /**
- * Deletes all variables with the given name
- *
- * @param string $name The name of the variable objects that are supposed to be removed
- *
- * @access public
- */
- function delete_variables_by_name($name)
- {
- for ($i = 0, $size = sizeof($this->variables); $i < $size; $i++)
- {
- // Make sure this is a variable object and not a comment
- if (($this->variables[$i] instanceof phpbb_search_sphinx_config_variable) && $this->variables[$i]->get_name() == $name)
- {
- array_splice($this->variables, $i, 1);
- $i--;
- }
- }
- }
-
- /**
- * Create a new variable object and append it to the variable list of this section
- *
- * @param string $name The name for the new variable
- * @param string $value The value for the new variable
- * @return phpbb_search_sphinx_config_variable Variable object that was created
- *
- * @access public
- */
- function create_variable($name, $value)
- {
- $this->variables[] = new phpbb_search_sphinx_config_variable($name, $value, '');
- return $this->variables[sizeof($this->variables) - 1];
- }
-
- /**
- * Turns this object into a string which can be written to a config file
- *
- * @return string Config data in textual form, parsable for sphinx
- *
- * @access public
- */
- function to_string()
- {
- $content = $this->name . ' ' . $this->comment . "\n{\n";
-
- // Make sure we don't get too many newlines after the opening bracket
- while (trim($this->variables[0]->to_string()) == '')
- {
- array_shift($this->variables);
- }
-
- foreach ($this->variables as $variable)
- {
- $content .= $variable->to_string();
- }
- $content .= '}' . $this->end_comment . "\n";
-
- return $content;
- }
-}
diff --git a/phpBB/includes/search/sphinx/config_variable.php b/phpBB/includes/search/sphinx/config_variable.php
deleted file mode 100644
index 35abe281cb..0000000000
--- a/phpBB/includes/search/sphinx/config_variable.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-/**
-*
-* @package search
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* phpbb_search_sphinx_config_variable
-* Represents a single variable inside the sphinx configuration
-*/
-class phpbb_search_sphinx_config_variable
-{
- private $name;
- private $value;
- private $comment;
-
- /**
- * Constructs a new variable object
- *
- * @param string $name Name of the variable
- * @param string $value Value of the variable
- * @param string $comment Optional comment after the variable in the
- * config file
- *
- * @access public
- */
- function __construct($name, $value, $comment)
- {
- $this->name = $name;
- $this->value = $value;
- $this->comment = $comment;
- }
-
- /**
- * Getter for the variable's name
- *
- * @return string The variable object's name
- *
- * @access public
- */
- function get_name()
- {
- return $this->name;
- }
-
- /**
- * Allows changing the variable's value
- *
- * @param string $value New value for this variable
- *
- * @access public
- */
- function set_value($value)
- {
- $this->value = $value;
- }
-
- /**
- * Turns this object into a string readable by sphinx
- *
- * @return string Config data in textual form
- *
- * @access public
- */
- function to_string()
- {
- return "\t" . $this->name . ' = ' . str_replace("\n", "\\\n", $this->value) . ' ' . $this->comment . "\n";
- }
-}
diff --git a/phpBB/includes/session.php b/phpBB/includes/session.php
deleted file mode 100644
index ee8a4094c7..0000000000
--- a/phpBB/includes/session.php
+++ /dev/null
@@ -1,1521 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Session class
-* @package phpBB3
-*/
-class phpbb_session
-{
- var $cookie_data = array();
- var $page = array();
- var $data = array();
- var $browser = '';
- var $forwarded_for = '';
- var $host = '';
- var $session_id = '';
- var $ip = '';
- var $load = 0;
- var $time_now = 0;
- var $update_session_page = true;
-
- /**
- * Extract current session page
- *
- * @param string $root_path current root path (phpbb_root_path)
- */
- static function extract_current_page($root_path)
- {
- global $request;
-
- $page_array = array();
-
- // First of all, get the request uri...
- $script_name = htmlspecialchars_decode($request->server('PHP_SELF'));
- $args = explode('&', htmlspecialchars_decode($request->server('QUERY_STRING')));
-
- // If we are unable to get the script name we use REQUEST_URI as a failover and note it within the page array for easier support...
- if (!$script_name)
- {
- $script_name = htmlspecialchars_decode($request->server('REQUEST_URI'));
- $script_name = (($pos = strpos($script_name, '?')) !== false) ? substr($script_name, 0, $pos) : $script_name;
- $page_array['failover'] = 1;
- }
-
- // Replace backslashes and doubled slashes (could happen on some proxy setups)
- $script_name = str_replace(array('\\', '//'), '/', $script_name);
-
- // Now, remove the sid and let us get a clean query string...
- $use_args = array();
-
- // Since some browser do not encode correctly we need to do this with some "special" characters...
- // " -> %22, ' => %27, < -> %3C, > -> %3E
- $find = array('"', "'", '<', '>');
- $replace = array('%22', '%27', '%3C', '%3E');
-
- foreach ($args as $key => $argument)
- {
- if (strpos($argument, 'sid=') === 0)
- {
- continue;
- }
-
- $use_args[] = str_replace($find, $replace, $argument);
- }
- unset($args);
-
- // The following examples given are for an request uri of {path to the phpbb directory}/adm/index.php?i=10&b=2
-
- // The current query string
- $query_string = trim(implode('&', $use_args));
-
- // basenamed page name (for example: index.php)
- $page_name = (substr($script_name, -1, 1) == '/') ? '' : basename($script_name);
- $page_name = urlencode(htmlspecialchars($page_name));
-
- // current directory within the phpBB root (for example: adm)
- $root_dirs = explode('/', str_replace('\\', '/', phpbb_realpath($root_path)));
- $page_dirs = explode('/', str_replace('\\', '/', phpbb_realpath('./')));
- $intersection = array_intersect_assoc($root_dirs, $page_dirs);
-
- $root_dirs = array_diff_assoc($root_dirs, $intersection);
- $page_dirs = array_diff_assoc($page_dirs, $intersection);
-
- $page_dir = str_repeat('../', sizeof($root_dirs)) . implode('/', $page_dirs);
-
- if ($page_dir && substr($page_dir, -1, 1) == '/')
- {
- $page_dir = substr($page_dir, 0, -1);
- }
-
- // Current page from phpBB root (for example: adm/index.php?i=10&b=2)
- $page = (($page_dir) ? $page_dir . '/' : '') . $page_name . (($query_string) ? "?$query_string" : '');
-
- // The script path from the webroot to the current directory (for example: /phpBB3/adm/) : always prefixed with / and ends in /
- $script_path = trim(str_replace('\\', '/', dirname($script_name)));
-
- // The script path from the webroot to the phpBB root (for example: /phpBB3/)
- $script_dirs = explode('/', $script_path);
- array_splice($script_dirs, -sizeof($page_dirs));
- $root_script_path = implode('/', $script_dirs) . (sizeof($root_dirs) ? '/' . implode('/', $root_dirs) : '');
-
- // We are on the base level (phpBB root == webroot), lets adjust the variables a bit...
- if (!$root_script_path)
- {
- $root_script_path = ($page_dir) ? str_replace($page_dir, '', $script_path) : $script_path;
- }
-
- $script_path .= (substr($script_path, -1, 1) == '/') ? '' : '/';
- $root_script_path .= (substr($root_script_path, -1, 1) == '/') ? '' : '/';
-
- $page_array += array(
- 'page_name' => $page_name,
- 'page_dir' => $page_dir,
-
- 'query_string' => $query_string,
- 'script_path' => str_replace(' ', '%20', htmlspecialchars($script_path)),
- 'root_script_path' => str_replace(' ', '%20', htmlspecialchars($root_script_path)),
-
- 'page' => $page,
- 'forum' => request_var('f', 0),
- );
-
- return $page_array;
- }
-
- /**
- * Get valid hostname/port. HTTP_HOST is used, SERVER_NAME if HTTP_HOST not present.
- */
- function extract_current_hostname()
- {
- global $config, $request;
-
- // Get hostname
- $host = htmlspecialchars_decode($request->header('Host', $request->server('SERVER_NAME')));
-
- // Should be a string and lowered
- $host = (string) strtolower($host);
-
- // If host is equal the cookie domain or the server name (if config is set), then we assume it is valid
- if ((isset($config['cookie_domain']) && $host === $config['cookie_domain']) || (isset($config['server_name']) && $host === $config['server_name']))
- {
- return $host;
- }
-
- // Is the host actually a IP? If so, we use the IP... (IPv4)
- if (long2ip(ip2long($host)) === $host)
- {
- return $host;
- }
-
- // Now return the hostname (this also removes any port definition). The http:// is prepended to construct a valid URL, hosts never have a scheme assigned
- $host = @parse_url('http://' . $host);
- $host = (!empty($host['host'])) ? $host['host'] : '';
-
- // Remove any portions not removed by parse_url (#)
- $host = str_replace('#', '', $host);
-
- // If, by any means, the host is now empty, we will use a "best approach" way to guess one
- if (empty($host))
- {
- if (!empty($config['server_name']))
- {
- $host = $config['server_name'];
- }
- else if (!empty($config['cookie_domain']))
- {
- $host = (strpos($config['cookie_domain'], '.') === 0) ? substr($config['cookie_domain'], 1) : $config['cookie_domain'];
- }
- else
- {
- // Set to OS hostname or localhost
- $host = (function_exists('php_uname')) ? php_uname('n') : 'localhost';
- }
- }
-
- // It may be still no valid host, but for sure only a hostname (we may further expand on the cookie domain... if set)
- return $host;
- }
-
- /**
- * Start session management
- *
- * This is where all session activity begins. We gather various pieces of
- * information from the client and server. We test to see if a session already
- * exists. If it does, fine and dandy. If it doesn't we'll go on to create a
- * new one ... pretty logical heh? We also examine the system load (if we're
- * running on a system which makes such information readily available) and
- * halt if it's above an admin definable limit.
- *
- * @param bool $update_session_page if true the session page gets updated.
- * This can be set to circumvent certain scripts to update the users last visited page.
- */
- function session_begin($update_session_page = true)
- {
- global $phpEx, $SID, $_SID, $_EXTRA_URL, $db, $config, $phpbb_root_path;
- global $request;
-
- // Give us some basic information
- $this->time_now = time();
- $this->cookie_data = array('u' => 0, 'k' => '');
- $this->update_session_page = $update_session_page;
- $this->browser = $request->header('User-Agent');
- $this->referer = $request->header('Referer');
- $this->forwarded_for = $request->header('X-Forwarded-For');
-
- $this->host = $this->extract_current_hostname();
- $this->page = $this->extract_current_page($phpbb_root_path);
-
- // if the forwarded for header shall be checked we have to validate its contents
- if ($config['forwarded_for_check'])
- {
- $this->forwarded_for = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->forwarded_for));
-
- // split the list of IPs
- $ips = explode(' ', $this->forwarded_for);
- 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))
- {
- // contains invalid data, don't use the forwarded for header
- $this->forwarded_for = '';
- break;
- }
- }
- }
- else
- {
- $this->forwarded_for = '';
- }
-
- if ($request->is_set($config['cookie_name'] . '_sid', phpbb_request_interface::COOKIE) || $request->is_set($config['cookie_name'] . '_u', phpbb_request_interface::COOKIE))
- {
- $this->cookie_data['u'] = request_var($config['cookie_name'] . '_u', 0, false, true);
- $this->cookie_data['k'] = request_var($config['cookie_name'] . '_k', '', false, true);
- $this->session_id = request_var($config['cookie_name'] . '_sid', '', false, true);
-
- $SID = (defined('NEED_SID')) ? '?sid=' . $this->session_id : '?sid=';
- $_SID = (defined('NEED_SID')) ? $this->session_id : '';
-
- if (empty($this->session_id))
- {
- $this->session_id = $_SID = request_var('sid', '');
- $SID = '?sid=' . $this->session_id;
- $this->cookie_data = array('u' => 0, 'k' => '');
- }
- }
- else
- {
- $this->session_id = $_SID = request_var('sid', '');
- $SID = '?sid=' . $this->session_id;
- }
-
- $_EXTRA_URL = array();
-
- // 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 = htmlspecialchars_decode($request->server('REMOTE_ADDR'));
- $this->ip = preg_replace('# {2,}#', ' ', str_replace(',', ' ', $this->ip));
-
- // split the list of IPs
- $ips = explode(' ', trim($this->ip));
-
- // Default IP if REMOTE_ADDR is invalid
- $this->ip = '127.0.0.1';
-
- foreach ($ips as $ip)
- {
- if (function_exists('phpbb_ip_normalise'))
- {
- // Normalise IP address
- $ip = phpbb_ip_normalise($ip);
-
- if (empty($ip))
- {
- // IP address is invalid.
- break;
- }
-
- // IP address is valid.
- $this->ip = $ip;
-
- // Skip legacy code.
- continue;
- }
-
- if (preg_match(get_preg_expression('ipv4'), $ip))
- {
- $this->ip = $ip;
- }
- else if (preg_match(get_preg_expression('ipv6'), $ip))
- {
- // Quick check for IPv4-mapped address in IPv6
- if (stripos($ip, '::ffff:') === 0)
- {
- $ipv4 = substr($ip, 7);
-
- if (preg_match(get_preg_expression('ipv4'), $ipv4))
- {
- $ip = $ipv4;
- }
- }
-
- $this->ip = $ip;
- }
- else
- {
- // We want to use the last valid address in the chain
- // Leave foreach loop when address is invalid
- break;
- }
- }
-
- $this->load = false;
-
- // Load limit check (if applicable)
- if ($config['limit_load'] || $config['limit_search_load'])
- {
- if ((function_exists('sys_getloadavg') && $load = sys_getloadavg()) || ($load = explode(' ', @file_get_contents('/proc/loadavg'))))
- {
- $this->load = array_slice($load, 0, 1);
- $this->load = floatval($this->load[0]);
- }
- else
- {
- set_config('limit_load', '0');
- set_config('limit_search_load', '0');
- }
- }
-
- // if no session id is set, redirect to index.php
- $session_id = $request->variable('sid', '');
- if (defined('NEED_SID') && (empty($session_id) || $this->session_id !== $session_id))
- {
- send_status_line(401, 'Not authorized');
- redirect(append_sid("{$phpbb_root_path}index.$phpEx"));
- }
-
- // if session id is set
- if (!empty($this->session_id))
- {
- $sql = 'SELECT u.*, s.*
- FROM ' . SESSIONS_TABLE . ' s, ' . USERS_TABLE . " u
- WHERE s.session_id = '" . $db->sql_escape($this->session_id) . "'
- AND u.user_id = s.session_user_id";
- $result = $db->sql_query($sql);
- $this->data = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- // Did the session exist in the DB?
- if (isset($this->data['user_id']))
- {
- // Validate IP length according to admin ... enforces an IP
- // check on bots if admin requires this
-// $quadcheck = ($config['ip_check_bot'] && $this->data['user_type'] & USER_BOT) ? 4 : $config['ip_check'];
-
- if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false)
- {
- $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']);
- $u_ip = short_ipv6($this->ip, $config['ip_check']);
- }
- else
- {
- $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check']));
- $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check']));
- }
-
- $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 149))) : '';
- $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 149))) : '';
-
- $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : '';
- $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : '';
-
- // referer checks
- // The @ before $config['referer_validation'] suppresses notices present while running the updater
- $check_referer_path = (@$config['referer_validation'] == REFERER_VALIDATE_PATH);
- $referer_valid = true;
-
- // we assume HEAD and TRACE to be foul play and thus only whitelist GET
- if (@$config['referer_validation'] && strtolower($request->server('REQUEST_METHOD')) !== 'get')
- {
- $referer_valid = $this->validate_referer($check_referer_path);
- }
-
- if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for && $referer_valid)
- {
- $session_expired = false;
-
- // Check whether the session is still valid if we have one
- $method = basename(trim($config['auth_method']));
- include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
-
- $method = 'validate_session_' . $method;
- if (function_exists($method))
- {
- if (!$method($this->data))
- {
- $session_expired = true;
- }
- }
-
- if (!$session_expired)
- {
- // Check the session length timeframe if autologin is not enabled.
- // Else check the autologin length... and also removing those having autologin enabled but no longer allowed board-wide.
- if (!$this->data['session_autologin'])
- {
- if ($this->data['session_time'] < $this->time_now - ($config['session_length'] + 60))
- {
- $session_expired = true;
- }
- }
- else if (!$config['allow_autologin'] || ($config['max_autologin_time'] && $this->data['session_time'] < $this->time_now - (86400 * (int) $config['max_autologin_time']) + 60))
- {
- $session_expired = true;
- }
- }
-
- if (!$session_expired)
- {
- // Only update session DB a minute or so after last update or if page changes
- if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
- {
- $sql_ary = array('session_time' => $this->time_now);
-
- if ($this->update_session_page)
- {
- $sql_ary['session_page'] = substr($this->page['page'], 0, 199);
- $sql_ary['session_forum_id'] = $this->page['forum'];
- }
-
- $db->sql_return_on_error(true);
-
- $this->update_session($sql_ary);
-
- $db->sql_return_on_error(false);
-
- // If the database is not yet updated, there will be an error due to the session_forum_id
- // @todo REMOVE for 3.0.2
- if ($result === false)
- {
- unset($sql_ary['session_forum_id']);
-
- $this->update_session($sql_ary);
- }
-
- 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;
- $this->data['is_bot'] = (!$this->data['is_registered'] && $this->data['user_id'] != ANONYMOUS) ? true : false;
- $this->data['user_lang'] = basename($this->data['user_lang']);
-
- return true;
- }
- }
- else
- {
- // Added logging temporarly to help debug bugs...
- if (defined('DEBUG') && $this->data['user_id'] != ANONYMOUS)
- {
- if ($referer_valid)
- {
- add_log('critical', 'LOG_IP_BROWSER_FORWARDED_CHECK', $u_ip, $s_ip, $u_browser, $s_browser, htmlspecialchars($u_forwarded_for), htmlspecialchars($s_forwarded_for));
- }
- else
- {
- add_log('critical', 'LOG_REFERER_INVALID', $this->referer);
- }
- }
- }
- }
- }
-
- // If we reach here then no (valid) session exists. So we'll create a new one
- return $this->session_create();
- }
-
- /**
- * Create a new session
- *
- * If upon trying to start a session we discover there is nothing existing we
- * jump here. Additionally this method is called directly during login to regenerate
- * the session for the specific user. In this method we carry out a number of tasks;
- * garbage collection, (search)bot checking, banned user comparison. Basically
- * though this method will result in a new session for a specific user.
- */
- function session_create($user_id = false, $set_admin = false, $persist_login = false, $viewonline = true)
- {
- global $SID, $_SID, $db, $config, $cache, $phpbb_root_path, $phpEx;
-
- $this->data = array();
-
- /* Garbage collection ... remove old sessions updating user information
- // if necessary. It means (potentially) 11 queries but only infrequently
- if ($this->time_now > $config['session_last_gc'] + $config['session_gc'])
- {
- $this->session_gc();
- }*/
-
- // Do we allow autologin on this board? No? Then override anything
- // that may be requested here
- if (!$config['allow_autologin'])
- {
- $this->cookie_data['k'] = $persist_login = false;
- }
-
- /**
- * Here we do a bot check, oh er saucy! No, not that kind of bot
- * check. We loop through the list of bots defined by the admin and
- * see if we have any useragent and/or IP matches. If we do, this is a
- * bot, act accordingly
- */
- $bot = false;
- $active_bots = $cache->obtain_bots();
-
- foreach ($active_bots as $row)
- {
- if ($row['bot_agent'] && preg_match('#' . str_replace('\*', '.*?', preg_quote($row['bot_agent'], '#')) . '#i', $this->browser))
- {
- $bot = $row['user_id'];
- }
-
- // If ip is supplied, we will make sure the ip is matching too...
- if ($row['bot_ip'] && ($bot || !$row['bot_agent']))
- {
- // Set bot to false, then we only have to set it to true if it is matching
- $bot = false;
-
- foreach (explode(',', $row['bot_ip']) as $bot_ip)
- {
- $bot_ip = trim($bot_ip);
-
- if (!$bot_ip)
- {
- continue;
- }
-
- if (strpos($this->ip, $bot_ip) === 0)
- {
- $bot = (int) $row['user_id'];
- break;
- }
- }
- }
-
- if ($bot)
- {
- break;
- }
- }
-
- $method = basename(trim($config['auth_method']));
- include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
-
- $method = 'autologin_' . $method;
- if (function_exists($method))
- {
- $this->data = $method();
-
- if (sizeof($this->data))
- {
- $this->cookie_data['k'] = '';
- $this->cookie_data['u'] = $this->data['user_id'];
- }
- }
-
- // If we're presented with an autologin key we'll join against it.
- // Else if we've been passed a user_id we'll grab data based on that
- if (isset($this->cookie_data['k']) && $this->cookie_data['k'] && $this->cookie_data['u'] && !sizeof($this->data))
- {
- $sql = 'SELECT u.*
- FROM ' . USERS_TABLE . ' u, ' . SESSIONS_KEYS_TABLE . ' k
- WHERE u.user_id = ' . (int) $this->cookie_data['u'] . '
- AND u.user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ")
- AND k.user_id = u.user_id
- AND k.key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'";
- $result = $db->sql_query($sql);
- $this->data = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
- $bot = false;
- }
- else if ($user_id !== false && !sizeof($this->data))
- {
- $this->cookie_data['k'] = '';
- $this->cookie_data['u'] = $user_id;
-
- $sql = 'SELECT *
- FROM ' . USERS_TABLE . '
- WHERE user_id = ' . (int) $this->cookie_data['u'] . '
- AND user_type IN (' . USER_NORMAL . ', ' . USER_FOUNDER . ')';
- $result = $db->sql_query($sql);
- $this->data = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
- $bot = false;
- }
-
- // Bot user, if they have a SID in the Request URI we need to get rid of it
- // otherwise they'll index this page with the SID, duplicate content oh my!
- if ($bot && isset($_GET['sid']))
- {
- send_status_line(301, 'Moved Permanently');
- redirect(build_url(array('sid')));
- }
-
- // If no data was returned one or more of the following occurred:
- // Key didn't match one in the DB
- // User does not exist
- // User is inactive
- // User is bot
- if (!sizeof($this->data) || !is_array($this->data))
- {
- $this->cookie_data['k'] = '';
- $this->cookie_data['u'] = ($bot) ? $bot : ANONYMOUS;
-
- if (!$bot)
- {
- $sql = 'SELECT *
- FROM ' . USERS_TABLE . '
- WHERE user_id = ' . (int) $this->cookie_data['u'];
- }
- else
- {
- // We give bots always the same session if it is not yet expired.
- $sql = 'SELECT u.*, s.*
- FROM ' . USERS_TABLE . ' u
- LEFT JOIN ' . SESSIONS_TABLE . ' s ON (s.session_user_id = u.user_id)
- WHERE u.user_id = ' . (int) $bot;
- }
-
- $result = $db->sql_query($sql);
- $this->data = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
- }
-
- if ($this->data['user_id'] != ANONYMOUS && !$bot)
- {
- $this->data['session_last_visit'] = (isset($this->data['session_time']) && $this->data['session_time']) ? $this->data['session_time'] : (($this->data['user_lastvisit']) ? $this->data['user_lastvisit'] : time());
- }
- else
- {
- $this->data['session_last_visit'] = $this->time_now;
- }
-
- // Force user id to be integer...
- $this->data['user_id'] = (int) $this->data['user_id'];
-
- // At this stage we should have a filled data array, defined cookie u and k data.
- // data array should contain recent session info if we're a real user and a recent
- // session exists in which case session_id will also be set
-
- // Is user banned? Are they excluded? Won't return on ban, exists within method
- if ($this->data['user_type'] != USER_FOUNDER)
- {
- if (!$config['forwarded_for_check'])
- {
- $this->check_ban($this->data['user_id'], $this->ip);
- }
- else
- {
- $ips = explode(' ', $this->forwarded_for);
- $ips[] = $this->ip;
- $this->check_ban($this->data['user_id'], $ips);
- }
- }
-
- $this->data['is_registered'] = (!$bot && $this->data['user_id'] != ANONYMOUS && ($this->data['user_type'] == USER_NORMAL || $this->data['user_type'] == USER_FOUNDER)) ? true : false;
- $this->data['is_bot'] = ($bot) ? true : false;
-
- // If our friend is a bot, we re-assign a previously assigned session
- if ($this->data['is_bot'] && $bot == $this->data['user_id'] && $this->data['session_id'])
- {
- // Only assign the current session if the ip, browser and forwarded_for match...
- if (strpos($this->ip, ':') !== false && strpos($this->data['session_ip'], ':') !== false)
- {
- $s_ip = short_ipv6($this->data['session_ip'], $config['ip_check']);
- $u_ip = short_ipv6($this->ip, $config['ip_check']);
- }
- else
- {
- $s_ip = implode('.', array_slice(explode('.', $this->data['session_ip']), 0, $config['ip_check']));
- $u_ip = implode('.', array_slice(explode('.', $this->ip), 0, $config['ip_check']));
- }
-
- $s_browser = ($config['browser_check']) ? trim(strtolower(substr($this->data['session_browser'], 0, 149))) : '';
- $u_browser = ($config['browser_check']) ? trim(strtolower(substr($this->browser, 0, 149))) : '';
-
- $s_forwarded_for = ($config['forwarded_for_check']) ? substr($this->data['session_forwarded_for'], 0, 254) : '';
- $u_forwarded_for = ($config['forwarded_for_check']) ? substr($this->forwarded_for, 0, 254) : '';
-
- if ($u_ip === $s_ip && $s_browser === $u_browser && $s_forwarded_for === $u_forwarded_for)
- {
- $this->session_id = $this->data['session_id'];
-
- // Only update session DB a minute or so after last update or if page changes
- if ($this->time_now - $this->data['session_time'] > 60 || ($this->update_session_page && $this->data['session_page'] != $this->page['page']))
- {
- $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now;
-
- $sql_ary = array('session_time' => $this->time_now, 'session_last_visit' => $this->time_now, 'session_admin' => 0);
-
- if ($this->update_session_page)
- {
- $sql_ary['session_page'] = substr($this->page['page'], 0, 199);
- $sql_ary['session_forum_id'] = $this->page['forum'];
- }
-
- $this->update_session($sql_ary);
-
- // Update the last visit time
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_lastvisit = ' . (int) $this->data['session_time'] . '
- WHERE user_id = ' . (int) $this->data['user_id'];
- $db->sql_query($sql);
- }
-
- $SID = '?sid=';
- $_SID = '';
- return true;
- }
- else
- {
- // If the ip and browser does not match make sure we only have one bot assigned to one session
- $db->sql_query('DELETE FROM ' . SESSIONS_TABLE . ' WHERE session_user_id = ' . $this->data['user_id']);
- }
- }
-
- $session_autologin = (($this->cookie_data['k'] || $persist_login) && $this->data['is_registered']) ? true : false;
- $set_admin = ($set_admin && $this->data['is_registered']) ? true : false;
-
- // Create or update the session
- $sql_ary = array(
- 'session_user_id' => (int) $this->data['user_id'],
- 'session_start' => (int) $this->time_now,
- 'session_last_visit' => (int) $this->data['session_last_visit'],
- 'session_time' => (int) $this->time_now,
- 'session_browser' => (string) trim(substr($this->browser, 0, 149)),
- 'session_forwarded_for' => (string) $this->forwarded_for,
- 'session_ip' => (string) $this->ip,
- 'session_autologin' => ($session_autologin) ? 1 : 0,
- 'session_admin' => ($set_admin) ? 1 : 0,
- 'session_viewonline' => ($viewonline) ? 1 : 0,
- );
-
- if ($this->update_session_page)
- {
- $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199);
- $sql_ary['session_forum_id'] = $this->page['forum'];
- }
-
- $db->sql_return_on_error(true);
-
- $sql = 'DELETE
- FROM ' . SESSIONS_TABLE . '
- WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\'
- AND session_user_id = ' . ANONYMOUS;
-
- if (!defined('IN_ERROR_HANDLER') && (!$this->session_id || !$db->sql_query($sql) || !$db->sql_affectedrows()))
- {
- // Limit new sessions in 1 minute period (if required)
- if (empty($this->data['session_time']) && $config['active_sessions'])
- {
-// $db->sql_return_on_error(false);
-
- $sql = 'SELECT COUNT(session_id) AS sessions
- FROM ' . SESSIONS_TABLE . '
- WHERE session_time >= ' . ($this->time_now - 60);
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if ((int) $row['sessions'] > (int) $config['active_sessions'])
- {
- send_status_line(503, 'Service Unavailable');
- trigger_error('BOARD_UNAVAILABLE');
- }
- }
- }
-
- // Since we re-create the session id here, the inserted row must be unique. Therefore, we display potential errors.
- // Commented out because it will not allow forums to update correctly
-// $db->sql_return_on_error(false);
-
- // Something quite important: session_page always holds the *last* page visited, except for the *first* visit.
- // We are not able to simply have an empty session_page btw, therefore we need to tell phpBB how to detect this special case.
- // If the session id is empty, we have a completely new one and will set an "identifier" here. This identifier is able to be checked later.
- if (empty($this->data['session_id']))
- {
- // This is a temporary variable, only set for the very first visit
- $this->data['session_created'] = true;
- }
-
- $this->session_id = $this->data['session_id'] = md5(unique_id());
-
- $sql_ary['session_id'] = (string) $this->session_id;
- $sql_ary['session_page'] = (string) substr($this->page['page'], 0, 199);
- $sql_ary['session_forum_id'] = $this->page['forum'];
-
- $sql = 'INSERT INTO ' . SESSIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
- $db->sql_query($sql);
-
- $db->sql_return_on_error(false);
-
- // Regenerate autologin/persistent login key
- if ($session_autologin)
- {
- $this->set_login_key();
- }
-
- // refresh data
- $SID = '?sid=' . $this->session_id;
- $_SID = $this->session_id;
- $this->data = array_merge($this->data, $sql_ary);
-
- if (!$bot)
- {
- $cookie_expire = $this->time_now + (($config['max_autologin_time']) ? 86400 * (int) $config['max_autologin_time'] : 31536000);
-
- $this->set_cookie('u', $this->cookie_data['u'], $cookie_expire);
- $this->set_cookie('k', $this->cookie_data['k'], $cookie_expire);
- $this->set_cookie('sid', $this->session_id, $cookie_expire);
-
- unset($cookie_expire);
-
- $sql = 'SELECT COUNT(session_id) AS sessions
- FROM ' . SESSIONS_TABLE . '
- WHERE session_user_id = ' . (int) $this->data['user_id'] . '
- AND session_time >= ' . (int) ($this->time_now - (max($config['session_length'], $config['form_token_lifetime'])));
- $result = $db->sql_query($sql);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if ((int) $row['sessions'] <= 1 || empty($this->data['user_form_salt']))
- {
- $this->data['user_form_salt'] = unique_id();
- // Update the form key
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_form_salt = \'' . $db->sql_escape($this->data['user_form_salt']) . '\'
- WHERE user_id = ' . (int) $this->data['user_id'];
- $db->sql_query($sql);
- }
- }
- else
- {
- $this->data['session_time'] = $this->data['session_last_visit'] = $this->time_now;
-
- // Update the last visit time
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_lastvisit = ' . (int) $this->data['session_time'] . '
- WHERE user_id = ' . (int) $this->data['user_id'];
- $db->sql_query($sql);
-
- $SID = '?sid=';
- $_SID = '';
- }
-
- return true;
- }
-
- /**
- * Kills a session
- *
- * This method does what it says on the tin. It will delete a pre-existing session.
- * It resets cookie information (destroying any autologin key within that cookie data)
- * and update the users information from the relevant session data. It will then
- * grab guest user information.
- */
- function session_kill($new_session = true)
- {
- global $SID, $_SID, $db, $config, $phpbb_root_path, $phpEx;
-
- $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
- WHERE session_id = '" . $db->sql_escape($this->session_id) . "'
- AND session_user_id = " . (int) $this->data['user_id'];
- $db->sql_query($sql);
-
- // Allow connecting logout with external auth method logout
- $method = basename(trim($config['auth_method']));
- include_once($phpbb_root_path . 'includes/auth/auth_' . $method . '.' . $phpEx);
-
- $method = 'logout_' . $method;
- if (function_exists($method))
- {
- $method($this->data, $new_session);
- }
-
- if ($this->data['user_id'] != ANONYMOUS)
- {
- // Delete existing session, update last visit info first!
- if (!isset($this->data['session_time']))
- {
- $this->data['session_time'] = time();
- }
-
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_lastvisit = ' . (int) $this->data['session_time'] . '
- WHERE user_id = ' . (int) $this->data['user_id'];
- $db->sql_query($sql);
-
- if ($this->cookie_data['k'])
- {
- $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . '
- WHERE user_id = ' . (int) $this->data['user_id'] . "
- AND key_id = '" . $db->sql_escape(md5($this->cookie_data['k'])) . "'";
- $db->sql_query($sql);
- }
-
- // Reset the data array
- $this->data = array();
-
- $sql = 'SELECT *
- FROM ' . USERS_TABLE . '
- WHERE user_id = ' . ANONYMOUS;
- $result = $db->sql_query($sql);
- $this->data = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
- }
-
- $cookie_expire = $this->time_now - 31536000;
- $this->set_cookie('u', '', $cookie_expire);
- $this->set_cookie('k', '', $cookie_expire);
- $this->set_cookie('sid', '', $cookie_expire);
- unset($cookie_expire);
-
- $SID = '?sid=';
- $this->session_id = $_SID = '';
-
- // To make sure a valid session is created we create one for the anonymous user
- if ($new_session)
- {
- $this->session_create(ANONYMOUS);
- }
-
- return true;
- }
-
- /**
- * Session garbage collection
- *
- * This looks a lot more complex than it really is. Effectively we are
- * deleting any sessions older than an admin definable limit. Due to the
- * way in which we maintain session data we have to ensure we update user
- * data before those sessions are destroyed. In addition this method
- * removes autologin key information that is older than an admin defined
- * limit.
- */
- function session_gc()
- {
- global $db, $config, $phpbb_root_path, $phpEx;
-
- $batch_size = 10;
-
- if (!$this->time_now)
- {
- $this->time_now = time();
- }
-
- // Firstly, delete guest sessions
- $sql = 'DELETE FROM ' . SESSIONS_TABLE . '
- WHERE session_user_id = ' . ANONYMOUS . '
- AND session_time < ' . (int) ($this->time_now - $config['session_length']);
- $db->sql_query($sql);
-
- // Get expired sessions, only most recent for each user
- $sql = 'SELECT session_user_id, session_page, MAX(session_time) AS recent_time
- FROM ' . SESSIONS_TABLE . '
- WHERE session_time < ' . ($this->time_now - $config['session_length']) . '
- GROUP BY session_user_id, session_page';
- $result = $db->sql_query_limit($sql, $batch_size);
-
- $del_user_id = array();
- $del_sessions = 0;
-
- while ($row = $db->sql_fetchrow($result))
- {
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_lastvisit = ' . (int) $row['recent_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "'
- WHERE user_id = " . (int) $row['session_user_id'];
- $db->sql_query($sql);
-
- $del_user_id[] = (int) $row['session_user_id'];
- $del_sessions++;
- }
- $db->sql_freeresult($result);
-
- if (sizeof($del_user_id))
- {
- // Delete expired sessions
- $sql = 'DELETE FROM ' . SESSIONS_TABLE . '
- WHERE ' . $db->sql_in_set('session_user_id', $del_user_id) . '
- AND session_time < ' . ($this->time_now - $config['session_length']);
- $db->sql_query($sql);
- }
-
- if ($del_sessions < $batch_size)
- {
- // Less than 10 users, update gc timer ... else we want gc
- // called again to delete other sessions
- set_config('session_last_gc', $this->time_now, true);
-
- if ($config['max_autologin_time'])
- {
- $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . '
- WHERE last_login < ' . (time() - (86400 * (int) $config['max_autologin_time']));
- $db->sql_query($sql);
- }
-
- // only called from CRON; should be a safe workaround until the infrastructure gets going
- if (!class_exists('phpbb_captcha_factory', false))
- {
- include($phpbb_root_path . "includes/captcha/captcha_factory." . $phpEx);
- }
- phpbb_captcha_factory::garbage_collect($config['captcha_plugin']);
-
- $sql = 'DELETE FROM ' . LOGIN_ATTEMPT_TABLE . '
- WHERE attempt_time < ' . (time() - (int) $config['ip_login_limit_time']);
- $db->sql_query($sql);
- }
-
- return;
- }
-
- /**
- * Sets a cookie
- *
- * Sets a cookie of the given name with the specified data for the given length of time. If no time is specified, a session cookie will be set.
- *
- * @param string $name Name of the cookie, will be automatically prefixed with the phpBB cookie name. track becomes [cookie_name]_track then.
- * @param string $cookiedata The data to hold within the cookie
- * @param int $cookietime The expiration time as UNIX timestamp. If 0 is provided, a session cookie is set.
- */
- function set_cookie($name, $cookiedata, $cookietime)
- {
- global $config;
-
- $name_data = rawurlencode($config['cookie_name'] . '_' . $name) . '=' . rawurlencode($cookiedata);
- $expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime);
- $domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain'];
-
- header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false);
- }
-
- /**
- * Check for banned user
- *
- * Checks whether the supplied user is banned by id, ip or email. If no parameters
- * are passed to the method pre-existing session data is used. If $return is false
- * this routine does not return on finding a banned user, it outputs a relevant
- * message and stops execution.
- *
- * @param string|array $user_ips Can contain a string with one IP or an array of multiple IPs
- */
- function check_ban($user_id = false, $user_ips = false, $user_email = false, $return = false)
- {
- global $config, $db;
-
- if (defined('IN_CHECK_BAN'))
- {
- return;
- }
-
- $banned = false;
- $cache_ttl = 3600;
- $where_sql = array();
-
- $sql = 'SELECT ban_ip, ban_userid, ban_email, ban_exclude, ban_give_reason, ban_end
- FROM ' . BANLIST_TABLE . '
- WHERE ';
-
- // Determine which entries to check, only return those
- if ($user_email === false)
- {
- $where_sql[] = "ban_email = ''";
- }
-
- if ($user_ips === false)
- {
- $where_sql[] = "(ban_ip = '' OR ban_exclude = 1)";
- }
-
- if ($user_id === false)
- {
- $where_sql[] = '(ban_userid = 0 OR ban_exclude = 1)';
- }
- else
- {
- $cache_ttl = ($user_id == ANONYMOUS) ? 3600 : 0;
- $_sql = '(ban_userid = ' . $user_id;
-
- if ($user_email !== false)
- {
- $_sql .= " OR ban_email <> ''";
- }
-
- if ($user_ips !== false)
- {
- $_sql .= " OR ban_ip <> ''";
- }
-
- $_sql .= ')';
-
- $where_sql[] = $_sql;
- }
-
- $sql .= (sizeof($where_sql)) ? implode(' AND ', $where_sql) : '';
- $result = $db->sql_query($sql, $cache_ttl);
-
- $ban_triggered_by = 'user';
- while ($row = $db->sql_fetchrow($result))
- {
- if ($row['ban_end'] && $row['ban_end'] < time())
- {
- continue;
- }
-
- $ip_banned = false;
- if (!empty($row['ban_ip']))
- {
- if (!is_array($user_ips))
- {
- $ip_banned = preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ips);
- }
- else
- {
- foreach ($user_ips as $user_ip)
- {
- if (preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_ip'], '#')) . '$#i', $user_ip))
- {
- $ip_banned = true;
- break;
- }
- }
- }
- }
-
- if ((!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id) ||
- $ip_banned ||
- (!empty($row['ban_email']) && preg_match('#^' . str_replace('\*', '.*?', preg_quote($row['ban_email'], '#')) . '$#i', $user_email)))
- {
- if (!empty($row['ban_exclude']))
- {
- $banned = false;
- break;
- }
- else
- {
- $banned = true;
- $ban_row = $row;
-
- if (!empty($row['ban_userid']) && intval($row['ban_userid']) == $user_id)
- {
- $ban_triggered_by = 'user';
- }
- else if ($ip_banned)
- {
- $ban_triggered_by = 'ip';
- }
- else
- {
- $ban_triggered_by = 'email';
- }
-
- // Don't break. Check if there is an exclude rule for this user
- }
- }
- }
- $db->sql_freeresult($result);
-
- if ($banned && !$return)
- {
- global $template;
-
- // If the session is empty we need to create a valid one...
- if (empty($this->session_id))
- {
- // This seems to be no longer needed? - #14971
-// $this->session_create(ANONYMOUS);
- }
-
- // Initiate environment ... since it won't be set at this stage
- $this->setup();
-
- // Logout the user, banned users are unable to use the normal 'logout' link
- if ($this->data['user_id'] != ANONYMOUS)
- {
- $this->session_kill();
- }
-
- // We show a login box here to allow founders accessing the board if banned by IP
- if (defined('IN_LOGIN') && $this->data['user_id'] == ANONYMOUS)
- {
- global $phpEx;
-
- $this->setup('ucp');
- $this->data['is_registered'] = $this->data['is_bot'] = false;
-
- // Set as a precaution to allow login_box() handling this case correctly as well as this function not being executed again.
- define('IN_CHECK_BAN', 1);
-
- login_box("index.$phpEx");
-
- // The false here is needed, else the user is able to circumvent the ban.
- $this->session_kill(false);
- }
-
- // Ok, we catch the case of an empty session id for the anonymous user...
- // This can happen if the user is logging in, banned by username and the login_box() being called "again".
- if (empty($this->session_id) && defined('IN_CHECK_BAN'))
- {
- $this->session_create(ANONYMOUS);
- }
-
-
- // Determine which message to output
- $till_date = ($ban_row['ban_end']) ? $this->format_date($ban_row['ban_end']) : '';
- $message = ($ban_row['ban_end']) ? 'BOARD_BAN_TIME' : 'BOARD_BAN_PERM';
-
- $message = sprintf($this->lang[$message], $till_date, '<a href="mailto:' . $config['board_contact'] . '">', '</a>');
- $message .= ($ban_row['ban_give_reason']) ? '<br /><br />' . sprintf($this->lang['BOARD_BAN_REASON'], $ban_row['ban_give_reason']) : '';
- $message .= '<br /><br /><em>' . $this->lang['BAN_TRIGGERED_BY_' . strtoupper($ban_triggered_by)] . '</em>';
-
- // To circumvent session_begin returning a valid value and the check_ban() not called on second page view, we kill the session again
- $this->session_kill(false);
-
- // A very special case... we are within the cron script which is not supposed to print out the ban message... show blank page
- if (defined('IN_CRON'))
- {
- garbage_collection();
- exit_handler();
- exit;
- }
-
- trigger_error($message);
- }
-
- return ($banned && $ban_row['ban_give_reason']) ? $ban_row['ban_give_reason'] : $banned;
- }
-
- /**
- * Check if ip is blacklisted
- * This should be called only where absolutly necessary
- *
- * Only IPv4 (rbldns does not support AAAA records/IPv6 lookups)
- *
- * @author satmd (from the php manual)
- * @param string $mode register/post - spamcop for example is ommitted for posting
- * @return false if ip is not blacklisted, else an array([checked server], [lookup])
- */
- function check_dnsbl($mode, $ip = false)
- {
- if ($ip === false)
- {
- $ip = $this->ip;
- }
-
- // Neither Spamhaus nor Spamcop supports IPv6 addresses.
- if (strpos($ip, ':') !== false)
- {
- return false;
- }
-
- $dnsbl_check = array(
- 'sbl.spamhaus.org' => 'http://www.spamhaus.org/query/bl?ip=',
- );
-
- if ($mode == 'register')
- {
- $dnsbl_check['bl.spamcop.net'] = 'http://spamcop.net/bl.shtml?';
- }
-
- if ($ip)
- {
- $quads = explode('.', $ip);
- $reverse_ip = $quads[3] . '.' . $quads[2] . '.' . $quads[1] . '.' . $quads[0];
-
- // Need to be listed on all servers...
- $listed = true;
- $info = array();
-
- foreach ($dnsbl_check as $dnsbl => $lookup)
- {
- if (phpbb_checkdnsrr($reverse_ip . '.' . $dnsbl . '.', 'A') === true)
- {
- $info = array($dnsbl, $lookup . $ip);
- }
- else
- {
- $listed = false;
- }
- }
-
- if ($listed)
- {
- return $info;
- }
- }
-
- return false;
- }
-
- /**
- * Check if URI is blacklisted
- * This should be called only where absolutly necessary, for example on the submitted website field
- * This function is not in use at the moment and is only included for testing purposes, it may not work at all!
- * This means it is untested at the moment and therefore commented out
- *
- * @param string $uri URI to check
- * @return true if uri is on blacklist, else false. Only blacklist is checked (~zero FP), no grey lists
- function check_uribl($uri)
- {
- // Normally parse_url() is not intended to parse uris
- // We need to get the top-level domain name anyway... change.
- $uri = parse_url($uri);
-
- if ($uri === false || empty($uri['host']))
- {
- return false;
- }
-
- $uri = trim($uri['host']);
-
- if ($uri)
- {
- // One problem here... the return parameter for the "windows" method is different from what
- // we expect... this may render this check useless...
- if (phpbb_checkdnsrr($uri . '.multi.uribl.com.', 'A') === true)
- {
- return true;
- }
- }
-
- return false;
- }
- */
-
- /**
- * Set/Update a persistent login key
- *
- * This method creates or updates a persistent session key. When a user makes
- * use of persistent (formerly auto-) logins a key is generated and stored in the
- * DB. When they revisit with the same key it's automatically updated in both the
- * DB and cookie. Multiple keys may exist for each user representing different
- * browsers or locations. As with _any_ non-secure-socket no passphrase login this
- * remains vulnerable to exploit.
- */
- function set_login_key($user_id = false, $key = false, $user_ip = false)
- {
- global $config, $db;
-
- $user_id = ($user_id === false) ? $this->data['user_id'] : $user_id;
- $user_ip = ($user_ip === false) ? $this->ip : $user_ip;
- $key = ($key === false) ? (($this->cookie_data['k']) ? $this->cookie_data['k'] : false) : $key;
-
- $key_id = unique_id(hexdec(substr($this->session_id, 0, 8)));
-
- $sql_ary = array(
- 'key_id' => (string) md5($key_id),
- 'last_ip' => (string) $this->ip,
- 'last_login' => (int) time()
- );
-
- if (!$key)
- {
- $sql_ary += array(
- 'user_id' => (int) $user_id
- );
- }
-
- if ($key)
- {
- $sql = 'UPDATE ' . SESSIONS_KEYS_TABLE . '
- SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
- WHERE user_id = ' . (int) $user_id . "
- AND key_id = '" . $db->sql_escape(md5($key)) . "'";
- }
- else
- {
- $sql = 'INSERT INTO ' . SESSIONS_KEYS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
- }
- $db->sql_query($sql);
-
- $this->cookie_data['k'] = $key_id;
-
- return false;
- }
-
- /**
- * Reset all login keys for the specified user
- *
- * This method removes all current login keys for a specified (or the current)
- * user. It will be called on password change to render old keys unusable
- */
- function reset_login_keys($user_id = false)
- {
- global $config, $db;
-
- $user_id = ($user_id === false) ? (int) $this->data['user_id'] : (int) $user_id;
-
- $sql = 'DELETE FROM ' . SESSIONS_KEYS_TABLE . '
- WHERE user_id = ' . (int) $user_id;
- $db->sql_query($sql);
-
- // If the user is logged in, update last visit info first before deleting sessions
- $sql = 'SELECT session_time, session_page
- FROM ' . SESSIONS_TABLE . '
- WHERE session_user_id = ' . (int) $user_id . '
- ORDER BY session_time DESC';
- $result = $db->sql_query_limit($sql, 1);
- $row = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- if ($row)
- {
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET user_lastvisit = ' . (int) $row['session_time'] . ", user_lastpage = '" . $db->sql_escape($row['session_page']) . "'
- WHERE user_id = " . (int) $user_id;
- $db->sql_query($sql);
- }
-
- // Let's also clear any current sessions for the specified user_id
- // If it's the current user then we'll leave this session intact
- $sql_where = 'session_user_id = ' . (int) $user_id;
- $sql_where .= ($user_id === (int) $this->data['user_id']) ? " AND session_id <> '" . $db->sql_escape($this->session_id) . "'" : '';
-
- $sql = 'DELETE FROM ' . SESSIONS_TABLE . "
- WHERE $sql_where";
- $db->sql_query($sql);
-
- // We're changing the password of the current user and they have a key
- // Lets regenerate it to be safe
- if ($user_id === (int) $this->data['user_id'] && $this->cookie_data['k'])
- {
- $this->set_login_key($user_id);
- }
- }
-
-
- /**
- * Check if the request originated from the same page.
- * @param bool $check_script_path If true, the path will be checked as well
- */
- function validate_referer($check_script_path = false)
- {
- global $config, $request;
-
- // 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))
- {
- return true;
- }
-
- $host = htmlspecialchars($this->host);
- $ref = substr($this->referer, strpos($this->referer, '://') + 3);
-
- if (!(stripos($ref, $host) === 0) && (!$config['force_server_vars'] || !(stripos($ref, $config['server_name']) === 0)))
- {
- return false;
- }
- else if ($check_script_path && rtrim($this->page['root_script_path'], '/') !== '')
- {
- $ref = substr($ref, strlen($host));
- $server_port = $request->server('SERVER_PORT', 0);
-
- if ($server_port !== 80 && $server_port !== 443 && stripos($ref, ":$server_port") === 0)
- {
- $ref = substr($ref, strlen(":$server_port"));
- }
-
- if (!(stripos(rtrim($ref, '/'), rtrim($this->page['root_script_path'], '/')) === 0))
- {
- return false;
- }
- }
-
- return true;
- }
-
-
- function unset_admin()
- {
- global $db;
- $sql = 'UPDATE ' . SESSIONS_TABLE . '
- SET session_admin = 0
- WHERE session_id = \'' . $db->sql_escape($this->session_id) . '\'';
- $db->sql_query($sql);
- }
-
- /**
- * Update the session data
- *
- * @param array $session_data associative array of session keys to be updated
- * @param string $session_id optional session_id, defaults to current user's session_id
- */
- public function update_session($session_data, $session_id = null)
- {
- global $db;
-
- $session_id = ($session_id) ? $session_id : $this->session_id;
-
- $sql = 'UPDATE ' . SESSIONS_TABLE . ' SET ' . $db->sql_build_array('UPDATE', $session_data) . "
- WHERE session_id = '" . $db->sql_escape($session_id) . "'";
- $db->sql_query($sql);
- }
-}
diff --git a/phpBB/includes/sphinxapi.php b/phpBB/includes/sphinxapi.php
index bd83b1d2e0..6c3b66710c 100644
--- a/phpBB/includes/sphinxapi.php
+++ b/phpBB/includes/sphinxapi.php
@@ -1,1712 +1,1712 @@
-<?php
-
-//
-// $Id: sphinxapi.php 3087 2012-01-30 23:07:35Z shodan $
-//
-
-//
-// Copyright (c) 2001-2012, Andrew Aksyonoff
-// Copyright (c) 2008-2012, Sphinx Technologies Inc
-// All rights reserved
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License. You should have
-// received a copy of the GPL license along with this program; if you
-// did not, you can find it at http://www.gnu.org/
-//
-
-/////////////////////////////////////////////////////////////////////////////
-// PHP version of Sphinx searchd client (PHP API)
-/////////////////////////////////////////////////////////////////////////////
-
-/// known searchd commands
-define ( "SEARCHD_COMMAND_SEARCH", 0 );
-define ( "SEARCHD_COMMAND_EXCERPT", 1 );
-define ( "SEARCHD_COMMAND_UPDATE", 2 );
-define ( "SEARCHD_COMMAND_KEYWORDS", 3 );
-define ( "SEARCHD_COMMAND_PERSIST", 4 );
-define ( "SEARCHD_COMMAND_STATUS", 5 );
-define ( "SEARCHD_COMMAND_FLUSHATTRS", 7 );
-
-/// current client-side command implementation versions
-define ( "VER_COMMAND_SEARCH", 0x119 );
-define ( "VER_COMMAND_EXCERPT", 0x104 );
-define ( "VER_COMMAND_UPDATE", 0x102 );
-define ( "VER_COMMAND_KEYWORDS", 0x100 );
-define ( "VER_COMMAND_STATUS", 0x100 );
-define ( "VER_COMMAND_QUERY", 0x100 );
-define ( "VER_COMMAND_FLUSHATTRS", 0x100 );
-
-/// known searchd status codes
-define ( "SEARCHD_OK", 0 );
-define ( "SEARCHD_ERROR", 1 );
-define ( "SEARCHD_RETRY", 2 );
-define ( "SEARCHD_WARNING", 3 );
-
-/// known match modes
-define ( "SPH_MATCH_ALL", 0 );
-define ( "SPH_MATCH_ANY", 1 );
-define ( "SPH_MATCH_PHRASE", 2 );
-define ( "SPH_MATCH_BOOLEAN", 3 );
-define ( "SPH_MATCH_EXTENDED", 4 );
-define ( "SPH_MATCH_FULLSCAN", 5 );
-define ( "SPH_MATCH_EXTENDED2", 6 ); // extended engine V2 (TEMPORARY, WILL BE REMOVED)
-
-/// known ranking modes (ext2 only)
-define ( "SPH_RANK_PROXIMITY_BM25", 0 ); ///< default mode, phrase proximity major factor and BM25 minor one
-define ( "SPH_RANK_BM25", 1 ); ///< statistical mode, BM25 ranking only (faster but worse quality)
-define ( "SPH_RANK_NONE", 2 ); ///< no ranking, all matches get a weight of 1
-define ( "SPH_RANK_WORDCOUNT", 3 ); ///< simple word-count weighting, rank is a weighted sum of per-field keyword occurence counts
-define ( "SPH_RANK_PROXIMITY", 4 );
-define ( "SPH_RANK_MATCHANY", 5 );
-define ( "SPH_RANK_FIELDMASK", 6 );
-define ( "SPH_RANK_SPH04", 7 );
-define ( "SPH_RANK_EXPR", 8 );
-define ( "SPH_RANK_TOTAL", 9 );
-
-/// known sort modes
-define ( "SPH_SORT_RELEVANCE", 0 );
-define ( "SPH_SORT_ATTR_DESC", 1 );
-define ( "SPH_SORT_ATTR_ASC", 2 );
-define ( "SPH_SORT_TIME_SEGMENTS", 3 );
-define ( "SPH_SORT_EXTENDED", 4 );
-define ( "SPH_SORT_EXPR", 5 );
-
-/// known filter types
-define ( "SPH_FILTER_VALUES", 0 );
-define ( "SPH_FILTER_RANGE", 1 );
-define ( "SPH_FILTER_FLOATRANGE", 2 );
-
-/// known attribute types
-define ( "SPH_ATTR_INTEGER", 1 );
-define ( "SPH_ATTR_TIMESTAMP", 2 );
-define ( "SPH_ATTR_ORDINAL", 3 );
-define ( "SPH_ATTR_BOOL", 4 );
-define ( "SPH_ATTR_FLOAT", 5 );
-define ( "SPH_ATTR_BIGINT", 6 );
-define ( "SPH_ATTR_STRING", 7 );
-define ( "SPH_ATTR_MULTI", 0x40000001 );
-define ( "SPH_ATTR_MULTI64", 0x40000002 );
-
-/// known grouping functions
-define ( "SPH_GROUPBY_DAY", 0 );
-define ( "SPH_GROUPBY_WEEK", 1 );
-define ( "SPH_GROUPBY_MONTH", 2 );
-define ( "SPH_GROUPBY_YEAR", 3 );
-define ( "SPH_GROUPBY_ATTR", 4 );
-define ( "SPH_GROUPBY_ATTRPAIR", 5 );
-
-// important properties of PHP's integers:
-// - always signed (one bit short of PHP_INT_SIZE)
-// - conversion from string to int is saturated
-// - float is double
-// - div converts arguments to floats
-// - mod converts arguments to ints
-
-// the packing code below works as follows:
-// - when we got an int, just pack it
-// if performance is a problem, this is the branch users should aim for
-//
-// - otherwise, we got a number in string form
-// this might be due to different reasons, but we assume that this is
-// because it didn't fit into PHP int
-//
-// - factor the string into high and low ints for packing
-// - if we have bcmath, then it is used
-// - if we don't, we have to do it manually (this is the fun part)
-//
-// - x64 branch does factoring using ints
-// - x32 (ab)uses floats, since we can't fit unsigned 32-bit number into an int
-//
-// unpacking routines are pretty much the same.
-// - return ints if we can
-// - otherwise format number into a string
-
-/// pack 64-bit signed
-function sphPackI64 ( $v )
-{
- assert ( is_numeric($v) );
-
- // x64
- if ( PHP_INT_SIZE>=8 )
- {
- $v = (int)$v;
- return pack ( "NN", $v>>32, $v&0xFFFFFFFF );
- }
-
- // x32, int
- if ( is_int($v) )
- return pack ( "NN", $v < 0 ? -1 : 0, $v );
-
- // x32, bcmath
- if ( function_exists("bcmul") )
- {
- if ( bccomp ( $v, 0 ) == -1 )
- $v = bcadd ( "18446744073709551616", $v );
- $h = bcdiv ( $v, "4294967296", 0 );
- $l = bcmod ( $v, "4294967296" );
- return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit
- }
-
- // x32, no-bcmath
- $p = max(0, strlen($v) - 13);
- $lo = abs((float)substr($v, $p));
- $hi = abs((float)substr($v, 0, $p));
-
- $m = $lo + $hi*1316134912.0; // (10 ^ 13) % (1 << 32) = 1316134912
- $q = floor($m/4294967296.0);
- $l = $m - ($q*4294967296.0);
- $h = $hi*2328.0 + $q; // (10 ^ 13) / (1 << 32) = 2328
-
- if ( $v<0 )
- {
- if ( $l==0 )
- $h = 4294967296.0 - $h;
- else
- {
- $h = 4294967295.0 - $h;
- $l = 4294967296.0 - $l;
- }
- }
- return pack ( "NN", $h, $l );
-}
-
-/// pack 64-bit unsigned
-function sphPackU64 ( $v )
-{
- assert ( is_numeric($v) );
-
- // x64
- if ( PHP_INT_SIZE>=8 )
- {
- assert ( $v>=0 );
-
- // x64, int
- if ( is_int($v) )
- return pack ( "NN", $v>>32, $v&0xFFFFFFFF );
-
- // x64, bcmath
- if ( function_exists("bcmul") )
- {
- $h = bcdiv ( $v, 4294967296, 0 );
- $l = bcmod ( $v, 4294967296 );
- return pack ( "NN", $h, $l );
- }
-
- // x64, no-bcmath
- $p = max ( 0, strlen($v) - 13 );
- $lo = (int)substr ( $v, $p );
- $hi = (int)substr ( $v, 0, $p );
-
- $m = $lo + $hi*1316134912;
- $l = $m % 4294967296;
- $h = $hi*2328 + (int)($m/4294967296);
-
- return pack ( "NN", $h, $l );
- }
-
- // x32, int
- if ( is_int($v) )
- return pack ( "NN", 0, $v );
-
- // x32, bcmath
- if ( function_exists("bcmul") )
- {
- $h = bcdiv ( $v, "4294967296", 0 );
- $l = bcmod ( $v, "4294967296" );
- return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit
- }
-
- // x32, no-bcmath
- $p = max(0, strlen($v) - 13);
- $lo = (float)substr($v, $p);
- $hi = (float)substr($v, 0, $p);
-
- $m = $lo + $hi*1316134912.0;
- $q = floor($m / 4294967296.0);
- $l = $m - ($q * 4294967296.0);
- $h = $hi*2328.0 + $q;
-
- return pack ( "NN", $h, $l );
-}
-
-// unpack 64-bit unsigned
-function sphUnpackU64 ( $v )
-{
- list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) );
-
- if ( PHP_INT_SIZE>=8 )
- {
- if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again
- if ( $lo<0 ) $lo += (1<<32);
-
- // x64, int
- if ( $hi<=2147483647 )
- return ($hi<<32) + $lo;
-
- // x64, bcmath
- if ( function_exists("bcmul") )
- return bcadd ( $lo, bcmul ( $hi, "4294967296" ) );
-
- // x64, no-bcmath
- $C = 100000;
- $h = ((int)($hi / $C) << 32) + (int)($lo / $C);
- $l = (($hi % $C) << 32) + ($lo % $C);
- if ( $l>$C )
- {
- $h += (int)($l / $C);
- $l = $l % $C;
- }
-
- if ( $h==0 )
- return $l;
- return sprintf ( "%d%05d", $h, $l );
- }
-
- // x32, int
- if ( $hi==0 )
- {
- if ( $lo>0 )
- return $lo;
- return sprintf ( "%u", $lo );
- }
-
- $hi = sprintf ( "%u", $hi );
- $lo = sprintf ( "%u", $lo );
-
- // x32, bcmath
- if ( function_exists("bcmul") )
- return bcadd ( $lo, bcmul ( $hi, "4294967296" ) );
-
- // x32, no-bcmath
- $hi = (float)$hi;
- $lo = (float)$lo;
-
- $q = floor($hi/10000000.0);
- $r = $hi - $q*10000000.0;
- $m = $lo + $r*4967296.0;
- $mq = floor($m/10000000.0);
- $l = $m - $mq*10000000.0;
- $h = $q*4294967296.0 + $r*429.0 + $mq;
-
- $h = sprintf ( "%.0f", $h );
- $l = sprintf ( "%07.0f", $l );
- if ( $h=="0" )
- return sprintf( "%.0f", (float)$l );
- return $h . $l;
-}
-
-// unpack 64-bit signed
-function sphUnpackI64 ( $v )
-{
- list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) );
-
- // x64
- if ( PHP_INT_SIZE>=8 )
- {
- if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again
- if ( $lo<0 ) $lo += (1<<32);
-
- return ($hi<<32) + $lo;
- }
-
- // x32, int
- if ( $hi==0 )
- {
- if ( $lo>0 )
- return $lo;
- return sprintf ( "%u", $lo );
- }
- // x32, int
- elseif ( $hi==-1 )
- {
- if ( $lo<0 )
- return $lo;
- return sprintf ( "%.0f", $lo - 4294967296.0 );
- }
-
- $neg = "";
- $c = 0;
- if ( $hi<0 )
- {
- $hi = ~$hi;
- $lo = ~$lo;
- $c = 1;
- $neg = "-";
- }
-
- $hi = sprintf ( "%u", $hi );
- $lo = sprintf ( "%u", $lo );
-
- // x32, bcmath
- if ( function_exists("bcmul") )
- return $neg . bcadd ( bcadd ( $lo, bcmul ( $hi, "4294967296" ) ), $c );
-
- // x32, no-bcmath
- $hi = (float)$hi;
- $lo = (float)$lo;
-
- $q = floor($hi/10000000.0);
- $r = $hi - $q*10000000.0;
- $m = $lo + $r*4967296.0;
- $mq = floor($m/10000000.0);
- $l = $m - $mq*10000000.0 + $c;
- $h = $q*4294967296.0 + $r*429.0 + $mq;
- if ( $l==10000000 )
- {
- $l = 0;
- $h += 1;
- }
-
- $h = sprintf ( "%.0f", $h );
- $l = sprintf ( "%07.0f", $l );
- if ( $h=="0" )
- return $neg . sprintf( "%.0f", (float)$l );
- return $neg . $h . $l;
-}
-
-
-function sphFixUint ( $value )
-{
- if ( PHP_INT_SIZE>=8 )
- {
- // x64 route, workaround broken unpack() in 5.2.2+
- if ( $value<0 ) $value += (1<<32);
- return $value;
- }
- else
- {
- // x32 route, workaround php signed/unsigned braindamage
- return sprintf ( "%u", $value );
- }
-}
-
-
-/// sphinx searchd client class
-class SphinxClient
-{
- var $_host; ///< searchd host (default is "localhost")
- var $_port; ///< searchd port (default is 9312)
- var $_offset; ///< how many records to seek from result-set start (default is 0)
- var $_limit; ///< how many records to return from result-set starting at offset (default is 20)
- var $_mode; ///< query matching mode (default is SPH_MATCH_ALL)
- var $_weights; ///< per-field weights (default is 1 for all fields)
- var $_sort; ///< match sorting mode (default is SPH_SORT_RELEVANCE)
- var $_sortby; ///< attribute to sort by (defualt is "")
- var $_min_id; ///< min ID to match (default is 0, which means no limit)
- var $_max_id; ///< max ID to match (default is 0, which means no limit)
- var $_filters; ///< search filters
- var $_groupby; ///< group-by attribute name
- var $_groupfunc; ///< group-by function (to pre-process group-by attribute value with)
- var $_groupsort; ///< group-by sorting clause (to sort groups in result set with)
- var $_groupdistinct;///< group-by count-distinct attribute
- var $_maxmatches; ///< max matches to retrieve
- var $_cutoff; ///< cutoff to stop searching at (default is 0)
- var $_retrycount; ///< distributed retries count
- var $_retrydelay; ///< distributed retries delay
- var $_anchor; ///< geographical anchor point
- var $_indexweights; ///< per-index weights
- var $_ranker; ///< ranking mode (default is SPH_RANK_PROXIMITY_BM25)
- var $_rankexpr; ///< ranking mode expression (for SPH_RANK_EXPR)
- var $_maxquerytime; ///< max query time, milliseconds (default is 0, do not limit)
- var $_fieldweights; ///< per-field-name weights
- var $_overrides; ///< per-query attribute values overrides
- var $_select; ///< select-list (attributes or expressions, with optional aliases)
-
- var $_error; ///< last error message
- var $_warning; ///< last warning message
- var $_connerror; ///< connection error vs remote error flag
-
- var $_reqs; ///< requests array for multi-query
- var $_mbenc; ///< stored mbstring encoding
- var $_arrayresult; ///< whether $result["matches"] should be a hash or an array
- var $_timeout; ///< connect timeout
-
- /////////////////////////////////////////////////////////////////////////////
- // common stuff
- /////////////////////////////////////////////////////////////////////////////
-
- /// create a new client object and fill defaults
- function SphinxClient ()
- {
- // per-client-object settings
- $this->_host = "localhost";
- $this->_port = 9312;
- $this->_path = false;
- $this->_socket = false;
-
- // per-query settings
- $this->_offset = 0;
- $this->_limit = 20;
- $this->_mode = SPH_MATCH_ALL;
- $this->_weights = array ();
- $this->_sort = SPH_SORT_RELEVANCE;
- $this->_sortby = "";
- $this->_min_id = 0;
- $this->_max_id = 0;
- $this->_filters = array ();
- $this->_groupby = "";
- $this->_groupfunc = SPH_GROUPBY_DAY;
- $this->_groupsort = "@group desc";
- $this->_groupdistinct= "";
- $this->_maxmatches = 1000;
- $this->_cutoff = 0;
- $this->_retrycount = 0;
- $this->_retrydelay = 0;
- $this->_anchor = array ();
- $this->_indexweights= array ();
- $this->_ranker = SPH_RANK_PROXIMITY_BM25;
- $this->_rankexpr = "";
- $this->_maxquerytime= 0;
- $this->_fieldweights= array();
- $this->_overrides = array();
- $this->_select = "*";
-
- $this->_error = ""; // per-reply fields (for single-query case)
- $this->_warning = "";
- $this->_connerror = false;
-
- $this->_reqs = array (); // requests storage (for multi-query case)
- $this->_mbenc = "";
- $this->_arrayresult = false;
- $this->_timeout = 0;
- }
-
- function __destruct()
- {
- if ( $this->_socket !== false )
- fclose ( $this->_socket );
- }
-
- /// get last error message (string)
- function GetLastError ()
- {
- return $this->_error;
- }
-
- /// get last warning message (string)
- function GetLastWarning ()
- {
- return $this->_warning;
- }
-
- /// get last error flag (to tell network connection errors from searchd errors or broken responses)
- function IsConnectError()
- {
- return $this->_connerror;
- }
-
- /// set searchd host name (string) and port (integer)
- function SetServer ( $host, $port = 0 )
- {
- assert ( is_string($host) );
- if ( $host[0] == '/')
- {
- $this->_path = 'unix://' . $host;
- return;
- }
- if ( substr ( $host, 0, 7 )=="unix://" )
- {
- $this->_path = $host;
- return;
- }
-
- assert ( is_int($port) );
- $this->_host = $host;
- $this->_port = $port;
- $this->_path = '';
-
- }
-
- /// set server connection timeout (0 to remove)
- function SetConnectTimeout ( $timeout )
- {
- assert ( is_numeric($timeout) );
- $this->_timeout = $timeout;
- }
-
-
- function _Send ( $handle, $data, $length )
- {
- if ( feof($handle) || fwrite ( $handle, $data, $length ) !== $length )
- {
- $this->_error = 'connection unexpectedly closed (timed out?)';
- $this->_connerror = true;
- return false;
- }
- return true;
- }
-
- /////////////////////////////////////////////////////////////////////////////
-
- /// enter mbstring workaround mode
- function _MBPush ()
- {
- $this->_mbenc = "";
- if ( ini_get ( "mbstring.func_overload" ) & 2 )
- {
- $this->_mbenc = mb_internal_encoding();
- mb_internal_encoding ( "latin1" );
- }
- }
-
- /// leave mbstring workaround mode
- function _MBPop ()
- {
- if ( $this->_mbenc )
- mb_internal_encoding ( $this->_mbenc );
- }
-
- /// connect to searchd server
- function _Connect ()
- {
- if ( $this->_socket!==false )
- {
- // we are in persistent connection mode, so we have a socket
- // however, need to check whether it's still alive
- if ( !@feof ( $this->_socket ) )
- return $this->_socket;
-
- // force reopen
- $this->_socket = false;
- }
-
- $errno = 0;
- $errstr = "";
- $this->_connerror = false;
-
- if ( $this->_path )
- {
- $host = $this->_path;
- $port = 0;
- }
- else
- {
- $host = $this->_host;
- $port = $this->_port;
- }
-
- if ( $this->_timeout<=0 )
- $fp = @fsockopen ( $host, $port, $errno, $errstr );
- else
- $fp = @fsockopen ( $host, $port, $errno, $errstr, $this->_timeout );
-
- if ( !$fp )
- {
- if ( $this->_path )
- $location = $this->_path;
- else
- $location = "{$this->_host}:{$this->_port}";
-
- $errstr = trim ( $errstr );
- $this->_error = "connection to $location failed (errno=$errno, msg=$errstr)";
- $this->_connerror = true;
- return false;
- }
-
- // send my version
- // this is a subtle part. we must do it before (!) reading back from searchd.
- // because otherwise under some conditions (reported on FreeBSD for instance)
- // TCP stack could throttle write-write-read pattern because of Nagle.
- if ( !$this->_Send ( $fp, pack ( "N", 1 ), 4 ) )
- {
- fclose ( $fp );
- $this->_error = "failed to send client protocol version";
- return false;
- }
-
- // check version
- list(,$v) = unpack ( "N*", fread ( $fp, 4 ) );
- $v = (int)$v;
- if ( $v<1 )
- {
- fclose ( $fp );
- $this->_error = "expected searchd protocol version 1+, got version '$v'";
- return false;
- }
-
- return $fp;
- }
-
- /// get and check response packet from searchd server
- function _GetResponse ( $fp, $client_ver )
- {
- $response = "";
- $len = 0;
-
- $header = fread ( $fp, 8 );
- if ( strlen($header)==8 )
- {
- list ( $status, $ver, $len ) = array_values ( unpack ( "n2a/Nb", $header ) );
- $left = $len;
- while ( $left>0 && !feof($fp) )
- {
- $chunk = fread ( $fp, min ( 8192, $left ) );
- if ( $chunk )
- {
- $response .= $chunk;
- $left -= strlen($chunk);
- }
- }
- }
- if ( $this->_socket === false )
- fclose ( $fp );
-
- // check response
- $read = strlen ( $response );
- if ( !$response || $read!=$len )
- {
- $this->_error = $len
- ? "failed to read searchd response (status=$status, ver=$ver, len=$len, read=$read)"
- : "received zero-sized searchd response";
- return false;
- }
-
- // check status
- if ( $status==SEARCHD_WARNING )
- {
- list(,$wlen) = unpack ( "N*", substr ( $response, 0, 4 ) );
- $this->_warning = substr ( $response, 4, $wlen );
- return substr ( $response, 4+$wlen );
- }
- if ( $status==SEARCHD_ERROR )
- {
- $this->_error = "searchd error: " . substr ( $response, 4 );
- return false;
- }
- if ( $status==SEARCHD_RETRY )
- {
- $this->_error = "temporary searchd error: " . substr ( $response, 4 );
- return false;
- }
- if ( $status!=SEARCHD_OK )
- {
- $this->_error = "unknown status code '$status'";
- return false;
- }
-
- // check version
- if ( $ver<$client_ver )
- {
- $this->_warning = sprintf ( "searchd command v.%d.%d older than client's v.%d.%d, some options might not work",
- $ver>>8, $ver&0xff, $client_ver>>8, $client_ver&0xff );
- }
-
- return $response;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // searching
- /////////////////////////////////////////////////////////////////////////////
-
- /// set offset and count into result set,
- /// and optionally set max-matches and cutoff limits
- function SetLimits ( $offset, $limit, $max=0, $cutoff=0 )
- {
- assert ( is_int($offset) );
- assert ( is_int($limit) );
- assert ( $offset>=0 );
- assert ( $limit>0 );
- assert ( $max>=0 );
- $this->_offset = $offset;
- $this->_limit = $limit;
- if ( $max>0 )
- $this->_maxmatches = $max;
- if ( $cutoff>0 )
- $this->_cutoff = $cutoff;
- }
-
- /// set maximum query time, in milliseconds, per-index
- /// integer, 0 means "do not limit"
- function SetMaxQueryTime ( $max )
- {
- assert ( is_int($max) );
- assert ( $max>=0 );
- $this->_maxquerytime = $max;
- }
-
- /// set matching mode
- function SetMatchMode ( $mode )
- {
- assert ( $mode==SPH_MATCH_ALL
- || $mode==SPH_MATCH_ANY
- || $mode==SPH_MATCH_PHRASE
- || $mode==SPH_MATCH_BOOLEAN
- || $mode==SPH_MATCH_EXTENDED
- || $mode==SPH_MATCH_FULLSCAN
- || $mode==SPH_MATCH_EXTENDED2 );
- $this->_mode = $mode;
- }
-
- /// set ranking mode
- function SetRankingMode ( $ranker, $rankexpr="" )
- {
- assert ( $ranker>=0 && $ranker<SPH_RANK_TOTAL );
- assert ( is_string($rankexpr) );
- $this->_ranker = $ranker;
- $this->_rankexpr = $rankexpr;
- }
-
- /// set matches sorting mode
- function SetSortMode ( $mode, $sortby="" )
- {
- assert (
- $mode==SPH_SORT_RELEVANCE ||
- $mode==SPH_SORT_ATTR_DESC ||
- $mode==SPH_SORT_ATTR_ASC ||
- $mode==SPH_SORT_TIME_SEGMENTS ||
- $mode==SPH_SORT_EXTENDED ||
- $mode==SPH_SORT_EXPR );
- assert ( is_string($sortby) );
- assert ( $mode==SPH_SORT_RELEVANCE || strlen($sortby)>0 );
-
- $this->_sort = $mode;
- $this->_sortby = $sortby;
- }
-
- /// bind per-field weights by order
- /// DEPRECATED; use SetFieldWeights() instead
- function SetWeights ( $weights )
- {
- assert ( is_array($weights) );
- foreach ( $weights as $weight )
- assert ( is_int($weight) );
-
- $this->_weights = $weights;
- }
-
- /// bind per-field weights by name
- function SetFieldWeights ( $weights )
- {
- assert ( is_array($weights) );
- foreach ( $weights as $name=>$weight )
- {
- assert ( is_string($name) );
- assert ( is_int($weight) );
- }
- $this->_fieldweights = $weights;
- }
-
- /// bind per-index weights by name
- function SetIndexWeights ( $weights )
- {
- assert ( is_array($weights) );
- foreach ( $weights as $index=>$weight )
- {
- assert ( is_string($index) );
- assert ( is_int($weight) );
- }
- $this->_indexweights = $weights;
- }
-
- /// set IDs range to match
- /// only match records if document ID is beetwen $min and $max (inclusive)
- function SetIDRange ( $min, $max )
- {
- assert ( is_numeric($min) );
- assert ( is_numeric($max) );
- assert ( $min<=$max );
- $this->_min_id = $min;
- $this->_max_id = $max;
- }
-
- /// set values set filter
- /// only match records where $attribute value is in given set
- function SetFilter ( $attribute, $values, $exclude=false )
- {
- assert ( is_string($attribute) );
- assert ( is_array($values) );
- assert ( count($values) );
-
- if ( is_array($values) && count($values) )
- {
- foreach ( $values as $value )
- assert ( is_numeric($value) );
-
- $this->_filters[] = array ( "type"=>SPH_FILTER_VALUES, "attr"=>$attribute, "exclude"=>$exclude, "values"=>$values );
- }
- }
-
- /// set range filter
- /// only match records if $attribute value is beetwen $min and $max (inclusive)
- function SetFilterRange ( $attribute, $min, $max, $exclude=false )
- {
- assert ( is_string($attribute) );
- assert ( is_numeric($min) );
- assert ( is_numeric($max) );
- assert ( $min<=$max );
-
- $this->_filters[] = array ( "type"=>SPH_FILTER_RANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max );
- }
-
- /// set float range filter
- /// only match records if $attribute value is beetwen $min and $max (inclusive)
- function SetFilterFloatRange ( $attribute, $min, $max, $exclude=false )
- {
- assert ( is_string($attribute) );
- assert ( is_float($min) );
- assert ( is_float($max) );
- assert ( $min<=$max );
-
- $this->_filters[] = array ( "type"=>SPH_FILTER_FLOATRANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max );
- }
-
- /// setup anchor point for geosphere distance calculations
- /// required to use @geodist in filters and sorting
- /// latitude and longitude must be in radians
- function SetGeoAnchor ( $attrlat, $attrlong, $lat, $long )
- {
- assert ( is_string($attrlat) );
- assert ( is_string($attrlong) );
- assert ( is_float($lat) );
- assert ( is_float($long) );
-
- $this->_anchor = array ( "attrlat"=>$attrlat, "attrlong"=>$attrlong, "lat"=>$lat, "long"=>$long );
- }
-
- /// set grouping attribute and function
- function SetGroupBy ( $attribute, $func, $groupsort="@group desc" )
- {
- assert ( is_string($attribute) );
- assert ( is_string($groupsort) );
- assert ( $func==SPH_GROUPBY_DAY
- || $func==SPH_GROUPBY_WEEK
- || $func==SPH_GROUPBY_MONTH
- || $func==SPH_GROUPBY_YEAR
- || $func==SPH_GROUPBY_ATTR
- || $func==SPH_GROUPBY_ATTRPAIR );
-
- $this->_groupby = $attribute;
- $this->_groupfunc = $func;
- $this->_groupsort = $groupsort;
- }
-
- /// set count-distinct attribute for group-by queries
- function SetGroupDistinct ( $attribute )
- {
- assert ( is_string($attribute) );
- $this->_groupdistinct = $attribute;
- }
-
- /// set distributed retries count and delay
- function SetRetries ( $count, $delay=0 )
- {
- assert ( is_int($count) && $count>=0 );
- assert ( is_int($delay) && $delay>=0 );
- $this->_retrycount = $count;
- $this->_retrydelay = $delay;
- }
-
- /// set result set format (hash or array; hash by default)
- /// PHP specific; needed for group-by-MVA result sets that may contain duplicate IDs
- function SetArrayResult ( $arrayresult )
- {
- assert ( is_bool($arrayresult) );
- $this->_arrayresult = $arrayresult;
- }
-
- /// set attribute values override
- /// there can be only one override per attribute
- /// $values must be a hash that maps document IDs to attribute values
- function SetOverride ( $attrname, $attrtype, $values )
- {
- assert ( is_string ( $attrname ) );
- assert ( in_array ( $attrtype, array ( SPH_ATTR_INTEGER, SPH_ATTR_TIMESTAMP, SPH_ATTR_BOOL, SPH_ATTR_FLOAT, SPH_ATTR_BIGINT ) ) );
- assert ( is_array ( $values ) );
-
- $this->_overrides[$attrname] = array ( "attr"=>$attrname, "type"=>$attrtype, "values"=>$values );
- }
-
- /// set select-list (attributes or expressions), SQL-like syntax
- function SetSelect ( $select )
- {
- assert ( is_string ( $select ) );
- $this->_select = $select;
- }
-
- //////////////////////////////////////////////////////////////////////////////
-
- /// clear all filters (for multi-queries)
- function ResetFilters ()
- {
- $this->_filters = array();
- $this->_anchor = array();
- }
-
- /// clear groupby settings (for multi-queries)
- function ResetGroupBy ()
- {
- $this->_groupby = "";
- $this->_groupfunc = SPH_GROUPBY_DAY;
- $this->_groupsort = "@group desc";
- $this->_groupdistinct= "";
- }
-
- /// clear all attribute value overrides (for multi-queries)
- function ResetOverrides ()
- {
- $this->_overrides = array ();
- }
-
- //////////////////////////////////////////////////////////////////////////////
-
- /// connect to searchd server, run given search query through given indexes,
- /// and return the search results
- function Query ( $query, $index="*", $comment="" )
- {
- assert ( empty($this->_reqs) );
-
- $this->AddQuery ( $query, $index, $comment );
- $results = $this->RunQueries ();
- $this->_reqs = array (); // just in case it failed too early
-
- if ( !is_array($results) )
- return false; // probably network error; error message should be already filled
-
- $this->_error = $results[0]["error"];
- $this->_warning = $results[0]["warning"];
- if ( $results[0]["status"]==SEARCHD_ERROR )
- return false;
- else
- return $results[0];
- }
-
- /// helper to pack floats in network byte order
- function _PackFloat ( $f )
- {
- $t1 = pack ( "f", $f ); // machine order
- list(,$t2) = unpack ( "L*", $t1 ); // int in machine order
- return pack ( "N", $t2 );
- }
-
- /// add query to multi-query batch
- /// returns index into results array from RunQueries() call
- function AddQuery ( $query, $index="*", $comment="" )
- {
- // mbstring workaround
- $this->_MBPush ();
-
- // build request
- $req = pack ( "NNNN", $this->_offset, $this->_limit, $this->_mode, $this->_ranker );
- if ( $this->_ranker==SPH_RANK_EXPR )
- $req .= pack ( "N", strlen($this->_rankexpr) ) . $this->_rankexpr;
- $req .= pack ( "N", $this->_sort ); // (deprecated) sort mode
- $req .= pack ( "N", strlen($this->_sortby) ) . $this->_sortby;
- $req .= pack ( "N", strlen($query) ) . $query; // query itself
- $req .= pack ( "N", count($this->_weights) ); // weights
- foreach ( $this->_weights as $weight )
- $req .= pack ( "N", (int)$weight );
- $req .= pack ( "N", strlen($index) ) . $index; // indexes
- $req .= pack ( "N", 1 ); // id64 range marker
- $req .= sphPackU64 ( $this->_min_id ) . sphPackU64 ( $this->_max_id ); // id64 range
-
- // filters
- $req .= pack ( "N", count($this->_filters) );
- foreach ( $this->_filters as $filter )
- {
- $req .= pack ( "N", strlen($filter["attr"]) ) . $filter["attr"];
- $req .= pack ( "N", $filter["type"] );
- switch ( $filter["type"] )
- {
- case SPH_FILTER_VALUES:
- $req .= pack ( "N", count($filter["values"]) );
- foreach ( $filter["values"] as $value )
- $req .= sphPackI64 ( $value );
- break;
-
- case SPH_FILTER_RANGE:
- $req .= sphPackI64 ( $filter["min"] ) . sphPackI64 ( $filter["max"] );
- break;
-
- case SPH_FILTER_FLOATRANGE:
- $req .= $this->_PackFloat ( $filter["min"] ) . $this->_PackFloat ( $filter["max"] );
- break;
-
- default:
- assert ( 0 && "internal error: unhandled filter type" );
- }
- $req .= pack ( "N", $filter["exclude"] );
- }
-
- // group-by clause, max-matches count, group-sort clause, cutoff count
- $req .= pack ( "NN", $this->_groupfunc, strlen($this->_groupby) ) . $this->_groupby;
- $req .= pack ( "N", $this->_maxmatches );
- $req .= pack ( "N", strlen($this->_groupsort) ) . $this->_groupsort;
- $req .= pack ( "NNN", $this->_cutoff, $this->_retrycount, $this->_retrydelay );
- $req .= pack ( "N", strlen($this->_groupdistinct) ) . $this->_groupdistinct;
-
- // anchor point
- if ( empty($this->_anchor) )
- {
- $req .= pack ( "N", 0 );
- } else
- {
- $a =& $this->_anchor;
- $req .= pack ( "N", 1 );
- $req .= pack ( "N", strlen($a["attrlat"]) ) . $a["attrlat"];
- $req .= pack ( "N", strlen($a["attrlong"]) ) . $a["attrlong"];
- $req .= $this->_PackFloat ( $a["lat"] ) . $this->_PackFloat ( $a["long"] );
- }
-
- // per-index weights
- $req .= pack ( "N", count($this->_indexweights) );
- foreach ( $this->_indexweights as $idx=>$weight )
- $req .= pack ( "N", strlen($idx) ) . $idx . pack ( "N", $weight );
-
- // max query time
- $req .= pack ( "N", $this->_maxquerytime );
-
- // per-field weights
- $req .= pack ( "N", count($this->_fieldweights) );
- foreach ( $this->_fieldweights as $field=>$weight )
- $req .= pack ( "N", strlen($field) ) . $field . pack ( "N", $weight );
-
- // comment
- $req .= pack ( "N", strlen($comment) ) . $comment;
-
- // attribute overrides
- $req .= pack ( "N", count($this->_overrides) );
- foreach ( $this->_overrides as $key => $entry )
- {
- $req .= pack ( "N", strlen($entry["attr"]) ) . $entry["attr"];
- $req .= pack ( "NN", $entry["type"], count($entry["values"]) );
- foreach ( $entry["values"] as $id=>$val )
- {
- assert ( is_numeric($id) );
- assert ( is_numeric($val) );
-
- $req .= sphPackU64 ( $id );
- switch ( $entry["type"] )
- {
- case SPH_ATTR_FLOAT: $req .= $this->_PackFloat ( $val ); break;
- case SPH_ATTR_BIGINT: $req .= sphPackI64 ( $val ); break;
- default: $req .= pack ( "N", $val ); break;
- }
- }
- }
-
- // select-list
- $req .= pack ( "N", strlen($this->_select) ) . $this->_select;
-
- // mbstring workaround
- $this->_MBPop ();
-
- // store request to requests array
- $this->_reqs[] = $req;
- return count($this->_reqs)-1;
- }
-
- /// connect to searchd, run queries batch, and return an array of result sets
- function RunQueries ()
- {
- if ( empty($this->_reqs) )
- {
- $this->_error = "no queries defined, issue AddQuery() first";
- return false;
- }
-
- // mbstring workaround
- $this->_MBPush ();
-
- if (!( $fp = $this->_Connect() ))
- {
- $this->_MBPop ();
- return false;
- }
-
- // send query, get response
- $nreqs = count($this->_reqs);
- $req = join ( "", $this->_reqs );
- $len = 8+strlen($req);
- $req = pack ( "nnNNN", SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, 0, $nreqs ) . $req; // add header
-
- if ( !( $this->_Send ( $fp, $req, $len+8 ) ) ||
- !( $response = $this->_GetResponse ( $fp, VER_COMMAND_SEARCH ) ) )
- {
- $this->_MBPop ();
- return false;
- }
-
- // query sent ok; we can reset reqs now
- $this->_reqs = array ();
-
- // parse and return response
- return $this->_ParseSearchResponse ( $response, $nreqs );
- }
-
- /// parse and return search query (or queries) response
- function _ParseSearchResponse ( $response, $nreqs )
- {
- $p = 0; // current position
- $max = strlen($response); // max position for checks, to protect against broken responses
-
- $results = array ();
- for ( $ires=0; $ires<$nreqs && $p<$max; $ires++ )
- {
- $results[] = array();
- $result =& $results[$ires];
-
- $result["error"] = "";
- $result["warning"] = "";
-
- // extract status
- list(,$status) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- $result["status"] = $status;
- if ( $status!=SEARCHD_OK )
- {
- list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- $message = substr ( $response, $p, $len ); $p += $len;
-
- if ( $status==SEARCHD_WARNING )
- {
- $result["warning"] = $message;
- } else
- {
- $result["error"] = $message;
- continue;
- }
- }
-
- // read schema
- $fields = array ();
- $attrs = array ();
-
- list(,$nfields) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- while ( $nfields-->0 && $p<$max )
- {
- list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- $fields[] = substr ( $response, $p, $len ); $p += $len;
- }
- $result["fields"] = $fields;
-
- list(,$nattrs) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- while ( $nattrs-->0 && $p<$max )
- {
- list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- $attr = substr ( $response, $p, $len ); $p += $len;
- list(,$type) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- $attrs[$attr] = $type;
- }
- $result["attrs"] = $attrs;
-
- // read match count
- list(,$count) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- list(,$id64) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
-
- // read matches
- $idx = -1;
- while ( $count-->0 && $p<$max )
- {
- // index into result array
- $idx++;
-
- // parse document id and weight
- if ( $id64 )
- {
- $doc = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8;
- list(,$weight) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- }
- else
- {
- list ( $doc, $weight ) = array_values ( unpack ( "N*N*",
- substr ( $response, $p, 8 ) ) );
- $p += 8;
- $doc = sphFixUint($doc);
- }
- $weight = sprintf ( "%u", $weight );
-
- // create match entry
- if ( $this->_arrayresult )
- $result["matches"][$idx] = array ( "id"=>$doc, "weight"=>$weight );
- else
- $result["matches"][$doc]["weight"] = $weight;
-
- // parse and create attributes
- $attrvals = array ();
- foreach ( $attrs as $attr=>$type )
- {
- // handle 64bit ints
- if ( $type==SPH_ATTR_BIGINT )
- {
- $attrvals[$attr] = sphUnpackI64 ( substr ( $response, $p, 8 ) ); $p += 8;
- continue;
- }
-
- // handle floats
- if ( $type==SPH_ATTR_FLOAT )
- {
- list(,$uval) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- list(,$fval) = unpack ( "f*", pack ( "L", $uval ) );
- $attrvals[$attr] = $fval;
- continue;
- }
-
- // handle everything else as unsigned ints
- list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- if ( $type==SPH_ATTR_MULTI )
- {
- $attrvals[$attr] = array ();
- $nvalues = $val;
- while ( $nvalues-->0 && $p<$max )
- {
- list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- $attrvals[$attr][] = sphFixUint($val);
- }
- } else if ( $type==SPH_ATTR_MULTI64 )
- {
- $attrvals[$attr] = array ();
- $nvalues = $val;
- while ( $nvalues>0 && $p<$max )
- {
- $attrvals[$attr][] = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8;
- $nvalues -= 2;
- }
- } else if ( $type==SPH_ATTR_STRING )
- {
- $attrvals[$attr] = substr ( $response, $p, $val );
- $p += $val;
- } else
- {
- $attrvals[$attr] = sphFixUint($val);
- }
- }
-
- if ( $this->_arrayresult )
- $result["matches"][$idx]["attrs"] = $attrvals;
- else
- $result["matches"][$doc]["attrs"] = $attrvals;
- }
-
- list ( $total, $total_found, $msecs, $words ) =
- array_values ( unpack ( "N*N*N*N*", substr ( $response, $p, 16 ) ) );
- $result["total"] = sprintf ( "%u", $total );
- $result["total_found"] = sprintf ( "%u", $total_found );
- $result["time"] = sprintf ( "%.3f", $msecs/1000 );
- $p += 16;
-
- while ( $words-->0 && $p<$max )
- {
- list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- $word = substr ( $response, $p, $len ); $p += $len;
- list ( $docs, $hits ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8;
- $result["words"][$word] = array (
- "docs"=>sprintf ( "%u", $docs ),
- "hits"=>sprintf ( "%u", $hits ) );
- }
- }
-
- $this->_MBPop ();
- return $results;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // excerpts generation
- /////////////////////////////////////////////////////////////////////////////
-
- /// connect to searchd server, and generate exceprts (snippets)
- /// of given documents for given query. returns false on failure,
- /// an array of snippets on success
- function BuildExcerpts ( $docs, $index, $words, $opts=array() )
- {
- assert ( is_array($docs) );
- assert ( is_string($index) );
- assert ( is_string($words) );
- assert ( is_array($opts) );
-
- $this->_MBPush ();
-
- if (!( $fp = $this->_Connect() ))
- {
- $this->_MBPop();
- return false;
- }
-
- /////////////////
- // fixup options
- /////////////////
-
- if ( !isset($opts["before_match"]) ) $opts["before_match"] = "<b>";
- if ( !isset($opts["after_match"]) ) $opts["after_match"] = "</b>";
- if ( !isset($opts["chunk_separator"]) ) $opts["chunk_separator"] = " ... ";
- if ( !isset($opts["limit"]) ) $opts["limit"] = 256;
- if ( !isset($opts["limit_passages"]) ) $opts["limit_passages"] = 0;
- if ( !isset($opts["limit_words"]) ) $opts["limit_words"] = 0;
- if ( !isset($opts["around"]) ) $opts["around"] = 5;
- if ( !isset($opts["exact_phrase"]) ) $opts["exact_phrase"] = false;
- if ( !isset($opts["single_passage"]) ) $opts["single_passage"] = false;
- if ( !isset($opts["use_boundaries"]) ) $opts["use_boundaries"] = false;
- if ( !isset($opts["weight_order"]) ) $opts["weight_order"] = false;
- if ( !isset($opts["query_mode"]) ) $opts["query_mode"] = false;
- if ( !isset($opts["force_all_words"]) ) $opts["force_all_words"] = false;
- if ( !isset($opts["start_passage_id"]) ) $opts["start_passage_id"] = 1;
- if ( !isset($opts["load_files"]) ) $opts["load_files"] = false;
- if ( !isset($opts["html_strip_mode"]) ) $opts["html_strip_mode"] = "index";
- if ( !isset($opts["allow_empty"]) ) $opts["allow_empty"] = false;
- if ( !isset($opts["passage_boundary"]) ) $opts["passage_boundary"] = "none";
- if ( !isset($opts["emit_zones"]) ) $opts["emit_zones"] = false;
- if ( !isset($opts["load_files_scattered"]) ) $opts["load_files_scattered"] = false;
-
-
- /////////////////
- // build request
- /////////////////
-
- // v.1.2 req
- $flags = 1; // remove spaces
- if ( $opts["exact_phrase"] ) $flags |= 2;
- if ( $opts["single_passage"] ) $flags |= 4;
- if ( $opts["use_boundaries"] ) $flags |= 8;
- if ( $opts["weight_order"] ) $flags |= 16;
- if ( $opts["query_mode"] ) $flags |= 32;
- if ( $opts["force_all_words"] ) $flags |= 64;
- if ( $opts["load_files"] ) $flags |= 128;
- if ( $opts["allow_empty"] ) $flags |= 256;
- if ( $opts["emit_zones"] ) $flags |= 512;
- if ( $opts["load_files_scattered"] ) $flags |= 1024;
- $req = pack ( "NN", 0, $flags ); // mode=0, flags=$flags
- $req .= pack ( "N", strlen($index) ) . $index; // req index
- $req .= pack ( "N", strlen($words) ) . $words; // req words
-
- // options
- $req .= pack ( "N", strlen($opts["before_match"]) ) . $opts["before_match"];
- $req .= pack ( "N", strlen($opts["after_match"]) ) . $opts["after_match"];
- $req .= pack ( "N", strlen($opts["chunk_separator"]) ) . $opts["chunk_separator"];
- $req .= pack ( "NN", (int)$opts["limit"], (int)$opts["around"] );
- $req .= pack ( "NNN", (int)$opts["limit_passages"], (int)$opts["limit_words"], (int)$opts["start_passage_id"] ); // v.1.2
- $req .= pack ( "N", strlen($opts["html_strip_mode"]) ) . $opts["html_strip_mode"];
- $req .= pack ( "N", strlen($opts["passage_boundary"]) ) . $opts["passage_boundary"];
-
- // documents
- $req .= pack ( "N", count($docs) );
- foreach ( $docs as $doc )
- {
- assert ( is_string($doc) );
- $req .= pack ( "N", strlen($doc) ) . $doc;
- }
-
- ////////////////////////////
- // send query, get response
- ////////////////////////////
-
- $len = strlen($req);
- $req = pack ( "nnN", SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len ) . $req; // add header
- if ( !( $this->_Send ( $fp, $req, $len+8 ) ) ||
- !( $response = $this->_GetResponse ( $fp, VER_COMMAND_EXCERPT ) ) )
- {
- $this->_MBPop ();
- return false;
- }
-
- //////////////////
- // parse response
- //////////////////
-
- $pos = 0;
- $res = array ();
- $rlen = strlen($response);
- for ( $i=0; $i<count($docs); $i++ )
- {
- list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) );
- $pos += 4;
-
- if ( $pos+$len > $rlen )
- {
- $this->_error = "incomplete reply";
- $this->_MBPop ();
- return false;
- }
- $res[] = $len ? substr ( $response, $pos, $len ) : "";
- $pos += $len;
- }
-
- $this->_MBPop ();
- return $res;
- }
-
-
- /////////////////////////////////////////////////////////////////////////////
- // keyword generation
- /////////////////////////////////////////////////////////////////////////////
-
- /// connect to searchd server, and generate keyword list for a given query
- /// returns false on failure,
- /// an array of words on success
- function BuildKeywords ( $query, $index, $hits )
- {
- assert ( is_string($query) );
- assert ( is_string($index) );
- assert ( is_bool($hits) );
-
- $this->_MBPush ();
-
- if (!( $fp = $this->_Connect() ))
- {
- $this->_MBPop();
- return false;
- }
-
- /////////////////
- // build request
- /////////////////
-
- // v.1.0 req
- $req = pack ( "N", strlen($query) ) . $query; // req query
- $req .= pack ( "N", strlen($index) ) . $index; // req index
- $req .= pack ( "N", (int)$hits );
-
- ////////////////////////////
- // send query, get response
- ////////////////////////////
-
- $len = strlen($req);
- $req = pack ( "nnN", SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len ) . $req; // add header
- if ( !( $this->_Send ( $fp, $req, $len+8 ) ) ||
- !( $response = $this->_GetResponse ( $fp, VER_COMMAND_KEYWORDS ) ) )
- {
- $this->_MBPop ();
- return false;
- }
-
- //////////////////
- // parse response
- //////////////////
-
- $pos = 0;
- $res = array ();
- $rlen = strlen($response);
- list(,$nwords) = unpack ( "N*", substr ( $response, $pos, 4 ) );
- $pos += 4;
- for ( $i=0; $i<$nwords; $i++ )
- {
- list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4;
- $tokenized = $len ? substr ( $response, $pos, $len ) : "";
- $pos += $len;
-
- list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4;
- $normalized = $len ? substr ( $response, $pos, $len ) : "";
- $pos += $len;
-
- $res[] = array ( "tokenized"=>$tokenized, "normalized"=>$normalized );
-
- if ( $hits )
- {
- list($ndocs,$nhits) = array_values ( unpack ( "N*N*", substr ( $response, $pos, 8 ) ) );
- $pos += 8;
- $res [$i]["docs"] = $ndocs;
- $res [$i]["hits"] = $nhits;
- }
-
- if ( $pos > $rlen )
- {
- $this->_error = "incomplete reply";
- $this->_MBPop ();
- return false;
- }
- }
-
- $this->_MBPop ();
- return $res;
- }
-
- function EscapeString ( $string )
- {
- $from = array ( '\\', '(',')','|','-','!','@','~','"','&', '/', '^', '$', '=' );
- $to = array ( '\\\\', '\(','\)','\|','\-','\!','\@','\~','\"', '\&', '\/', '\^', '\$', '\=' );
-
- return str_replace ( $from, $to, $string );
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // attribute updates
- /////////////////////////////////////////////////////////////////////////////
-
- /// batch update given attributes in given rows in given indexes
- /// returns amount of updated documents (0 or more) on success, or -1 on failure
- function UpdateAttributes ( $index, $attrs, $values, $mva=false )
- {
- // verify everything
- assert ( is_string($index) );
- assert ( is_bool($mva) );
-
- assert ( is_array($attrs) );
- foreach ( $attrs as $attr )
- assert ( is_string($attr) );
-
- assert ( is_array($values) );
- foreach ( $values as $id=>$entry )
- {
- assert ( is_numeric($id) );
- assert ( is_array($entry) );
- assert ( count($entry)==count($attrs) );
- foreach ( $entry as $v )
- {
- if ( $mva )
- {
- assert ( is_array($v) );
- foreach ( $v as $vv )
- assert ( is_int($vv) );
- } else
- assert ( is_int($v) );
- }
- }
-
- // build request
- $this->_MBPush ();
- $req = pack ( "N", strlen($index) ) . $index;
-
- $req .= pack ( "N", count($attrs) );
- foreach ( $attrs as $attr )
- {
- $req .= pack ( "N", strlen($attr) ) . $attr;
- $req .= pack ( "N", $mva ? 1 : 0 );
- }
-
- $req .= pack ( "N", count($values) );
- foreach ( $values as $id=>$entry )
- {
- $req .= sphPackU64 ( $id );
- foreach ( $entry as $v )
- {
- $req .= pack ( "N", $mva ? count($v) : $v );
- if ( $mva )
- foreach ( $v as $vv )
- $req .= pack ( "N", $vv );
- }
- }
-
- // connect, send query, get response
- if (!( $fp = $this->_Connect() ))
- {
- $this->_MBPop ();
- return -1;
- }
-
- $len = strlen($req);
- $req = pack ( "nnN", SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len ) . $req; // add header
- if ( !$this->_Send ( $fp, $req, $len+8 ) )
- {
- $this->_MBPop ();
- return -1;
- }
-
- if (!( $response = $this->_GetResponse ( $fp, VER_COMMAND_UPDATE ) ))
- {
- $this->_MBPop ();
- return -1;
- }
-
- // parse response
- list(,$updated) = unpack ( "N*", substr ( $response, 0, 4 ) );
- $this->_MBPop ();
- return $updated;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // persistent connections
- /////////////////////////////////////////////////////////////////////////////
-
- function Open()
- {
- if ( $this->_socket !== false )
- {
- $this->_error = 'already connected';
- return false;
- }
- if ( !$fp = $this->_Connect() )
- return false;
-
- // command, command version = 0, body length = 4, body = 1
- $req = pack ( "nnNN", SEARCHD_COMMAND_PERSIST, 0, 4, 1 );
- if ( !$this->_Send ( $fp, $req, 12 ) )
- return false;
-
- $this->_socket = $fp;
- return true;
- }
-
- function Close()
- {
- if ( $this->_socket === false )
- {
- $this->_error = 'not connected';
- return false;
- }
-
- fclose ( $this->_socket );
- $this->_socket = false;
-
- return true;
- }
-
- //////////////////////////////////////////////////////////////////////////
- // status
- //////////////////////////////////////////////////////////////////////////
-
- function Status ()
- {
- $this->_MBPush ();
- if (!( $fp = $this->_Connect() ))
- {
- $this->_MBPop();
- return false;
- }
-
- $req = pack ( "nnNN", SEARCHD_COMMAND_STATUS, VER_COMMAND_STATUS, 4, 1 ); // len=4, body=1
- if ( !( $this->_Send ( $fp, $req, 12 ) ) ||
- !( $response = $this->_GetResponse ( $fp, VER_COMMAND_STATUS ) ) )
- {
- $this->_MBPop ();
- return false;
- }
-
- $res = substr ( $response, 4 ); // just ignore length, error handling, etc
- $p = 0;
- list ( $rows, $cols ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8;
-
- $res = array();
- for ( $i=0; $i<$rows; $i++ )
- for ( $j=0; $j<$cols; $j++ )
- {
- list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
- $res[$i][] = substr ( $response, $p, $len ); $p += $len;
- }
-
- $this->_MBPop ();
- return $res;
- }
-
- //////////////////////////////////////////////////////////////////////////
- // flush
- //////////////////////////////////////////////////////////////////////////
-
- function FlushAttributes ()
- {
- $this->_MBPush ();
- if (!( $fp = $this->_Connect() ))
- {
- $this->_MBPop();
- return -1;
- }
-
- $req = pack ( "nnN", SEARCHD_COMMAND_FLUSHATTRS, VER_COMMAND_FLUSHATTRS, 0 ); // len=0
- if ( !( $this->_Send ( $fp, $req, 8 ) ) ||
- !( $response = $this->_GetResponse ( $fp, VER_COMMAND_FLUSHATTRS ) ) )
- {
- $this->_MBPop ();
- return -1;
- }
-
- $tag = -1;
- if ( strlen($response)==4 )
- list(,$tag) = unpack ( "N*", $response );
- else
- $this->_error = "unexpected response length";
-
- $this->_MBPop ();
- return $tag;
- }
-}
-
-//
-// $Id: sphinxapi.php 3087 2012-01-30 23:07:35Z shodan $
-//
+<?php
+
+//
+// $Id: sphinxapi.php 3087 2012-01-30 23:07:35Z shodan $
+//
+
+//
+// Copyright (c) 2001-2012, Andrew Aksyonoff
+// Copyright (c) 2008-2012, Sphinx Technologies Inc
+// All rights reserved
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License. You should have
+// received a copy of the GPL license along with this program; if you
+// did not, you can find it at http://www.gnu.org/
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// PHP version of Sphinx searchd client (PHP API)
+/////////////////////////////////////////////////////////////////////////////
+
+/// known searchd commands
+define ( "SEARCHD_COMMAND_SEARCH", 0 );
+define ( "SEARCHD_COMMAND_EXCERPT", 1 );
+define ( "SEARCHD_COMMAND_UPDATE", 2 );
+define ( "SEARCHD_COMMAND_KEYWORDS", 3 );
+define ( "SEARCHD_COMMAND_PERSIST", 4 );
+define ( "SEARCHD_COMMAND_STATUS", 5 );
+define ( "SEARCHD_COMMAND_FLUSHATTRS", 7 );
+
+/// current client-side command implementation versions
+define ( "VER_COMMAND_SEARCH", 0x119 );
+define ( "VER_COMMAND_EXCERPT", 0x104 );
+define ( "VER_COMMAND_UPDATE", 0x102 );
+define ( "VER_COMMAND_KEYWORDS", 0x100 );
+define ( "VER_COMMAND_STATUS", 0x100 );
+define ( "VER_COMMAND_QUERY", 0x100 );
+define ( "VER_COMMAND_FLUSHATTRS", 0x100 );
+
+/// known searchd status codes
+define ( "SEARCHD_OK", 0 );
+define ( "SEARCHD_ERROR", 1 );
+define ( "SEARCHD_RETRY", 2 );
+define ( "SEARCHD_WARNING", 3 );
+
+/// known match modes
+define ( "SPH_MATCH_ALL", 0 );
+define ( "SPH_MATCH_ANY", 1 );
+define ( "SPH_MATCH_PHRASE", 2 );
+define ( "SPH_MATCH_BOOLEAN", 3 );
+define ( "SPH_MATCH_EXTENDED", 4 );
+define ( "SPH_MATCH_FULLSCAN", 5 );
+define ( "SPH_MATCH_EXTENDED2", 6 ); // extended engine V2 (TEMPORARY, WILL BE REMOVED)
+
+/// known ranking modes (ext2 only)
+define ( "SPH_RANK_PROXIMITY_BM25", 0 ); ///< default mode, phrase proximity major factor and BM25 minor one
+define ( "SPH_RANK_BM25", 1 ); ///< statistical mode, BM25 ranking only (faster but worse quality)
+define ( "SPH_RANK_NONE", 2 ); ///< no ranking, all matches get a weight of 1
+define ( "SPH_RANK_WORDCOUNT", 3 ); ///< simple word-count weighting, rank is a weighted sum of per-field keyword occurence counts
+define ( "SPH_RANK_PROXIMITY", 4 );
+define ( "SPH_RANK_MATCHANY", 5 );
+define ( "SPH_RANK_FIELDMASK", 6 );
+define ( "SPH_RANK_SPH04", 7 );
+define ( "SPH_RANK_EXPR", 8 );
+define ( "SPH_RANK_TOTAL", 9 );
+
+/// known sort modes
+define ( "SPH_SORT_RELEVANCE", 0 );
+define ( "SPH_SORT_ATTR_DESC", 1 );
+define ( "SPH_SORT_ATTR_ASC", 2 );
+define ( "SPH_SORT_TIME_SEGMENTS", 3 );
+define ( "SPH_SORT_EXTENDED", 4 );
+define ( "SPH_SORT_EXPR", 5 );
+
+/// known filter types
+define ( "SPH_FILTER_VALUES", 0 );
+define ( "SPH_FILTER_RANGE", 1 );
+define ( "SPH_FILTER_FLOATRANGE", 2 );
+
+/// known attribute types
+define ( "SPH_ATTR_INTEGER", 1 );
+define ( "SPH_ATTR_TIMESTAMP", 2 );
+define ( "SPH_ATTR_ORDINAL", 3 );
+define ( "SPH_ATTR_BOOL", 4 );
+define ( "SPH_ATTR_FLOAT", 5 );
+define ( "SPH_ATTR_BIGINT", 6 );
+define ( "SPH_ATTR_STRING", 7 );
+define ( "SPH_ATTR_MULTI", 0x40000001 );
+define ( "SPH_ATTR_MULTI64", 0x40000002 );
+
+/// known grouping functions
+define ( "SPH_GROUPBY_DAY", 0 );
+define ( "SPH_GROUPBY_WEEK", 1 );
+define ( "SPH_GROUPBY_MONTH", 2 );
+define ( "SPH_GROUPBY_YEAR", 3 );
+define ( "SPH_GROUPBY_ATTR", 4 );
+define ( "SPH_GROUPBY_ATTRPAIR", 5 );
+
+// important properties of PHP's integers:
+// - always signed (one bit short of PHP_INT_SIZE)
+// - conversion from string to int is saturated
+// - float is double
+// - div converts arguments to floats
+// - mod converts arguments to ints
+
+// the packing code below works as follows:
+// - when we got an int, just pack it
+// if performance is a problem, this is the branch users should aim for
+//
+// - otherwise, we got a number in string form
+// this might be due to different reasons, but we assume that this is
+// because it didn't fit into PHP int
+//
+// - factor the string into high and low ints for packing
+// - if we have bcmath, then it is used
+// - if we don't, we have to do it manually (this is the fun part)
+//
+// - x64 branch does factoring using ints
+// - x32 (ab)uses floats, since we can't fit unsigned 32-bit number into an int
+//
+// unpacking routines are pretty much the same.
+// - return ints if we can
+// - otherwise format number into a string
+
+/// pack 64-bit signed
+function sphPackI64 ( $v )
+{
+ assert ( is_numeric($v) );
+
+ // x64
+ if ( PHP_INT_SIZE>=8 )
+ {
+ $v = (int)$v;
+ return pack ( "NN", $v>>32, $v&0xFFFFFFFF );
+ }
+
+ // x32, int
+ if ( is_int($v) )
+ return pack ( "NN", $v < 0 ? -1 : 0, $v );
+
+ // x32, bcmath
+ if ( function_exists("bcmul") )
+ {
+ if ( bccomp ( $v, 0 ) == -1 )
+ $v = bcadd ( "18446744073709551616", $v );
+ $h = bcdiv ( $v, "4294967296", 0 );
+ $l = bcmod ( $v, "4294967296" );
+ return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit
+ }
+
+ // x32, no-bcmath
+ $p = max(0, strlen($v) - 13);
+ $lo = abs((float)substr($v, $p));
+ $hi = abs((float)substr($v, 0, $p));
+
+ $m = $lo + $hi*1316134912.0; // (10 ^ 13) % (1 << 32) = 1316134912
+ $q = floor($m/4294967296.0);
+ $l = $m - ($q*4294967296.0);
+ $h = $hi*2328.0 + $q; // (10 ^ 13) / (1 << 32) = 2328
+
+ if ( $v<0 )
+ {
+ if ( $l==0 )
+ $h = 4294967296.0 - $h;
+ else
+ {
+ $h = 4294967295.0 - $h;
+ $l = 4294967296.0 - $l;
+ }
+ }
+ return pack ( "NN", $h, $l );
+}
+
+/// pack 64-bit unsigned
+function sphPackU64 ( $v )
+{
+ assert ( is_numeric($v) );
+
+ // x64
+ if ( PHP_INT_SIZE>=8 )
+ {
+ assert ( $v>=0 );
+
+ // x64, int
+ if ( is_int($v) )
+ return pack ( "NN", $v>>32, $v&0xFFFFFFFF );
+
+ // x64, bcmath
+ if ( function_exists("bcmul") )
+ {
+ $h = bcdiv ( $v, 4294967296, 0 );
+ $l = bcmod ( $v, 4294967296 );
+ return pack ( "NN", $h, $l );
+ }
+
+ // x64, no-bcmath
+ $p = max ( 0, strlen($v) - 13 );
+ $lo = (int)substr ( $v, $p );
+ $hi = (int)substr ( $v, 0, $p );
+
+ $m = $lo + $hi*1316134912;
+ $l = $m % 4294967296;
+ $h = $hi*2328 + (int)($m/4294967296);
+
+ return pack ( "NN", $h, $l );
+ }
+
+ // x32, int
+ if ( is_int($v) )
+ return pack ( "NN", 0, $v );
+
+ // x32, bcmath
+ if ( function_exists("bcmul") )
+ {
+ $h = bcdiv ( $v, "4294967296", 0 );
+ $l = bcmod ( $v, "4294967296" );
+ return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit
+ }
+
+ // x32, no-bcmath
+ $p = max(0, strlen($v) - 13);
+ $lo = (float)substr($v, $p);
+ $hi = (float)substr($v, 0, $p);
+
+ $m = $lo + $hi*1316134912.0;
+ $q = floor($m / 4294967296.0);
+ $l = $m - ($q * 4294967296.0);
+ $h = $hi*2328.0 + $q;
+
+ return pack ( "NN", $h, $l );
+}
+
+// unpack 64-bit unsigned
+function sphUnpackU64 ( $v )
+{
+ list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) );
+
+ if ( PHP_INT_SIZE>=8 )
+ {
+ if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again
+ if ( $lo<0 ) $lo += (1<<32);
+
+ // x64, int
+ if ( $hi<=2147483647 )
+ return ($hi<<32) + $lo;
+
+ // x64, bcmath
+ if ( function_exists("bcmul") )
+ return bcadd ( $lo, bcmul ( $hi, "4294967296" ) );
+
+ // x64, no-bcmath
+ $C = 100000;
+ $h = ((int)($hi / $C) << 32) + (int)($lo / $C);
+ $l = (($hi % $C) << 32) + ($lo % $C);
+ if ( $l>$C )
+ {
+ $h += (int)($l / $C);
+ $l = $l % $C;
+ }
+
+ if ( $h==0 )
+ return $l;
+ return sprintf ( "%d%05d", $h, $l );
+ }
+
+ // x32, int
+ if ( $hi==0 )
+ {
+ if ( $lo>0 )
+ return $lo;
+ return sprintf ( "%u", $lo );
+ }
+
+ $hi = sprintf ( "%u", $hi );
+ $lo = sprintf ( "%u", $lo );
+
+ // x32, bcmath
+ if ( function_exists("bcmul") )
+ return bcadd ( $lo, bcmul ( $hi, "4294967296" ) );
+
+ // x32, no-bcmath
+ $hi = (float)$hi;
+ $lo = (float)$lo;
+
+ $q = floor($hi/10000000.0);
+ $r = $hi - $q*10000000.0;
+ $m = $lo + $r*4967296.0;
+ $mq = floor($m/10000000.0);
+ $l = $m - $mq*10000000.0;
+ $h = $q*4294967296.0 + $r*429.0 + $mq;
+
+ $h = sprintf ( "%.0f", $h );
+ $l = sprintf ( "%07.0f", $l );
+ if ( $h=="0" )
+ return sprintf( "%.0f", (float)$l );
+ return $h . $l;
+}
+
+// unpack 64-bit signed
+function sphUnpackI64 ( $v )
+{
+ list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) );
+
+ // x64
+ if ( PHP_INT_SIZE>=8 )
+ {
+ if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again
+ if ( $lo<0 ) $lo += (1<<32);
+
+ return ($hi<<32) + $lo;
+ }
+
+ // x32, int
+ if ( $hi==0 )
+ {
+ if ( $lo>0 )
+ return $lo;
+ return sprintf ( "%u", $lo );
+ }
+ // x32, int
+ elseif ( $hi==-1 )
+ {
+ if ( $lo<0 )
+ return $lo;
+ return sprintf ( "%.0f", $lo - 4294967296.0 );
+ }
+
+ $neg = "";
+ $c = 0;
+ if ( $hi<0 )
+ {
+ $hi = ~$hi;
+ $lo = ~$lo;
+ $c = 1;
+ $neg = "-";
+ }
+
+ $hi = sprintf ( "%u", $hi );
+ $lo = sprintf ( "%u", $lo );
+
+ // x32, bcmath
+ if ( function_exists("bcmul") )
+ return $neg . bcadd ( bcadd ( $lo, bcmul ( $hi, "4294967296" ) ), $c );
+
+ // x32, no-bcmath
+ $hi = (float)$hi;
+ $lo = (float)$lo;
+
+ $q = floor($hi/10000000.0);
+ $r = $hi - $q*10000000.0;
+ $m = $lo + $r*4967296.0;
+ $mq = floor($m/10000000.0);
+ $l = $m - $mq*10000000.0 + $c;
+ $h = $q*4294967296.0 + $r*429.0 + $mq;
+ if ( $l==10000000 )
+ {
+ $l = 0;
+ $h += 1;
+ }
+
+ $h = sprintf ( "%.0f", $h );
+ $l = sprintf ( "%07.0f", $l );
+ if ( $h=="0" )
+ return $neg . sprintf( "%.0f", (float)$l );
+ return $neg . $h . $l;
+}
+
+
+function sphFixUint ( $value )
+{
+ if ( PHP_INT_SIZE>=8 )
+ {
+ // x64 route, workaround broken unpack() in 5.2.2+
+ if ( $value<0 ) $value += (1<<32);
+ return $value;
+ }
+ else
+ {
+ // x32 route, workaround php signed/unsigned braindamage
+ return sprintf ( "%u", $value );
+ }
+}
+
+
+/// sphinx searchd client class
+class SphinxClient
+{
+ var $_host; ///< searchd host (default is "localhost")
+ var $_port; ///< searchd port (default is 9312)
+ var $_offset; ///< how many records to seek from result-set start (default is 0)
+ var $_limit; ///< how many records to return from result-set starting at offset (default is 20)
+ var $_mode; ///< query matching mode (default is SPH_MATCH_ALL)
+ var $_weights; ///< per-field weights (default is 1 for all fields)
+ var $_sort; ///< match sorting mode (default is SPH_SORT_RELEVANCE)
+ var $_sortby; ///< attribute to sort by (defualt is "")
+ var $_min_id; ///< min ID to match (default is 0, which means no limit)
+ var $_max_id; ///< max ID to match (default is 0, which means no limit)
+ var $_filters; ///< search filters
+ var $_groupby; ///< group-by attribute name
+ var $_groupfunc; ///< group-by function (to pre-process group-by attribute value with)
+ var $_groupsort; ///< group-by sorting clause (to sort groups in result set with)
+ var $_groupdistinct;///< group-by count-distinct attribute
+ var $_maxmatches; ///< max matches to retrieve
+ var $_cutoff; ///< cutoff to stop searching at (default is 0)
+ var $_retrycount; ///< distributed retries count
+ var $_retrydelay; ///< distributed retries delay
+ var $_anchor; ///< geographical anchor point
+ var $_indexweights; ///< per-index weights
+ var $_ranker; ///< ranking mode (default is SPH_RANK_PROXIMITY_BM25)
+ var $_rankexpr; ///< ranking mode expression (for SPH_RANK_EXPR)
+ var $_maxquerytime; ///< max query time, milliseconds (default is 0, do not limit)
+ var $_fieldweights; ///< per-field-name weights
+ var $_overrides; ///< per-query attribute values overrides
+ var $_select; ///< select-list (attributes or expressions, with optional aliases)
+
+ var $_error; ///< last error message
+ var $_warning; ///< last warning message
+ var $_connerror; ///< connection error vs remote error flag
+
+ var $_reqs; ///< requests array for multi-query
+ var $_mbenc; ///< stored mbstring encoding
+ var $_arrayresult; ///< whether $result["matches"] should be a hash or an array
+ var $_timeout; ///< connect timeout
+
+ /////////////////////////////////////////////////////////////////////////////
+ // common stuff
+ /////////////////////////////////////////////////////////////////////////////
+
+ /// create a new client object and fill defaults
+ function SphinxClient ()
+ {
+ // per-client-object settings
+ $this->_host = "localhost";
+ $this->_port = 9312;
+ $this->_path = false;
+ $this->_socket = false;
+
+ // per-query settings
+ $this->_offset = 0;
+ $this->_limit = 20;
+ $this->_mode = SPH_MATCH_ALL;
+ $this->_weights = array ();
+ $this->_sort = SPH_SORT_RELEVANCE;
+ $this->_sortby = "";
+ $this->_min_id = 0;
+ $this->_max_id = 0;
+ $this->_filters = array ();
+ $this->_groupby = "";
+ $this->_groupfunc = SPH_GROUPBY_DAY;
+ $this->_groupsort = "@group desc";
+ $this->_groupdistinct= "";
+ $this->_maxmatches = 1000;
+ $this->_cutoff = 0;
+ $this->_retrycount = 0;
+ $this->_retrydelay = 0;
+ $this->_anchor = array ();
+ $this->_indexweights= array ();
+ $this->_ranker = SPH_RANK_PROXIMITY_BM25;
+ $this->_rankexpr = "";
+ $this->_maxquerytime= 0;
+ $this->_fieldweights= array();
+ $this->_overrides = array();
+ $this->_select = "*";
+
+ $this->_error = ""; // per-reply fields (for single-query case)
+ $this->_warning = "";
+ $this->_connerror = false;
+
+ $this->_reqs = array (); // requests storage (for multi-query case)
+ $this->_mbenc = "";
+ $this->_arrayresult = false;
+ $this->_timeout = 0;
+ }
+
+ function __destruct()
+ {
+ if ( $this->_socket !== false )
+ fclose ( $this->_socket );
+ }
+
+ /// get last error message (string)
+ function GetLastError ()
+ {
+ return $this->_error;
+ }
+
+ /// get last warning message (string)
+ function GetLastWarning ()
+ {
+ return $this->_warning;
+ }
+
+ /// get last error flag (to tell network connection errors from searchd errors or broken responses)
+ function IsConnectError()
+ {
+ return $this->_connerror;
+ }
+
+ /// set searchd host name (string) and port (integer)
+ function SetServer ( $host, $port = 0 )
+ {
+ assert ( is_string($host) );
+ if ( $host[0] == '/')
+ {
+ $this->_path = 'unix://' . $host;
+ return;
+ }
+ if ( substr ( $host, 0, 7 )=="unix://" )
+ {
+ $this->_path = $host;
+ return;
+ }
+
+ assert ( is_int($port) );
+ $this->_host = $host;
+ $this->_port = $port;
+ $this->_path = '';
+
+ }
+
+ /// set server connection timeout (0 to remove)
+ function SetConnectTimeout ( $timeout )
+ {
+ assert ( is_numeric($timeout) );
+ $this->_timeout = $timeout;
+ }
+
+
+ function _Send ( $handle, $data, $length )
+ {
+ if ( feof($handle) || fwrite ( $handle, $data, $length ) !== $length )
+ {
+ $this->_error = 'connection unexpectedly closed (timed out?)';
+ $this->_connerror = true;
+ return false;
+ }
+ return true;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+
+ /// enter mbstring workaround mode
+ function _MBPush ()
+ {
+ $this->_mbenc = "";
+ if ( ini_get ( "mbstring.func_overload" ) & 2 )
+ {
+ $this->_mbenc = mb_internal_encoding();
+ mb_internal_encoding ( "latin1" );
+ }
+ }
+
+ /// leave mbstring workaround mode
+ function _MBPop ()
+ {
+ if ( $this->_mbenc )
+ mb_internal_encoding ( $this->_mbenc );
+ }
+
+ /// connect to searchd server
+ function _Connect ()
+ {
+ if ( $this->_socket!==false )
+ {
+ // we are in persistent connection mode, so we have a socket
+ // however, need to check whether it's still alive
+ if ( !@feof ( $this->_socket ) )
+ return $this->_socket;
+
+ // force reopen
+ $this->_socket = false;
+ }
+
+ $errno = 0;
+ $errstr = "";
+ $this->_connerror = false;
+
+ if ( $this->_path )
+ {
+ $host = $this->_path;
+ $port = 0;
+ }
+ else
+ {
+ $host = $this->_host;
+ $port = $this->_port;
+ }
+
+ if ( $this->_timeout<=0 )
+ $fp = @fsockopen ( $host, $port, $errno, $errstr );
+ else
+ $fp = @fsockopen ( $host, $port, $errno, $errstr, $this->_timeout );
+
+ if ( !$fp )
+ {
+ if ( $this->_path )
+ $location = $this->_path;
+ else
+ $location = "{$this->_host}:{$this->_port}";
+
+ $errstr = trim ( $errstr );
+ $this->_error = "connection to $location failed (errno=$errno, msg=$errstr)";
+ $this->_connerror = true;
+ return false;
+ }
+
+ // send my version
+ // this is a subtle part. we must do it before (!) reading back from searchd.
+ // because otherwise under some conditions (reported on FreeBSD for instance)
+ // TCP stack could throttle write-write-read pattern because of Nagle.
+ if ( !$this->_Send ( $fp, pack ( "N", 1 ), 4 ) )
+ {
+ fclose ( $fp );
+ $this->_error = "failed to send client protocol version";
+ return false;
+ }
+
+ // check version
+ list(,$v) = unpack ( "N*", fread ( $fp, 4 ) );
+ $v = (int)$v;
+ if ( $v<1 )
+ {
+ fclose ( $fp );
+ $this->_error = "expected searchd protocol version 1+, got version '$v'";
+ return false;
+ }
+
+ return $fp;
+ }
+
+ /// get and check response packet from searchd server
+ function _GetResponse ( $fp, $client_ver )
+ {
+ $response = "";
+ $len = 0;
+
+ $header = fread ( $fp, 8 );
+ if ( strlen($header)==8 )
+ {
+ list ( $status, $ver, $len ) = array_values ( unpack ( "n2a/Nb", $header ) );
+ $left = $len;
+ while ( $left>0 && !feof($fp) )
+ {
+ $chunk = fread ( $fp, min ( 8192, $left ) );
+ if ( $chunk )
+ {
+ $response .= $chunk;
+ $left -= strlen($chunk);
+ }
+ }
+ }
+ if ( $this->_socket === false )
+ fclose ( $fp );
+
+ // check response
+ $read = strlen ( $response );
+ if ( !$response || $read!=$len )
+ {
+ $this->_error = $len
+ ? "failed to read searchd response (status=$status, ver=$ver, len=$len, read=$read)"
+ : "received zero-sized searchd response";
+ return false;
+ }
+
+ // check status
+ if ( $status==SEARCHD_WARNING )
+ {
+ list(,$wlen) = unpack ( "N*", substr ( $response, 0, 4 ) );
+ $this->_warning = substr ( $response, 4, $wlen );
+ return substr ( $response, 4+$wlen );
+ }
+ if ( $status==SEARCHD_ERROR )
+ {
+ $this->_error = "searchd error: " . substr ( $response, 4 );
+ return false;
+ }
+ if ( $status==SEARCHD_RETRY )
+ {
+ $this->_error = "temporary searchd error: " . substr ( $response, 4 );
+ return false;
+ }
+ if ( $status!=SEARCHD_OK )
+ {
+ $this->_error = "unknown status code '$status'";
+ return false;
+ }
+
+ // check version
+ if ( $ver<$client_ver )
+ {
+ $this->_warning = sprintf ( "searchd command v.%d.%d older than client's v.%d.%d, some options might not work",
+ $ver>>8, $ver&0xff, $client_ver>>8, $client_ver&0xff );
+ }
+
+ return $response;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // searching
+ /////////////////////////////////////////////////////////////////////////////
+
+ /// set offset and count into result set,
+ /// and optionally set max-matches and cutoff limits
+ function SetLimits ( $offset, $limit, $max=0, $cutoff=0 )
+ {
+ assert ( is_int($offset) );
+ assert ( is_int($limit) );
+ assert ( $offset>=0 );
+ assert ( $limit>0 );
+ assert ( $max>=0 );
+ $this->_offset = $offset;
+ $this->_limit = $limit;
+ if ( $max>0 )
+ $this->_maxmatches = $max;
+ if ( $cutoff>0 )
+ $this->_cutoff = $cutoff;
+ }
+
+ /// set maximum query time, in milliseconds, per-index
+ /// integer, 0 means "do not limit"
+ function SetMaxQueryTime ( $max )
+ {
+ assert ( is_int($max) );
+ assert ( $max>=0 );
+ $this->_maxquerytime = $max;
+ }
+
+ /// set matching mode
+ function SetMatchMode ( $mode )
+ {
+ assert ( $mode==SPH_MATCH_ALL
+ || $mode==SPH_MATCH_ANY
+ || $mode==SPH_MATCH_PHRASE
+ || $mode==SPH_MATCH_BOOLEAN
+ || $mode==SPH_MATCH_EXTENDED
+ || $mode==SPH_MATCH_FULLSCAN
+ || $mode==SPH_MATCH_EXTENDED2 );
+ $this->_mode = $mode;
+ }
+
+ /// set ranking mode
+ function SetRankingMode ( $ranker, $rankexpr="" )
+ {
+ assert ( $ranker>=0 && $ranker<SPH_RANK_TOTAL );
+ assert ( is_string($rankexpr) );
+ $this->_ranker = $ranker;
+ $this->_rankexpr = $rankexpr;
+ }
+
+ /// set matches sorting mode
+ function SetSortMode ( $mode, $sortby="" )
+ {
+ assert (
+ $mode==SPH_SORT_RELEVANCE ||
+ $mode==SPH_SORT_ATTR_DESC ||
+ $mode==SPH_SORT_ATTR_ASC ||
+ $mode==SPH_SORT_TIME_SEGMENTS ||
+ $mode==SPH_SORT_EXTENDED ||
+ $mode==SPH_SORT_EXPR );
+ assert ( is_string($sortby) );
+ assert ( $mode==SPH_SORT_RELEVANCE || strlen($sortby)>0 );
+
+ $this->_sort = $mode;
+ $this->_sortby = $sortby;
+ }
+
+ /// bind per-field weights by order
+ /// DEPRECATED; use SetFieldWeights() instead
+ function SetWeights ( $weights )
+ {
+ assert ( is_array($weights) );
+ foreach ( $weights as $weight )
+ assert ( is_int($weight) );
+
+ $this->_weights = $weights;
+ }
+
+ /// bind per-field weights by name
+ function SetFieldWeights ( $weights )
+ {
+ assert ( is_array($weights) );
+ foreach ( $weights as $name=>$weight )
+ {
+ assert ( is_string($name) );
+ assert ( is_int($weight) );
+ }
+ $this->_fieldweights = $weights;
+ }
+
+ /// bind per-index weights by name
+ function SetIndexWeights ( $weights )
+ {
+ assert ( is_array($weights) );
+ foreach ( $weights as $index=>$weight )
+ {
+ assert ( is_string($index) );
+ assert ( is_int($weight) );
+ }
+ $this->_indexweights = $weights;
+ }
+
+ /// set IDs range to match
+ /// only match records if document ID is beetwen $min and $max (inclusive)
+ function SetIDRange ( $min, $max )
+ {
+ assert ( is_numeric($min) );
+ assert ( is_numeric($max) );
+ assert ( $min<=$max );
+ $this->_min_id = $min;
+ $this->_max_id = $max;
+ }
+
+ /// set values set filter
+ /// only match records where $attribute value is in given set
+ function SetFilter ( $attribute, $values, $exclude=false )
+ {
+ assert ( is_string($attribute) );
+ assert ( is_array($values) );
+ assert ( count($values) );
+
+ if ( is_array($values) && count($values) )
+ {
+ foreach ( $values as $value )
+ assert ( is_numeric($value) );
+
+ $this->_filters[] = array ( "type"=>SPH_FILTER_VALUES, "attr"=>$attribute, "exclude"=>$exclude, "values"=>$values );
+ }
+ }
+
+ /// set range filter
+ /// only match records if $attribute value is beetwen $min and $max (inclusive)
+ function SetFilterRange ( $attribute, $min, $max, $exclude=false )
+ {
+ assert ( is_string($attribute) );
+ assert ( is_numeric($min) );
+ assert ( is_numeric($max) );
+ assert ( $min<=$max );
+
+ $this->_filters[] = array ( "type"=>SPH_FILTER_RANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max );
+ }
+
+ /// set float range filter
+ /// only match records if $attribute value is beetwen $min and $max (inclusive)
+ function SetFilterFloatRange ( $attribute, $min, $max, $exclude=false )
+ {
+ assert ( is_string($attribute) );
+ assert ( is_float($min) );
+ assert ( is_float($max) );
+ assert ( $min<=$max );
+
+ $this->_filters[] = array ( "type"=>SPH_FILTER_FLOATRANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max );
+ }
+
+ /// setup anchor point for geosphere distance calculations
+ /// required to use @geodist in filters and sorting
+ /// latitude and longitude must be in radians
+ function SetGeoAnchor ( $attrlat, $attrlong, $lat, $long )
+ {
+ assert ( is_string($attrlat) );
+ assert ( is_string($attrlong) );
+ assert ( is_float($lat) );
+ assert ( is_float($long) );
+
+ $this->_anchor = array ( "attrlat"=>$attrlat, "attrlong"=>$attrlong, "lat"=>$lat, "long"=>$long );
+ }
+
+ /// set grouping attribute and function
+ function SetGroupBy ( $attribute, $func, $groupsort="@group desc" )
+ {
+ assert ( is_string($attribute) );
+ assert ( is_string($groupsort) );
+ assert ( $func==SPH_GROUPBY_DAY
+ || $func==SPH_GROUPBY_WEEK
+ || $func==SPH_GROUPBY_MONTH
+ || $func==SPH_GROUPBY_YEAR
+ || $func==SPH_GROUPBY_ATTR
+ || $func==SPH_GROUPBY_ATTRPAIR );
+
+ $this->_groupby = $attribute;
+ $this->_groupfunc = $func;
+ $this->_groupsort = $groupsort;
+ }
+
+ /// set count-distinct attribute for group-by queries
+ function SetGroupDistinct ( $attribute )
+ {
+ assert ( is_string($attribute) );
+ $this->_groupdistinct = $attribute;
+ }
+
+ /// set distributed retries count and delay
+ function SetRetries ( $count, $delay=0 )
+ {
+ assert ( is_int($count) && $count>=0 );
+ assert ( is_int($delay) && $delay>=0 );
+ $this->_retrycount = $count;
+ $this->_retrydelay = $delay;
+ }
+
+ /// set result set format (hash or array; hash by default)
+ /// PHP specific; needed for group-by-MVA result sets that may contain duplicate IDs
+ function SetArrayResult ( $arrayresult )
+ {
+ assert ( is_bool($arrayresult) );
+ $this->_arrayresult = $arrayresult;
+ }
+
+ /// set attribute values override
+ /// there can be only one override per attribute
+ /// $values must be a hash that maps document IDs to attribute values
+ function SetOverride ( $attrname, $attrtype, $values )
+ {
+ assert ( is_string ( $attrname ) );
+ assert ( in_array ( $attrtype, array ( SPH_ATTR_INTEGER, SPH_ATTR_TIMESTAMP, SPH_ATTR_BOOL, SPH_ATTR_FLOAT, SPH_ATTR_BIGINT ) ) );
+ assert ( is_array ( $values ) );
+
+ $this->_overrides[$attrname] = array ( "attr"=>$attrname, "type"=>$attrtype, "values"=>$values );
+ }
+
+ /// set select-list (attributes or expressions), SQL-like syntax
+ function SetSelect ( $select )
+ {
+ assert ( is_string ( $select ) );
+ $this->_select = $select;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /// clear all filters (for multi-queries)
+ function ResetFilters ()
+ {
+ $this->_filters = array();
+ $this->_anchor = array();
+ }
+
+ /// clear groupby settings (for multi-queries)
+ function ResetGroupBy ()
+ {
+ $this->_groupby = "";
+ $this->_groupfunc = SPH_GROUPBY_DAY;
+ $this->_groupsort = "@group desc";
+ $this->_groupdistinct= "";
+ }
+
+ /// clear all attribute value overrides (for multi-queries)
+ function ResetOverrides ()
+ {
+ $this->_overrides = array ();
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ /// connect to searchd server, run given search query through given indexes,
+ /// and return the search results
+ function Query ( $query, $index="*", $comment="" )
+ {
+ assert ( empty($this->_reqs) );
+
+ $this->AddQuery ( $query, $index, $comment );
+ $results = $this->RunQueries ();
+ $this->_reqs = array (); // just in case it failed too early
+
+ if ( !is_array($results) )
+ return false; // probably network error; error message should be already filled
+
+ $this->_error = $results[0]["error"];
+ $this->_warning = $results[0]["warning"];
+ if ( $results[0]["status"]==SEARCHD_ERROR )
+ return false;
+ else
+ return $results[0];
+ }
+
+ /// helper to pack floats in network byte order
+ function _PackFloat ( $f )
+ {
+ $t1 = pack ( "f", $f ); // machine order
+ list(,$t2) = unpack ( "L*", $t1 ); // int in machine order
+ return pack ( "N", $t2 );
+ }
+
+ /// add query to multi-query batch
+ /// returns index into results array from RunQueries() call
+ function AddQuery ( $query, $index="*", $comment="" )
+ {
+ // mbstring workaround
+ $this->_MBPush ();
+
+ // build request
+ $req = pack ( "NNNN", $this->_offset, $this->_limit, $this->_mode, $this->_ranker );
+ if ( $this->_ranker==SPH_RANK_EXPR )
+ $req .= pack ( "N", strlen($this->_rankexpr) ) . $this->_rankexpr;
+ $req .= pack ( "N", $this->_sort ); // (deprecated) sort mode
+ $req .= pack ( "N", strlen($this->_sortby) ) . $this->_sortby;
+ $req .= pack ( "N", strlen($query) ) . $query; // query itself
+ $req .= pack ( "N", count($this->_weights) ); // weights
+ foreach ( $this->_weights as $weight )
+ $req .= pack ( "N", (int)$weight );
+ $req .= pack ( "N", strlen($index) ) . $index; // indexes
+ $req .= pack ( "N", 1 ); // id64 range marker
+ $req .= sphPackU64 ( $this->_min_id ) . sphPackU64 ( $this->_max_id ); // id64 range
+
+ // filters
+ $req .= pack ( "N", count($this->_filters) );
+ foreach ( $this->_filters as $filter )
+ {
+ $req .= pack ( "N", strlen($filter["attr"]) ) . $filter["attr"];
+ $req .= pack ( "N", $filter["type"] );
+ switch ( $filter["type"] )
+ {
+ case SPH_FILTER_VALUES:
+ $req .= pack ( "N", count($filter["values"]) );
+ foreach ( $filter["values"] as $value )
+ $req .= sphPackI64 ( $value );
+ break;
+
+ case SPH_FILTER_RANGE:
+ $req .= sphPackI64 ( $filter["min"] ) . sphPackI64 ( $filter["max"] );
+ break;
+
+ case SPH_FILTER_FLOATRANGE:
+ $req .= $this->_PackFloat ( $filter["min"] ) . $this->_PackFloat ( $filter["max"] );
+ break;
+
+ default:
+ assert ( 0 && "internal error: unhandled filter type" );
+ }
+ $req .= pack ( "N", $filter["exclude"] );
+ }
+
+ // group-by clause, max-matches count, group-sort clause, cutoff count
+ $req .= pack ( "NN", $this->_groupfunc, strlen($this->_groupby) ) . $this->_groupby;
+ $req .= pack ( "N", $this->_maxmatches );
+ $req .= pack ( "N", strlen($this->_groupsort) ) . $this->_groupsort;
+ $req .= pack ( "NNN", $this->_cutoff, $this->_retrycount, $this->_retrydelay );
+ $req .= pack ( "N", strlen($this->_groupdistinct) ) . $this->_groupdistinct;
+
+ // anchor point
+ if ( empty($this->_anchor) )
+ {
+ $req .= pack ( "N", 0 );
+ } else
+ {
+ $a =& $this->_anchor;
+ $req .= pack ( "N", 1 );
+ $req .= pack ( "N", strlen($a["attrlat"]) ) . $a["attrlat"];
+ $req .= pack ( "N", strlen($a["attrlong"]) ) . $a["attrlong"];
+ $req .= $this->_PackFloat ( $a["lat"] ) . $this->_PackFloat ( $a["long"] );
+ }
+
+ // per-index weights
+ $req .= pack ( "N", count($this->_indexweights) );
+ foreach ( $this->_indexweights as $idx=>$weight )
+ $req .= pack ( "N", strlen($idx) ) . $idx . pack ( "N", $weight );
+
+ // max query time
+ $req .= pack ( "N", $this->_maxquerytime );
+
+ // per-field weights
+ $req .= pack ( "N", count($this->_fieldweights) );
+ foreach ( $this->_fieldweights as $field=>$weight )
+ $req .= pack ( "N", strlen($field) ) . $field . pack ( "N", $weight );
+
+ // comment
+ $req .= pack ( "N", strlen($comment) ) . $comment;
+
+ // attribute overrides
+ $req .= pack ( "N", count($this->_overrides) );
+ foreach ( $this->_overrides as $key => $entry )
+ {
+ $req .= pack ( "N", strlen($entry["attr"]) ) . $entry["attr"];
+ $req .= pack ( "NN", $entry["type"], count($entry["values"]) );
+ foreach ( $entry["values"] as $id=>$val )
+ {
+ assert ( is_numeric($id) );
+ assert ( is_numeric($val) );
+
+ $req .= sphPackU64 ( $id );
+ switch ( $entry["type"] )
+ {
+ case SPH_ATTR_FLOAT: $req .= $this->_PackFloat ( $val ); break;
+ case SPH_ATTR_BIGINT: $req .= sphPackI64 ( $val ); break;
+ default: $req .= pack ( "N", $val ); break;
+ }
+ }
+ }
+
+ // select-list
+ $req .= pack ( "N", strlen($this->_select) ) . $this->_select;
+
+ // mbstring workaround
+ $this->_MBPop ();
+
+ // store request to requests array
+ $this->_reqs[] = $req;
+ return count($this->_reqs)-1;
+ }
+
+ /// connect to searchd, run queries batch, and return an array of result sets
+ function RunQueries ()
+ {
+ if ( empty($this->_reqs) )
+ {
+ $this->_error = "no queries defined, issue AddQuery() first";
+ return false;
+ }
+
+ // mbstring workaround
+ $this->_MBPush ();
+
+ if (!( $fp = $this->_Connect() ))
+ {
+ $this->_MBPop ();
+ return false;
+ }
+
+ // send query, get response
+ $nreqs = count($this->_reqs);
+ $req = join ( "", $this->_reqs );
+ $len = 8+strlen($req);
+ $req = pack ( "nnNNN", SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, 0, $nreqs ) . $req; // add header
+
+ if ( !( $this->_Send ( $fp, $req, $len+8 ) ) ||
+ !( $response = $this->_GetResponse ( $fp, VER_COMMAND_SEARCH ) ) )
+ {
+ $this->_MBPop ();
+ return false;
+ }
+
+ // query sent ok; we can reset reqs now
+ $this->_reqs = array ();
+
+ // parse and return response
+ return $this->_ParseSearchResponse ( $response, $nreqs );
+ }
+
+ /// parse and return search query (or queries) response
+ function _ParseSearchResponse ( $response, $nreqs )
+ {
+ $p = 0; // current position
+ $max = strlen($response); // max position for checks, to protect against broken responses
+
+ $results = array ();
+ for ( $ires=0; $ires<$nreqs && $p<$max; $ires++ )
+ {
+ $results[] = array();
+ $result =& $results[$ires];
+
+ $result["error"] = "";
+ $result["warning"] = "";
+
+ // extract status
+ list(,$status) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ $result["status"] = $status;
+ if ( $status!=SEARCHD_OK )
+ {
+ list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ $message = substr ( $response, $p, $len ); $p += $len;
+
+ if ( $status==SEARCHD_WARNING )
+ {
+ $result["warning"] = $message;
+ } else
+ {
+ $result["error"] = $message;
+ continue;
+ }
+ }
+
+ // read schema
+ $fields = array ();
+ $attrs = array ();
+
+ list(,$nfields) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ while ( $nfields-->0 && $p<$max )
+ {
+ list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ $fields[] = substr ( $response, $p, $len ); $p += $len;
+ }
+ $result["fields"] = $fields;
+
+ list(,$nattrs) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ while ( $nattrs-->0 && $p<$max )
+ {
+ list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ $attr = substr ( $response, $p, $len ); $p += $len;
+ list(,$type) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ $attrs[$attr] = $type;
+ }
+ $result["attrs"] = $attrs;
+
+ // read match count
+ list(,$count) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ list(,$id64) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+
+ // read matches
+ $idx = -1;
+ while ( $count-->0 && $p<$max )
+ {
+ // index into result array
+ $idx++;
+
+ // parse document id and weight
+ if ( $id64 )
+ {
+ $doc = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8;
+ list(,$weight) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ }
+ else
+ {
+ list ( $doc, $weight ) = array_values ( unpack ( "N*N*",
+ substr ( $response, $p, 8 ) ) );
+ $p += 8;
+ $doc = sphFixUint($doc);
+ }
+ $weight = sprintf ( "%u", $weight );
+
+ // create match entry
+ if ( $this->_arrayresult )
+ $result["matches"][$idx] = array ( "id"=>$doc, "weight"=>$weight );
+ else
+ $result["matches"][$doc]["weight"] = $weight;
+
+ // parse and create attributes
+ $attrvals = array ();
+ foreach ( $attrs as $attr=>$type )
+ {
+ // handle 64bit ints
+ if ( $type==SPH_ATTR_BIGINT )
+ {
+ $attrvals[$attr] = sphUnpackI64 ( substr ( $response, $p, 8 ) ); $p += 8;
+ continue;
+ }
+
+ // handle floats
+ if ( $type==SPH_ATTR_FLOAT )
+ {
+ list(,$uval) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ list(,$fval) = unpack ( "f*", pack ( "L", $uval ) );
+ $attrvals[$attr] = $fval;
+ continue;
+ }
+
+ // handle everything else as unsigned ints
+ list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ if ( $type==SPH_ATTR_MULTI )
+ {
+ $attrvals[$attr] = array ();
+ $nvalues = $val;
+ while ( $nvalues-->0 && $p<$max )
+ {
+ list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ $attrvals[$attr][] = sphFixUint($val);
+ }
+ } else if ( $type==SPH_ATTR_MULTI64 )
+ {
+ $attrvals[$attr] = array ();
+ $nvalues = $val;
+ while ( $nvalues>0 && $p<$max )
+ {
+ $attrvals[$attr][] = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8;
+ $nvalues -= 2;
+ }
+ } else if ( $type==SPH_ATTR_STRING )
+ {
+ $attrvals[$attr] = substr ( $response, $p, $val );
+ $p += $val;
+ } else
+ {
+ $attrvals[$attr] = sphFixUint($val);
+ }
+ }
+
+ if ( $this->_arrayresult )
+ $result["matches"][$idx]["attrs"] = $attrvals;
+ else
+ $result["matches"][$doc]["attrs"] = $attrvals;
+ }
+
+ list ( $total, $total_found, $msecs, $words ) =
+ array_values ( unpack ( "N*N*N*N*", substr ( $response, $p, 16 ) ) );
+ $result["total"] = sprintf ( "%u", $total );
+ $result["total_found"] = sprintf ( "%u", $total_found );
+ $result["time"] = sprintf ( "%.3f", $msecs/1000 );
+ $p += 16;
+
+ while ( $words-->0 && $p<$max )
+ {
+ list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ $word = substr ( $response, $p, $len ); $p += $len;
+ list ( $docs, $hits ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8;
+ $result["words"][$word] = array (
+ "docs"=>sprintf ( "%u", $docs ),
+ "hits"=>sprintf ( "%u", $hits ) );
+ }
+ }
+
+ $this->_MBPop ();
+ return $results;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // excerpts generation
+ /////////////////////////////////////////////////////////////////////////////
+
+ /// connect to searchd server, and generate exceprts (snippets)
+ /// of given documents for given query. returns false on failure,
+ /// an array of snippets on success
+ function BuildExcerpts ( $docs, $index, $words, $opts=array() )
+ {
+ assert ( is_array($docs) );
+ assert ( is_string($index) );
+ assert ( is_string($words) );
+ assert ( is_array($opts) );
+
+ $this->_MBPush ();
+
+ if (!( $fp = $this->_Connect() ))
+ {
+ $this->_MBPop();
+ return false;
+ }
+
+ /////////////////
+ // fixup options
+ /////////////////
+
+ if ( !isset($opts["before_match"]) ) $opts["before_match"] = "<b>";
+ if ( !isset($opts["after_match"]) ) $opts["after_match"] = "</b>";
+ if ( !isset($opts["chunk_separator"]) ) $opts["chunk_separator"] = " ... ";
+ if ( !isset($opts["limit"]) ) $opts["limit"] = 256;
+ if ( !isset($opts["limit_passages"]) ) $opts["limit_passages"] = 0;
+ if ( !isset($opts["limit_words"]) ) $opts["limit_words"] = 0;
+ if ( !isset($opts["around"]) ) $opts["around"] = 5;
+ if ( !isset($opts["exact_phrase"]) ) $opts["exact_phrase"] = false;
+ if ( !isset($opts["single_passage"]) ) $opts["single_passage"] = false;
+ if ( !isset($opts["use_boundaries"]) ) $opts["use_boundaries"] = false;
+ if ( !isset($opts["weight_order"]) ) $opts["weight_order"] = false;
+ if ( !isset($opts["query_mode"]) ) $opts["query_mode"] = false;
+ if ( !isset($opts["force_all_words"]) ) $opts["force_all_words"] = false;
+ if ( !isset($opts["start_passage_id"]) ) $opts["start_passage_id"] = 1;
+ if ( !isset($opts["load_files"]) ) $opts["load_files"] = false;
+ if ( !isset($opts["html_strip_mode"]) ) $opts["html_strip_mode"] = "index";
+ if ( !isset($opts["allow_empty"]) ) $opts["allow_empty"] = false;
+ if ( !isset($opts["passage_boundary"]) ) $opts["passage_boundary"] = "none";
+ if ( !isset($opts["emit_zones"]) ) $opts["emit_zones"] = false;
+ if ( !isset($opts["load_files_scattered"]) ) $opts["load_files_scattered"] = false;
+
+
+ /////////////////
+ // build request
+ /////////////////
+
+ // v.1.2 req
+ $flags = 1; // remove spaces
+ if ( $opts["exact_phrase"] ) $flags |= 2;
+ if ( $opts["single_passage"] ) $flags |= 4;
+ if ( $opts["use_boundaries"] ) $flags |= 8;
+ if ( $opts["weight_order"] ) $flags |= 16;
+ if ( $opts["query_mode"] ) $flags |= 32;
+ if ( $opts["force_all_words"] ) $flags |= 64;
+ if ( $opts["load_files"] ) $flags |= 128;
+ if ( $opts["allow_empty"] ) $flags |= 256;
+ if ( $opts["emit_zones"] ) $flags |= 512;
+ if ( $opts["load_files_scattered"] ) $flags |= 1024;
+ $req = pack ( "NN", 0, $flags ); // mode=0, flags=$flags
+ $req .= pack ( "N", strlen($index) ) . $index; // req index
+ $req .= pack ( "N", strlen($words) ) . $words; // req words
+
+ // options
+ $req .= pack ( "N", strlen($opts["before_match"]) ) . $opts["before_match"];
+ $req .= pack ( "N", strlen($opts["after_match"]) ) . $opts["after_match"];
+ $req .= pack ( "N", strlen($opts["chunk_separator"]) ) . $opts["chunk_separator"];
+ $req .= pack ( "NN", (int)$opts["limit"], (int)$opts["around"] );
+ $req .= pack ( "NNN", (int)$opts["limit_passages"], (int)$opts["limit_words"], (int)$opts["start_passage_id"] ); // v.1.2
+ $req .= pack ( "N", strlen($opts["html_strip_mode"]) ) . $opts["html_strip_mode"];
+ $req .= pack ( "N", strlen($opts["passage_boundary"]) ) . $opts["passage_boundary"];
+
+ // documents
+ $req .= pack ( "N", count($docs) );
+ foreach ( $docs as $doc )
+ {
+ assert ( is_string($doc) );
+ $req .= pack ( "N", strlen($doc) ) . $doc;
+ }
+
+ ////////////////////////////
+ // send query, get response
+ ////////////////////////////
+
+ $len = strlen($req);
+ $req = pack ( "nnN", SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len ) . $req; // add header
+ if ( !( $this->_Send ( $fp, $req, $len+8 ) ) ||
+ !( $response = $this->_GetResponse ( $fp, VER_COMMAND_EXCERPT ) ) )
+ {
+ $this->_MBPop ();
+ return false;
+ }
+
+ //////////////////
+ // parse response
+ //////////////////
+
+ $pos = 0;
+ $res = array ();
+ $rlen = strlen($response);
+ for ( $i=0; $i<count($docs); $i++ )
+ {
+ list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) );
+ $pos += 4;
+
+ if ( $pos+$len > $rlen )
+ {
+ $this->_error = "incomplete reply";
+ $this->_MBPop ();
+ return false;
+ }
+ $res[] = $len ? substr ( $response, $pos, $len ) : "";
+ $pos += $len;
+ }
+
+ $this->_MBPop ();
+ return $res;
+ }
+
+
+ /////////////////////////////////////////////////////////////////////////////
+ // keyword generation
+ /////////////////////////////////////////////////////////////////////////////
+
+ /// connect to searchd server, and generate keyword list for a given query
+ /// returns false on failure,
+ /// an array of words on success
+ function BuildKeywords ( $query, $index, $hits )
+ {
+ assert ( is_string($query) );
+ assert ( is_string($index) );
+ assert ( is_bool($hits) );
+
+ $this->_MBPush ();
+
+ if (!( $fp = $this->_Connect() ))
+ {
+ $this->_MBPop();
+ return false;
+ }
+
+ /////////////////
+ // build request
+ /////////////////
+
+ // v.1.0 req
+ $req = pack ( "N", strlen($query) ) . $query; // req query
+ $req .= pack ( "N", strlen($index) ) . $index; // req index
+ $req .= pack ( "N", (int)$hits );
+
+ ////////////////////////////
+ // send query, get response
+ ////////////////////////////
+
+ $len = strlen($req);
+ $req = pack ( "nnN", SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len ) . $req; // add header
+ if ( !( $this->_Send ( $fp, $req, $len+8 ) ) ||
+ !( $response = $this->_GetResponse ( $fp, VER_COMMAND_KEYWORDS ) ) )
+ {
+ $this->_MBPop ();
+ return false;
+ }
+
+ //////////////////
+ // parse response
+ //////////////////
+
+ $pos = 0;
+ $res = array ();
+ $rlen = strlen($response);
+ list(,$nwords) = unpack ( "N*", substr ( $response, $pos, 4 ) );
+ $pos += 4;
+ for ( $i=0; $i<$nwords; $i++ )
+ {
+ list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4;
+ $tokenized = $len ? substr ( $response, $pos, $len ) : "";
+ $pos += $len;
+
+ list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4;
+ $normalized = $len ? substr ( $response, $pos, $len ) : "";
+ $pos += $len;
+
+ $res[] = array ( "tokenized"=>$tokenized, "normalized"=>$normalized );
+
+ if ( $hits )
+ {
+ list($ndocs,$nhits) = array_values ( unpack ( "N*N*", substr ( $response, $pos, 8 ) ) );
+ $pos += 8;
+ $res [$i]["docs"] = $ndocs;
+ $res [$i]["hits"] = $nhits;
+ }
+
+ if ( $pos > $rlen )
+ {
+ $this->_error = "incomplete reply";
+ $this->_MBPop ();
+ return false;
+ }
+ }
+
+ $this->_MBPop ();
+ return $res;
+ }
+
+ function EscapeString ( $string )
+ {
+ $from = array ( '\\', '(',')','|','-','!','@','~','"','&', '/', '^', '$', '=' );
+ $to = array ( '\\\\', '\(','\)','\|','\-','\!','\@','\~','\"', '\&', '\/', '\^', '\$', '\=' );
+
+ return str_replace ( $from, $to, $string );
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // attribute updates
+ /////////////////////////////////////////////////////////////////////////////
+
+ /// batch update given attributes in given rows in given indexes
+ /// returns amount of updated documents (0 or more) on success, or -1 on failure
+ function UpdateAttributes ( $index, $attrs, $values, $mva=false )
+ {
+ // verify everything
+ assert ( is_string($index) );
+ assert ( is_bool($mva) );
+
+ assert ( is_array($attrs) );
+ foreach ( $attrs as $attr )
+ assert ( is_string($attr) );
+
+ assert ( is_array($values) );
+ foreach ( $values as $id=>$entry )
+ {
+ assert ( is_numeric($id) );
+ assert ( is_array($entry) );
+ assert ( count($entry)==count($attrs) );
+ foreach ( $entry as $v )
+ {
+ if ( $mva )
+ {
+ assert ( is_array($v) );
+ foreach ( $v as $vv )
+ assert ( is_int($vv) );
+ } else
+ assert ( is_int($v) );
+ }
+ }
+
+ // build request
+ $this->_MBPush ();
+ $req = pack ( "N", strlen($index) ) . $index;
+
+ $req .= pack ( "N", count($attrs) );
+ foreach ( $attrs as $attr )
+ {
+ $req .= pack ( "N", strlen($attr) ) . $attr;
+ $req .= pack ( "N", $mva ? 1 : 0 );
+ }
+
+ $req .= pack ( "N", count($values) );
+ foreach ( $values as $id=>$entry )
+ {
+ $req .= sphPackU64 ( $id );
+ foreach ( $entry as $v )
+ {
+ $req .= pack ( "N", $mva ? count($v) : $v );
+ if ( $mva )
+ foreach ( $v as $vv )
+ $req .= pack ( "N", $vv );
+ }
+ }
+
+ // connect, send query, get response
+ if (!( $fp = $this->_Connect() ))
+ {
+ $this->_MBPop ();
+ return -1;
+ }
+
+ $len = strlen($req);
+ $req = pack ( "nnN", SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len ) . $req; // add header
+ if ( !$this->_Send ( $fp, $req, $len+8 ) )
+ {
+ $this->_MBPop ();
+ return -1;
+ }
+
+ if (!( $response = $this->_GetResponse ( $fp, VER_COMMAND_UPDATE ) ))
+ {
+ $this->_MBPop ();
+ return -1;
+ }
+
+ // parse response
+ list(,$updated) = unpack ( "N*", substr ( $response, 0, 4 ) );
+ $this->_MBPop ();
+ return $updated;
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+ // persistent connections
+ /////////////////////////////////////////////////////////////////////////////
+
+ function Open()
+ {
+ if ( $this->_socket !== false )
+ {
+ $this->_error = 'already connected';
+ return false;
+ }
+ if ( !$fp = $this->_Connect() )
+ return false;
+
+ // command, command version = 0, body length = 4, body = 1
+ $req = pack ( "nnNN", SEARCHD_COMMAND_PERSIST, 0, 4, 1 );
+ if ( !$this->_Send ( $fp, $req, 12 ) )
+ return false;
+
+ $this->_socket = $fp;
+ return true;
+ }
+
+ function Close()
+ {
+ if ( $this->_socket === false )
+ {
+ $this->_error = 'not connected';
+ return false;
+ }
+
+ fclose ( $this->_socket );
+ $this->_socket = false;
+
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // status
+ //////////////////////////////////////////////////////////////////////////
+
+ function Status ()
+ {
+ $this->_MBPush ();
+ if (!( $fp = $this->_Connect() ))
+ {
+ $this->_MBPop();
+ return false;
+ }
+
+ $req = pack ( "nnNN", SEARCHD_COMMAND_STATUS, VER_COMMAND_STATUS, 4, 1 ); // len=4, body=1
+ if ( !( $this->_Send ( $fp, $req, 12 ) ) ||
+ !( $response = $this->_GetResponse ( $fp, VER_COMMAND_STATUS ) ) )
+ {
+ $this->_MBPop ();
+ return false;
+ }
+
+ $res = substr ( $response, 4 ); // just ignore length, error handling, etc
+ $p = 0;
+ list ( $rows, $cols ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8;
+
+ $res = array();
+ for ( $i=0; $i<$rows; $i++ )
+ for ( $j=0; $j<$cols; $j++ )
+ {
+ list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4;
+ $res[$i][] = substr ( $response, $p, $len ); $p += $len;
+ }
+
+ $this->_MBPop ();
+ return $res;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // flush
+ //////////////////////////////////////////////////////////////////////////
+
+ function FlushAttributes ()
+ {
+ $this->_MBPush ();
+ if (!( $fp = $this->_Connect() ))
+ {
+ $this->_MBPop();
+ return -1;
+ }
+
+ $req = pack ( "nnN", SEARCHD_COMMAND_FLUSHATTRS, VER_COMMAND_FLUSHATTRS, 0 ); // len=0
+ if ( !( $this->_Send ( $fp, $req, 8 ) ) ||
+ !( $response = $this->_GetResponse ( $fp, VER_COMMAND_FLUSHATTRS ) ) )
+ {
+ $this->_MBPop ();
+ return -1;
+ }
+
+ $tag = -1;
+ if ( strlen($response)==4 )
+ list(,$tag) = unpack ( "N*", $response );
+ else
+ $this->_error = "unexpected response length";
+
+ $this->_MBPop ();
+ return $tag;
+ }
+}
+
+//
+// $Id: sphinxapi.php 3087 2012-01-30 23:07:35Z shodan $
+//
diff --git a/phpBB/includes/style/extension_path_provider.php b/phpBB/includes/style/extension_path_provider.php
deleted file mode 100644
index 4eac300424..0000000000
--- a/phpBB/includes/style/extension_path_provider.php
+++ /dev/null
@@ -1,119 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Provides a style resource locator with core style paths and extension style paths
-*
-* Finds installed style paths and makes them available to the resource locator.
-*
-* @package phpBB3
-*/
-class phpbb_style_extension_path_provider extends phpbb_extension_provider implements phpbb_style_path_provider_interface
-{
- /**
- * Optional prefix for style paths searched within extensions.
- *
- * Empty by default. Relative to the extension directory. As an example, it
- * could be adm/ for admin style.
- *
- * @var string
- */
- protected $ext_dir_prefix = '';
-
- /**
- * A provider of paths to be searched for styles
- * @var phpbb_style_path_provider
- */
- protected $base_path_provider;
-
- /**
- * Constructor stores extension manager
- *
- * @param phpbb_extension_manager $extension_manager phpBB extension manager
- * @param phpbb_style_path_provider $base_path_provider A simple path provider
- * to provide paths to be located in extensions
- */
- public function __construct(phpbb_extension_manager $extension_manager, phpbb_style_path_provider $base_path_provider)
- {
- parent::__construct($extension_manager);
- $this->base_path_provider = $base_path_provider;
- }
-
- /**
- * Sets a prefix for style paths searched within extensions.
- *
- * The prefix is inserted between the extension's path e.g. ext/foo/ and
- * the looked up style path, e.g. styles/bar/. So it should not have a
- * leading slash, but should have a trailing slash.
- *
- * @param string $ext_dir_prefix The prefix including trailing slash
- * @return null
- */
- public function set_ext_dir_prefix($ext_dir_prefix)
- {
- $this->ext_dir_prefix = $ext_dir_prefix;
- }
-
- /**
- * Finds style paths using the extension manager
- *
- * Locates a path (e.g. styles/prosilver/) in all active extensions.
- * Then appends the core style paths based in the current working
- * directory.
- *
- * @return array List of style paths
- */
- public function find()
- {
- $directories = array();
-
- $finder = $this->extension_manager->get_finder();
- foreach ($this->base_path_provider as $key => $paths)
- {
- if ($key == 'style')
- {
- foreach ($paths as $path)
- {
- $directories['style'][] = $path;
- if ($path && !phpbb_is_absolute($path))
- {
- $result = $finder->directory('/' . $this->ext_dir_prefix . $path)
- ->get_directories(true, true);
- foreach ($result as $ext => $ext_path)
- {
- $directories[$ext][] = $ext_path;
- }
- }
- }
- }
- }
-
- return $directories;
- }
-
- /**
- * Overwrites the current style paths
- *
- * @param array $styles An array of style paths. The first element is the main style.
- * @return null
- */
- public function set_styles(array $styles)
- {
- $this->base_path_provider->set_styles($styles);
- $this->items = null;
- }
-}
diff --git a/phpBB/includes/style/path_provider.php b/phpBB/includes/style/path_provider.php
deleted file mode 100644
index 731d682e88..0000000000
--- a/phpBB/includes/style/path_provider.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Provides a style resource locator with paths
-*
-* Finds installed style paths and makes them available to the resource locator.
-*
-* @package phpBB3
-*/
-class phpbb_style_path_provider implements IteratorAggregate, phpbb_style_path_provider_interface
-{
- protected $paths = array();
-
- /**
- * Ignores the extension dir prefix
- *
- * @param string $ext_dir_prefix The prefix including trailing slash
- * @return null
- */
- public function set_ext_dir_prefix($ext_dir_prefix)
- {
- }
-
- /**
- * Overwrites the current style paths
- *
- * The first element of the passed styles map, is considered the main
- * style.
- *
- * @param array $styles An array of style paths. The first element is the main style.
- * @return null
- */
- public function set_styles(array $styles)
- {
- $this->paths = array('style' => $styles);
- }
-
- /**
- * Retrieve an iterator over all style paths
- *
- * @return ArrayIterator An iterator for the array of style paths
- */
- public function getIterator()
- {
- return new ArrayIterator($this->paths);
- }
-}
diff --git a/phpBB/includes/style/path_provider_interface.php b/phpBB/includes/style/path_provider_interface.php
deleted file mode 100644
index 1a6153a4d3..0000000000
--- a/phpBB/includes/style/path_provider_interface.php
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Provides a style resource locator with paths
-*
-* Finds installed style paths and makes them available to the resource locator.
-*
-* @package phpBB3
-*/
-interface phpbb_style_path_provider_interface extends Traversable
-{
- /**
- * Defines a prefix to use for style paths in extensions
- *
- * @param string $ext_dir_prefix The prefix including trailing slash
- * @return null
- */
- public function set_ext_dir_prefix($ext_dir_prefix);
-
- /**
- * Overwrites the current style paths
- *
- * @param array $styles An array of style paths. The first element is the main style.
- * @return null
- */
- public function set_styles(array $styles);
-}
diff --git a/phpBB/includes/style/resource_locator.php b/phpBB/includes/style/resource_locator.php
deleted file mode 100644
index 4cf767c062..0000000000
--- a/phpBB/includes/style/resource_locator.php
+++ /dev/null
@@ -1,348 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-
-/**
-* Style resource locator.
-* Maintains mapping from template handles to source template file paths.
-* Locates style files: resources (such as .js and .css files) and templates.
-*
-* Style resource locator is aware of styles tree, and can return actual
-* filesystem paths (i.e., the "child" style or the "parent" styles)
-* depending on what files exist.
-*
-* Root paths stored in locator are paths to style directories. Templates are
-* stored in subdirectory that $template_path points to.
-*
-* @package phpBB3
-*/
-class phpbb_style_resource_locator implements phpbb_template_locator
-{
- /**
- * Paths to style directories.
- * @var array
- */
- private $roots = array();
-
- /**
- * Location of templates directory within style directories.
- * Must have trailing slash. Empty if templates are stored in root
- * style directory, such as admin control panel templates.
- * @var string
- */
- private $template_path;
-
- /**
- * Map from root index to handles to source template file paths.
- * Normally it only contains paths for handles that are used
- * (or are likely to be used) by the page being rendered and not
- * all templates that exist on the filesystem.
- * @var array
- */
- private $files = array();
-
- /**
- * Map from handles to source template file names.
- * Covers the same data as $files property but maps to basenames
- * instead of paths.
- * @var array
- */
- private $filenames = array();
-
- /**
- * Constructor.
- *
- * Sets default template path to template/.
- */
- public function __construct()
- {
- $this->set_default_template_path();
- }
-
- /**
- * Sets the list of style paths
- *
- * These paths will be searched for style files in the provided order.
- * Paths may be outside of phpBB, but templates loaded from these paths
- * will still be cached.
- *
- * @param array $style_paths An array of paths to style directories
- * @return null
- */
- public function set_paths($style_paths)
- {
- $this->roots = array();
- $this->files = array();
- $this->filenames = array();
-
- foreach ($style_paths as $key => $paths)
- {
- foreach ($paths as $path)
- {
- // Make sure $path has no ending slash
- if (substr($path, -1) === '/')
- {
- $path = substr($path, 0, -1);
- }
- $this->roots[$key][] = $path;
- }
- }
- }
-
- /**
- * Sets the location of templates directory within style directories.
- *
- * The location must be a relative path, with a trailing slash.
- * Typically it is one directory level deep, e.g. "template/".
- *
- * @param string $template_path Relative path to templates directory within style directories
- * @return null
- */
- public function set_template_path($template_path)
- {
- $this->template_path = $template_path;
- }
-
- /**
- * Sets the location of templates directory within style directories
- * to the default, which is "template/".
- *
- * @return null
- */
- public function set_default_template_path()
- {
- $this->template_path = 'template/';
- }
-
- /**
- * {@inheritDoc}
- */
- public function set_filenames(array $filename_array)
- {
- foreach ($filename_array as $handle => $filename)
- {
- if (empty($filename))
- {
- trigger_error("style resource locator: set_filenames: Empty filename specified for $handle", E_USER_ERROR);
- }
-
- $this->filename[$handle] = $filename;
-
- foreach ($this->roots as $root_key => $root_paths)
- {
- foreach ($root_paths as $root_index => $root)
- {
- $this->files[$root_key][$root_index][$handle] = $root . '/' . $this->template_path . $filename;
- }
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- public function get_filename_for_handle($handle)
- {
- if (!isset($this->filename[$handle]))
- {
- trigger_error("style resource locator: get_filename_for_handle: No file specified for handle $handle", E_USER_ERROR);
- }
- return $this->filename[$handle];
- }
-
- /**
- * {@inheritDoc}
- */
- public function get_virtual_source_file_for_handle($handle)
- {
- // If we don't have a file assigned to this handle, die.
- if (!isset($this->files['style'][0][$handle]))
- {
- trigger_error("style resource locator: No file specified for handle $handle", E_USER_ERROR);
- }
-
- $source_file = $this->files['style'][0][$handle];
- return $source_file;
- }
-
- /**
- * {@inheritDoc}
- */
- public function get_source_file_for_handle($handle, $find_all = false)
- {
- // If we don't have a file assigned to this handle, die.
- if (!isset($this->files['style'][0][$handle]))
- {
- trigger_error("style resource locator: No file specified for handle $handle", E_USER_ERROR);
- }
-
- // locate a source file that exists
- $source_file = $this->files['style'][0][$handle];
- $tried = $source_file;
- $found = false;
- $found_all = array();
- foreach ($this->roots as $root_key => $root_paths)
- {
- foreach ($root_paths as $root_index => $root)
- {
- $source_file = $this->files[$root_key][$root_index][$handle];
- $tried .= ', ' . $source_file;
- if (file_exists($source_file))
- {
- $found = true;
- break;
- }
- }
- if ($found)
- {
- if ($find_all)
- {
- $found_all[] = $source_file;
- $found = false;
- }
- else
- {
- break;
- }
- }
- }
-
- // search failed
- if (!$found && !$find_all)
- {
- trigger_error("style resource locator: File for handle $handle does not exist. Could not find: $tried", E_USER_ERROR);
- }
-
- return ($find_all) ? $found_all : $source_file;
- }
-
- /**
- * {@inheritDoc}
- */
- public function get_first_file_location($files, $return_default = false, $return_full_path = true)
- {
- // set default value
- $default_result = false;
-
- // check all available paths
- foreach ($this->roots as $root_paths)
- {
- foreach ($root_paths as $path)
- {
- // check all files
- foreach ($files as $filename)
- {
- $source_file = $path . '/' . $filename;
- if (file_exists($source_file))
- {
- return ($return_full_path) ? $source_file : $filename;
- }
-
- // assign first file as result if $return_default is true
- if ($return_default && $default_result === false)
- {
- $default_result = $source_file;
- }
- }
- }
- }
-
- // search failed
- return $default_result;
- }
-
- /**
- * Obtains filesystem path for a template file.
- *
- * The simplest use is specifying a single template file as a string
- * in the first argument. This template file should be a basename
- * of a template file in the selected style, or its parent styles
- * if template inheritance is being utilized.
- *
- * Note: "selected style" is whatever style the style resource locator
- * is configured for.
- *
- * The return value then will be a path, relative to the current
- * directory or absolute, to the template file in the selected style
- * or its closest parent.
- *
- * If the selected style does not have the template file being searched,
- * (and if inheritance is involved, none of the parents have it either),
- * false will be returned.
- *
- * Specifying true for $return_default will cause the function to
- * return the first path which was checked for existence in the event
- * that the template file was not found, instead of false.
- * This is the path in the selected style itself, not any of its
- * parents.
- *
- * $files can be given an array of templates instead of a single
- * template. When given an array, the function will try to resolve
- * each template in the array to a path, and will return the first
- * path that exists, or false if none exist.
- *
- * If $files is an array and template inheritance is involved, first
- * each of the files will be checked in the selected style, then each
- * of the files will be checked in the immediate parent, and so on.
- *
- * If $return_full_path is false, then instead of returning a usable
- * path (when the template is found) only the template's basename
- * will be returned. This can be used to check which of the templates
- * specified in $files exists. Naturally more than one template must
- * be given in $files.
- *
- * This function works identically to get_first_file_location except
- * it operates on a list of templates, not files. Practically speaking,
- * the templates given in the first argument first are prepended with
- * the template path (property in this class), then given to
- * get_first_file_location for the rest of the processing.
- *
- * Templates given to this function can be relative paths for templates
- * located in subdirectories of the template directories. The paths
- * should be relative to the templates directory (template/ by default).
- *
- * @param string or array $files List of templates to locate. If there is only
- * one template, $files can be a string to make code easier to read.
- * @param bool $return_default Determines what to return if template does not
- * exist. If true, function will return location where template is
- * supposed to be. If false, function will return false.
- * @param bool $return_full_path If true, function will return full path
- * to template. If false, function will return template file name.
- * This parameter can be used to check which one of set of template
- * files is available.
- * @return string or boolean Source template path if template exists or $return_default is
- * true. False if template does not exist and $return_default is false
- */
- public function get_first_template_location($templates, $return_default = false, $return_full_path = true)
- {
- // add template path prefix
- $files = array();
- if (is_string($templates))
- {
- $files[] = $this->template_path . $templates;
- }
- else
- {
- foreach ($templates as $template)
- {
- $files[] = $this->template_path . $template;
- }
- }
-
- return $this->get_first_file_location($files, $return_default, $return_full_path);
- }
-}
diff --git a/phpBB/includes/style/style.php b/phpBB/includes/style/style.php
deleted file mode 100644
index effd496fb9..0000000000
--- a/phpBB/includes/style/style.php
+++ /dev/null
@@ -1,188 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Base Style class.
-* @package phpBB3
-*/
-class phpbb_style
-{
- /**
- * Template class.
- * Handles everything related to templates.
- * @var phpbb_template
- */
- private $template;
-
- /**
- * phpBB root path
- * @var string
- */
- private $phpbb_root_path;
-
- /**
- * PHP file extension
- * @var string
- */
- private $php_ext;
-
- /**
- * phpBB config instance
- * @var phpbb_config
- */
- private $config;
-
- /**
- * Current user
- * @var phpbb_user
- */
- private $user;
-
- /**
- * Style resource locator
- * @var phpbb_style_resource_locator
- */
- private $locator;
-
- /**
- * Style path provider
- * @var phpbb_style_path_provider
- */
- private $provider;
-
- /**
- * Constructor.
- *
- * @param string $phpbb_root_path phpBB root path
- * @param user $user current user
- * @param phpbb_style_resource_locator $locator style resource locator
- * @param phpbb_style_path_provider $provider style path provider
- * @param phpbb_template $template template
- */
- public function __construct($phpbb_root_path, $php_ext, $config, $user, phpbb_style_resource_locator $locator, phpbb_style_path_provider_interface $provider, phpbb_template $template)
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
- $this->config = $config;
- $this->user = $user;
- $this->locator = $locator;
- $this->provider = $provider;
- $this->template = $template;
- }
-
- /**
- * Set style location based on (current) user's chosen style.
- */
- public function set_style()
- {
- $style_path = $this->user->style['style_path'];
- $style_dirs = ($this->user->style['style_parent_id']) ? array_reverse(explode('/', $this->user->style['style_parent_tree'])) : array();
- $paths = array($this->get_style_path($style_path));
- foreach ($style_dirs as $dir)
- {
- $paths[] = $this->get_style_path($dir);
- }
-
- // Add 'all' path, used as last fallback path by hooks and extensions
- $paths[] = $this->get_style_path('all');
-
- return $this->set_custom_style($style_path, $paths);
- }
-
- /**
- * Set custom style location (able to use directory outside of phpBB).
- *
- * Note: Templates are still compiled to phpBB's cache directory.
- *
- * @param string $name Name of style, used for cache prefix. Examples: "admin", "prosilver"
- * @param array or string $paths Array of style paths, relative to current root directory
- * @param string $template_path Path to templates, relative to style directory. False if path should be set to default (templates/).
- */
- public function set_custom_style($name, $paths, $template_path = false)
- {
- if (is_string($paths))
- {
- $paths = array($paths);
- }
-
- $this->provider->set_styles($paths);
- $this->locator->set_paths($this->provider);
-
- if ($template_path !== false)
- {
- $this->locator->set_template_path($template_path);
- }
- else
- {
- $this->locator->set_default_template_path();
- }
-
- $this->template->cachepath = $this->phpbb_root_path . 'cache/tpl_' . str_replace('_', '-', $name) . '_';
-
- return true;
- }
-
- /**
- * Get location of style directory for specific style_path
- *
- * @param string $path Style path, such as "prosilver"
- * @return string Path to style directory, relative to current path
- */
- public function get_style_path($path)
- {
- return $this->phpbb_root_path . 'styles/' . $path;
- }
-
- /**
- * Defines a prefix to use for style paths in extensions
- *
- * @param string $ext_dir_prefix The prefix including trailing slash
- * @return null
- */
- public function set_ext_dir_prefix($ext_dir_prefix)
- {
- $this->provider->set_ext_dir_prefix($ext_dir_prefix);
- }
-
- /**
- * Locates source file path, accounting for styles tree and verifying that
- * the path exists.
- *
- * @param string or array $files List of files to locate. If there is only
- * one file, $files can be a string to make code easier to read.
- * @param bool $return_default Determines what to return if file does not
- * exist. If true, function will return location where file is
- * supposed to be. If false, function will return false.
- * @param bool $return_full_path If true, function will return full path
- * to file. If false, function will return file name. This
- * parameter can be used to check which one of set of files
- * is available.
- * @return string or boolean Source file path if file exists or $return_default is
- * true. False if file does not exist and $return_default is false
- */
- public function locate($files, $return_default = false, $return_full_path = true)
- {
- // convert string to array
- if (is_string($files))
- {
- $files = array($files);
- }
-
- // use resource locator to find files
- return $this->locator->get_first_file_location($files, $return_default, $return_full_path);
- }
-}
diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php
deleted file mode 100644
index 22da21820e..0000000000
--- a/phpBB/includes/template/compile.php
+++ /dev/null
@@ -1,130 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-stream_filter_register('phpbb_template', 'phpbb_template_filter');
-
-/**
-* Extension of template class - Functions needed for compiling templates only.
-*
-* @package phpBB3
-* @uses template_filter As a PHP stream filter to perform compilation of templates
-*/
-class phpbb_template_compile
-{
- /**
- * Array of parameters to forward to template filter
- *
- * @var array
- */
- private $filter_params;
-
- /**
- * Constructor.
- *
- * @param bool @allow_php Whether PHP code will be allowed in templates (inline PHP code, PHP tag and INCLUDEPHP tag)
- * @param phpbb_style_resource_locator $locator Resource locator
- * @param string $phpbb_root_path Path to phpBB root directory
- */
- public function __construct($allow_php, $locator, $phpbb_root_path)
- {
- $this->filter_params = array(
- 'allow_php' => $allow_php,
- 'locator' => $locator,
- 'phpbb_root_path' => $phpbb_root_path
- );
- }
-
- /**
- * Compiles template in $source_file and writes compiled template to
- * cache directory
- *
- * @param string $handle Template handle to compile
- * @param string $source_file Source template file
- * @return bool Return true on success otherwise false
- */
- public function compile_file_to_file($source_file, $compiled_file)
- {
- $lock = new phpbb_lock_flock($compiled_file);
- $lock->acquire();
-
- $source_handle = @fopen($source_file, 'rb');
- $destination_handle = @fopen($compiled_file, 'wb');
-
- if (!$source_handle || !$destination_handle)
- {
- return false;
- }
-
- $this->compile_stream_to_stream($source_handle, $destination_handle);
-
- @fclose($source_handle);
- @fclose($destination_handle);
-
- phpbb_chmod($compiled_file, CHMOD_READ | CHMOD_WRITE);
-
- $lock->release();
-
- clearstatcache();
-
- return true;
- }
-
- /**
- * Compiles a template located at $source_file.
- *
- * Returns PHP source suitable for eval().
- *
- * @param string $source_file Source template file
- * @return string|bool Return compiled code on successful compilation otherwise false
- */
- public function compile_file($source_file)
- {
- $source_handle = @fopen($source_file, 'rb');
- $destination_handle = @fopen('php://temp' ,'r+b');
-
- if (!$source_handle || !$destination_handle)
- {
- return false;
- }
-
- $this->compile_stream_to_stream($source_handle, $destination_handle);
-
- @fclose($source_handle);
-
- rewind($destination_handle);
- $contents = stream_get_contents($destination_handle);
- @fclose($dest_handle);
-
- return $contents;
- }
-
- /**
- * Compiles contents of $source_stream into $dest_stream.
- *
- * A stream filter is appended to $source_stream as part of the
- * process.
- *
- * @param resource $source_stream Source stream
- * @param resource $dest_stream Destination stream
- * @return null
- */
- private function compile_stream_to_stream($source_stream, $dest_stream)
- {
- stream_filter_append($source_stream, 'phpbb_template', null, $this->filter_params);
- stream_copy_to_stream($source_stream, $dest_stream);
- }
-}
diff --git a/phpBB/includes/template/context.php b/phpBB/includes/template/context.php
deleted file mode 100644
index ec09da1cf3..0000000000
--- a/phpBB/includes/template/context.php
+++ /dev/null
@@ -1,359 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Stores variables assigned to template.
-*
-* @package phpBB3
-*/
-class phpbb_template_context
-{
- /**
- * variable that holds all the data we'll be substituting into
- * the compiled templates. Takes form:
- * --> $this->tpldata[block][iteration#][child][iteration#][child2][iteration#][variablename] == value
- * if it's a root-level variable, it'll be like this:
- * --> $this->tpldata[.][0][varname] == value
- *
- * @var array
- */
- private $tpldata = array('.' => array(0 => array()));
-
- /**
- * @var array Reference to template->tpldata['.'][0]
- */
- private $rootref;
-
- public function __construct()
- {
- $this->clear();
- }
-
- /**
- * Clears template data set.
- */
- public function clear()
- {
- $this->tpldata = array('.' => array(0 => array()));
- $this->rootref = &$this->tpldata['.'][0];
- }
-
- /**
- * Assign a single scalar value to a single key.
- *
- * Value can be a string, an integer or a boolean.
- *
- * @param string $varname Variable name
- * @param string $varval Value to assign to variable
- */
- public function assign_var($varname, $varval)
- {
- $this->rootref[$varname] = $varval;
-
- return true;
- }
-
- /**
- * Append text to the string value stored in a key.
- *
- * Text is appended using the string concatenation operator (.).
- *
- * @param string $varname Variable name
- * @param string $varval Value to append to variable
- */
- public function append_var($varname, $varval)
- {
- $this->rootref[$varname] = (isset($this->rootref[$varname]) ? $this->rootref[$varname] : '') . $varval;
-
- return true;
- }
-
- /**
- * Returns a reference to template data array.
- *
- * This function is public so that template renderer may invoke it.
- * Users should alter template variables via functions in phpbb_template.
- *
- * Note: modifying returned array will affect data stored in the context.
- *
- * @return array template data
- */
- public function &get_data_ref()
- {
- // returning a reference directly is not
- // something php is capable of doing
- $ref = &$this->tpldata;
- return $ref;
- }
-
- /**
- * Returns a reference to template root scope.
- *
- * This function is public so that template renderer may invoke it.
- * Users should not need to invoke this function.
- *
- * Note: modifying returned array will affect data stored in the context.
- *
- * @return array template data
- */
- public function &get_root_ref()
- {
- // rootref is already a reference
- return $this->rootref;
- }
-
- /**
- * Assign key variable pairs from an array to a specified block
- *
- * @param string $blockname Name of block to assign $vararray to
- * @param array $vararray A hash of variable name => value pairs
- */
- public function assign_block_vars($blockname, array $vararray)
- {
- if (strpos($blockname, '.') !== false)
- {
- // Nested block.
- $blocks = explode('.', $blockname);
- $blockcount = sizeof($blocks) - 1;
-
- $str = &$this->tpldata;
- for ($i = 0; $i < $blockcount; $i++)
- {
- $str = &$str[$blocks[$i]];
- $str = &$str[sizeof($str) - 1];
- }
-
- $s_row_count = isset($str[$blocks[$blockcount]]) ? sizeof($str[$blocks[$blockcount]]) : 0;
- $vararray['S_ROW_COUNT'] = $s_row_count;
-
- // Assign S_FIRST_ROW
- if (!$s_row_count)
- {
- $vararray['S_FIRST_ROW'] = true;
- }
-
- // Now the tricky part, we always assign S_LAST_ROW and remove the entry before
- // This is much more clever than going through the complete template data on display (phew)
- $vararray['S_LAST_ROW'] = true;
- if ($s_row_count > 0)
- {
- unset($str[$blocks[$blockcount]][($s_row_count - 1)]['S_LAST_ROW']);
- }
-
- // Now we add the block that we're actually assigning to.
- // We're adding a new iteration to this block with the given
- // variable assignments.
- $str[$blocks[$blockcount]][] = $vararray;
- }
- else
- {
- // Top-level block.
- $s_row_count = (isset($this->tpldata[$blockname])) ? sizeof($this->tpldata[$blockname]) : 0;
- $vararray['S_ROW_COUNT'] = $s_row_count;
-
- // Assign S_FIRST_ROW
- if (!$s_row_count)
- {
- $vararray['S_FIRST_ROW'] = true;
- }
-
- // We always assign S_LAST_ROW and remove the entry before
- $vararray['S_LAST_ROW'] = true;
- if ($s_row_count > 0)
- {
- 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;
- }
-
- return true;
- }
-
- /**
- * Change already assigned key variable pair (one-dimensional - single loop entry)
- *
- * An example of how to use this function:
- * {@example alter_block_array.php}
- *
- * @param string $blockname the blockname, for example 'loop'
- * @param array $vararray the var array to insert/add or merge
- * @param mixed $key Key to search for
- *
- * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position]
- *
- * int: Position [the position to change or insert at directly given]
- *
- * If key is false the position is set to 0
- * If key is true the position is set to the last entry
- *
- * @param string $mode Mode to execute (valid modes are 'insert' and 'change')
- *
- * If insert, the vararray is inserted at the given position (position counting from zero).
- * If change, the current block gets merged with the vararray (resulting in new key/value pairs be added and existing keys be replaced by the new value).
- *
- * Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array)
- * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars)
- *
- * @return bool false on error, true on success
- */
- public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert')
- {
- if (strpos($blockname, '.') !== false)
- {
- // Nested block.
- $blocks = explode('.', $blockname);
- $blockcount = sizeof($blocks) - 1;
-
- $block = &$this->tpldata;
- for ($i = 0; $i < $blockcount; $i++)
- {
- if (($pos = strpos($blocks[$i], '[')) !== false)
- {
- $name = substr($blocks[$i], 0, $pos);
-
- if (strpos($blocks[$i], '[]') === $pos)
- {
- $index = sizeof($block[$name]) - 1;
- }
- else
- {
- $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1);
- }
- }
- else
- {
- $name = $blocks[$i];
- $index = sizeof($block[$name]) - 1;
- }
- $block = &$block[$name];
- $block = &$block[$index];
- }
-
- $block = &$block[$blocks[$i]]; // Traverse the last block
- }
- else
- {
- // Top-level block.
- $block = &$this->tpldata[$blockname];
- }
-
- // Change key to zero (change first position) if false and to last position if true
- if ($key === false || $key === true)
- {
- $key = ($key === false) ? 0 : sizeof($block);
- }
-
- // Get correct position if array given
- if (is_array($key))
- {
- // Search array to get correct position
- list($search_key, $search_value) = @each($key);
-
- $key = NULL;
- foreach ($block as $i => $val_ary)
- {
- if ($val_ary[$search_key] === $search_value)
- {
- $key = $i;
- break;
- }
- }
-
- // key/value pair not found
- if ($key === NULL)
- {
- return false;
- }
- }
-
- // Insert Block
- if ($mode == 'insert')
- {
- // Make sure we are not exceeding the last iteration
- if ($key >= sizeof($this->tpldata[$blockname]))
- {
- $key = sizeof($this->tpldata[$blockname]);
- unset($this->tpldata[$blockname][($key - 1)]['S_LAST_ROW']);
- $vararray['S_LAST_ROW'] = true;
- }
- else if ($key === 0)
- {
- unset($this->tpldata[$blockname][0]['S_FIRST_ROW']);
- $vararray['S_FIRST_ROW'] = true;
- }
-
- // Re-position template blocks
- for ($i = sizeof($block); $i > $key; $i--)
- {
- $block[$i] = $block[$i-1];
- }
-
- // Insert vararray at given position
- $block[$key] = $vararray;
-
- return true;
- }
-
- // Which block to change?
- if ($mode == 'change')
- {
- if ($key == sizeof($block))
- {
- $key--;
- }
-
- $block[$key] = array_merge($block[$key], $vararray);
-
- return true;
- }
-
- return false;
- }
-
- /**
- * Reset/empty complete block
- *
- * @param string $blockname Name of block to destroy
- */
- public function destroy_block_vars($blockname)
- {
- if (strpos($blockname, '.') !== false)
- {
- // Nested block.
- $blocks = explode('.', $blockname);
- $blockcount = sizeof($blocks) - 1;
-
- $str = &$this->tpldata;
- for ($i = 0; $i < $blockcount; $i++)
- {
- $str = &$str[$blocks[$i]];
- $str = &$str[sizeof($str) - 1];
- }
-
- unset($str[$blocks[$blockcount]]);
- }
- else
- {
- // Top-level block.
- unset($this->tpldata[$blockname]);
- }
-
- return true;
- }
-}
diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php
deleted file mode 100644
index 66d28242a3..0000000000
--- a/phpBB/includes/template/filter.php
+++ /dev/null
@@ -1,1059 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group, sections (c) 2001 ispi of Lincoln Inc
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* The template filter that does the actual compilation
-*
-* psoTFX, phpBB Development Team - Completion of file caching, decompilation
-* routines and implementation of conditionals/keywords and associated changes
-*
-* The interface was inspired by PHPLib templates, and the template file (formats are
-* quite similar)
-*
-* The keyword/conditional implementation is currently based on sections of code from
-* the Smarty templating engine (c) 2001 ispi of Lincoln, Inc. which is released
-* (on its own and in whole) under the LGPL. Section 3 of the LGPL states that any code
-* derived from an LGPL application may be relicenced under the GPL, this applies
-* to this source
-*
-* DEFINE directive inspired by a request by Cyberalien
-*
-* @see template_compile
-* @package phpBB3
-*/
-class phpbb_template_filter extends php_user_filter
-{
- const REGEX_NS = '[a-z_][a-z_0-9]+';
-
- const REGEX_VAR = '[A-Z_][A-Z_0-9]+';
- const REGEX_VAR_SUFFIX = '[A-Z_0-9]+';
-
- const REGEX_TAG = '<!-- ([A-Z][A-Z_0-9]+)(?: (.*?) ?)?-->';
-
- const REGEX_TOKENS = '~<!-- ([A-Z][A-Z_0-9]+)(?: (.*?) ?)?-->|{((?:[a-z_][a-z_0-9]+\.)*\\$?[A-Z][A-Z_0-9]+)}~';
-
- /**
- * @var array
- */
- private $block_names = array();
-
- /**
- * @var array
- */
- private $block_else_level = array();
-
- /**
- * @var string
- */
- private $chunk;
-
- /**
- * @var bool
- */
- private $in_php;
-
- /**
- * Whether inline PHP code, <!-- PHP --> and <!-- INCLUDEPHP --> tags
- * are allowed. If this is false all PHP code will be silently
- * removed from the template during compilation.
- *
- * @var bool
- */
- private $allow_php;
-
- /**
- * Resource locator.
- *
- * @var phpbb_template_locator
- */
- private $locator;
-
- /**
- * @var string phpBB root path
- */
- private $phpbb_root_path;
-
- /**
- * Stream filter
- *
- * Is invoked for evey chunk of the stream, allowing us
- * to work on a chunk at a time, which saves memory.
- */
- public function filter($in, $out, &$consumed, $closing)
- {
- $written = false;
- $first = false;
-
- while ($bucket = stream_bucket_make_writeable($in))
- {
- $consumed += $bucket->datalen;
-
- $data = $this->chunk . $bucket->data;
- $last_nl = strrpos($data, "\n");
- $this->chunk = substr($data, $last_nl);
- $data = substr($data, 0, $last_nl);
-
- if (!strlen($data))
- {
- continue;
- }
-
- $written = true;
-
- $data = $this->compile($data);
- if (!$first)
- {
- $data = $this->prepend_preamble($data);
- $first = false;
- }
- $bucket->data = $data;
- $bucket->datalen = strlen($bucket->data);
- stream_bucket_append($out, $bucket);
- }
-
- if ($closing && strlen($this->chunk))
- {
- $written = true;
- $bucket = stream_bucket_new($this->stream, $this->compile($this->chunk));
- stream_bucket_append($out, $bucket);
- }
-
- return $written ? PSFS_PASS_ON : PSFS_FEED_ME;
- }
-
- /**
- * Initializer, called on creation.
- *
- * Get the allow_php option, root directory and locator from params,
- * which are passed to stream_filter_append.
- */
- public function onCreate()
- {
- $this->chunk = '';
- $this->in_php = false;
- $this->allow_php = $this->params['allow_php'];
- $this->locator = $this->params['locator'];
- $this->phpbb_root_path = $this->params['phpbb_root_path'];
- return true;
- }
-
- /**
- * Compiles a chunk of template.
- *
- * The chunk must comprise of one or more complete lines from the source
- * template.
- *
- * @param string $data Chunk of source template to compile
- * @return string Compiled PHP/HTML code
- */
- private function compile($data)
- {
- $block_start_in_php = $this->in_php;
-
- $data = preg_replace('#<(?:[\\?%]|script)#s', '<?php echo\'\\0\';?>', $data);
- $data = preg_replace_callback(self::REGEX_TOKENS, array($this, 'replace'), $data);
-
- // Remove php
- if (!$this->allow_php)
- {
- if ($block_start_in_php
- && $this->in_php
- && strpos($data, '<!-- PHP -->') === false
- && strpos($data, '<!-- ENDPHP -->') === false)
- {
- // This is just php code
- return '';
- }
- $data = preg_replace('~^.*?<!-- ENDPHP -->~', '', $data);
- $data = preg_replace('~<!-- PHP -->.*?<!-- ENDPHP -->~', '', $data);
- $data = preg_replace('~<!-- ENDPHP -->.*?$~', '', $data);
- }
-
- /*
- Preserve whitespace.
- PHP removes a newline after the closing tag (if it's there). This is by design.
-
-
- Consider the following template:
-
- <!-- IF condition -->
- some content
- <!-- ENDIF -->
-
- If we were to simply preserve all whitespace, we could simply replace all "?>" tags
- with "?>\n".
- Doing that, would add additional newlines to the compiled tempalte in place of the
- IF and ENDIF statements. These newlines are unwanted (and one is conditional).
- The IF and ENDIF are usually on their own line for ease of reading.
-
- This replacement preserves newlines only for statements that aren't the only statement on a line.
- It will NOT preserve newlines at the end of statements in the above examle.
- It will preserve newlines in situations like:
-
- <!-- IF condition -->inline content<!-- ENDIF -->
-
-
- */
-
- $data = preg_replace('~(?<!^)(<\?php.+(?<!/\*\*/)\?>)$~m', "$1\n", $data);
- $data = str_replace('/**/?>', "?>\n", $data);
- $data = str_replace('?><?php', '', $data);
- return $data;
- }
-
- /**
- * Prepends a preamble to compiled template.
- * Currently preamble checks if IN_PHPBB is defined and calls exit() if it is not.
- *
- * @param string $data Compiled template chunk
- * @return string Compiled template chunk with preamble prepended
- */
- private function prepend_preamble($data)
- {
- $data = "<?php if (!defined('IN_PHPBB')) exit;" . ((strncmp($data, '<?php', 5) === 0) ? substr($data, 5) : ' ?>' . $data);
- return $data;
- }
-
- /**
- * Callback for replacing matched tokens with PHP code
- *
- * @param array $matches Regular expression matches
- * @return string compiled template code
- */
- private function replace($matches)
- {
- if ($this->in_php && $matches[1] != 'ENDPHP')
- {
- return '';
- }
-
- if (isset($matches[3]))
- {
- return $this->compile_var_tags($matches[0]);
- }
-
- switch ($matches[1])
- {
- case 'BEGIN':
- $this->block_else_level[] = false;
- return '<?php ' . $this->compile_tag_block($matches[2]) . ' ?>';
- break;
-
- case 'BEGINELSE':
- $this->block_else_level[sizeof($this->block_else_level) - 1] = true;
- return '<?php }} else { ?>';
- break;
-
- case 'END':
- array_pop($this->block_names);
- return '<?php ' . ((array_pop($this->block_else_level)) ? '}' : '}}') . ' ?>';
- break;
-
- case 'IF':
- return '<?php ' . $this->compile_tag_if($matches[2], false) . ' ?>';
- break;
-
- case 'ELSE':
- return '<?php } else { ?>';
- break;
-
- case 'ELSEIF':
- return '<?php ' . $this->compile_tag_if($matches[2], true) . ' ?>';
- break;
-
- case 'ENDIF':
- return '<?php } ?>';
- break;
-
- case 'DEFINE':
- return '<?php ' . $this->compile_tag_define($matches[2], true) . ' ?>';
- break;
-
- case 'UNDEFINE':
- return '<?php ' . $this->compile_tag_define($matches[2], false) . ' ?>';
- break;
-
- case 'INCLUDE':
- return '<?php ' . $this->compile_tag_include($matches[2]) . ' ?>';
- break;
-
- case 'INCLUDEPHP':
- return ($this->allow_php) ? '<?php ' . $this->compile_tag_include_php($matches[2]) . ' ?>' : '';
- break;
-
- case 'INCLUDEJS':
- return '<?php ' . $this->compile_tag_include_js($matches[2]) . ' ?>';
- break;
-
- case 'PHP':
- if ($this->allow_php)
- {
- $this->in_php = true;
- return '<?php ';
- }
- return '<!-- PHP -->';
- break;
-
- case 'ENDPHP':
- if ($this->allow_php)
- {
- $this->in_php = false;
- return ' ?>';
- }
- return '<!-- ENDPHP -->';
- break;
-
- default:
- return $matches[0];
- break;
-
- }
- return '';
- }
-
- /**
- * Convert template variables into PHP varrefs
- *
- * @param string $text_blocks Variable reference in source template
- * @param bool $is_expr Returns whether the source was an expression type variable (i.e. S_FIRST_ROW)
- * @return string PHP variable name
- */
- private function get_varref($text_blocks, &$is_expr)
- {
- // change template varrefs into PHP varrefs
- $varrefs = array();
-
- // This one will handle varrefs WITH namespaces
- preg_match_all('#\{((?:' . self::REGEX_NS . '\.)+)(\$)?(' . self::REGEX_VAR . ')\}#', $text_blocks, $varrefs, PREG_SET_ORDER);
-
- foreach ($varrefs as $var_val)
- {
- $namespace = $var_val[1];
- $varname = $var_val[3];
- $new = $this->generate_block_varref($namespace, $varname, $is_expr, $var_val[2]);
-
- $text_blocks = str_replace($var_val[0], $new, $text_blocks);
- }
-
- // Language variables cannot be reduced to a single varref, so they must be skipped
- // These two replacements would break language variables, so we can only run them on non-language types
- if (strpos($text_blocks, '{L_') === false && strpos($text_blocks, '{LA_') === false)
- {
- // This will handle the remaining root-level varrefs
- $text_blocks = preg_replace('#\{(' . self::REGEX_VAR . ')\}#', "\$_rootref['\\1']", $text_blocks);
- $text_blocks = preg_replace('#\{\$(' . self::REGEX_VAR . ')\}#', "\$_tpldata['DEFINE']['.']['\\1']", $text_blocks);
- }
-
- return $text_blocks;
- }
-
- /**
- * Parse paths of the form {FOO}/a/{BAR}/b
- *
- * Note: this method assumes at least one variable in the path, this should
- * be checked before this method is called.
- *
- * @param string $path The path to parse
- * @param string $include_type The type of template function to call
- * @return string An appropriately formatted string to include in the
- * template or an empty string if an expression like S_FIRST_ROW was
- * incorrectly used
- */
- private function parse_dynamic_path($path, $include_type)
- {
- $matches = array();
- $replace = array();
- $is_expr = true;
-
- preg_match_all('#\{((?:' . self::REGEX_NS . '\.)*)(\$)?(' . self::REGEX_VAR . ')\}#', $path, $matches);
- foreach ($matches[0] as $var_str)
- {
- $tmp_is_expr = false;
- $var = $this->get_varref($var_str, $tmp_is_expr);
- $is_expr = $is_expr && $tmp_is_expr;
- $replace[] = "' . $var . '";
- }
-
- if (!$is_expr)
- {
- return " \$_template->$include_type('" . str_replace($matches[0], $replace, $path) . "', true);";
- }
- else
- {
- return '';
- }
- }
-
- /**
- * Compile variables
- *
- * @param string $text_blocks Variable reference in source template
- * @return string compiled template code
- */
- private function compile_var_tags(&$text_blocks)
- {
- $text_blocks = $this->get_varref($text_blocks, $is_expr);
- $lang_replaced = $this->compile_language_tags($text_blocks);
-
- if(!$lang_replaced)
- {
- $text_blocks = '<?php echo ' . ($is_expr ? "$text_blocks" : "(isset($text_blocks)) ? $text_blocks : ''") . '; /**/?>';
- }
-
- return $text_blocks;
- }
-
- /**
- * Handles special language tags L_ and LA_
- *
- * @param string $text_blocks Variable reference in source template
- * @return bool Whether a replacement occurred or not
- */
- private function compile_language_tags(&$text_blocks)
- {
- $replacements = 0;
-
- // transform vars prefixed by L_ into their language variable pendant if nothing is set within the tpldata array
- if (strpos($text_blocks, '{L_') !== false)
- {
- $text_blocks = preg_replace('#\{L_(' . self::REGEX_VAR_SUFFIX . ')\}#', "<?php echo ((isset(\$_rootref['L_\\1'])) ? \$_rootref['L_\\1'] : ((isset(\$_lang['\\1'])) ? \$_lang['\\1'] : '{ \\1 }')); /**/?>", $text_blocks, -1, $replacements);
- return (bool) $replacements;
- }
-
- // Handle addslashed language variables prefixed with LA_
- // If a template variable already exist, it will be used in favor of it...
- if (strpos($text_blocks, '{LA_') !== false)
- {
- $text_blocks = preg_replace('#\{LA_(' . self::REGEX_VAR_SUFFIX . '+)\}#', "<?php echo ((isset(\$_rootref['LA_\\1'])) ? \$_rootref['LA_\\1'] : ((isset(\$_rootref['L_\\1'])) ? addslashes(\$_rootref['L_\\1']) : ((isset(\$_lang['\\1'])) ? addslashes(\$_lang['\\1']) : '{ \\1 }'))); /**/?>", $text_blocks, -1, $replacements);
- return (bool) $replacements;
- }
-
- return false;
- }
-
- /**
- * Compile blocks
- *
- * @param string $tag_args Block contents in source template
- * @return string compiled template code
- */
- private function compile_tag_block($tag_args)
- {
- $no_nesting = false;
-
- // Is the designer wanting to call another loop in a loop?
- // <!-- BEGIN loop -->
- // <!-- BEGIN !loop2 -->
- // <!-- END !loop2 -->
- // <!-- END loop -->
- // 'loop2' is actually on the same nesting level as 'loop' you assign
- // variables to it with template->assign_block_vars('loop2', array(...))
- if (strpos($tag_args, '!') === 0)
- {
- // Count the number if ! occurrences (not allowed in vars)
- $no_nesting = substr_count($tag_args, '!');
- $tag_args = substr($tag_args, $no_nesting);
- }
-
- // Allow for control of looping (indexes start from zero):
- // foo(2) : Will start the loop on the 3rd entry
- // foo(-2) : Will start the loop two entries from the end
- // foo(3,4) : Will start the loop on the fourth entry and end it on the fifth
- // foo(3,-4) : Will start the loop on the fourth entry and end it four from last
- $match = array();
-
- if (preg_match('#^([^()]*)\(([\-\d]+)(?:,([\-\d]+))?\)$#', $tag_args, $match))
- {
- $tag_args = $match[1];
-
- if ($match[2] < 0)
- {
- $loop_start = '($_' . $tag_args . '_count ' . $match[2] . ' < 0 ? 0 : $_' . $tag_args . '_count ' . $match[2] . ')';
- }
- else
- {
- $loop_start = '($_' . $tag_args . '_count < ' . $match[2] . ' ? $_' . $tag_args . '_count : ' . $match[2] . ')';
- }
-
- if (!isset($match[3]) || strlen($match[3]) < 1 || $match[3] == -1)
- {
- $loop_end = '$_' . $tag_args . '_count';
- }
- else if ($match[3] >= 0)
- {
- $loop_end = '(' . ($match[3] + 1) . ' > $_' . $tag_args . '_count ? $_' . $tag_args . '_count : ' . ($match[3] + 1) . ')';
- }
- else //if ($match[3] < -1)
- {
- $loop_end = '$_' . $tag_args . '_count' . ($match[3] + 1);
- }
- }
- else
- {
- $loop_start = 0;
- $loop_end = '$_' . $tag_args . '_count';
- }
-
- $tag_template_php = '';
- array_push($this->block_names, $tag_args);
-
- if ($no_nesting !== false)
- {
- // We need to implode $no_nesting times from the end...
- $block = array_slice($this->block_names, -$no_nesting);
- }
- else
- {
- $block = $this->block_names;
- }
-
- if (sizeof($block) < 2)
- {
- // Block is not nested.
- $tag_template_php = '$_' . $tag_args . "_count = (isset(\$_tpldata['$tag_args'])) ? sizeof(\$_tpldata['$tag_args']) : 0;";
- $varref = "\$_tpldata['$tag_args']";
- }
- else
- {
- // This block is nested.
- // Generate a namespace string for this block.
- $namespace = implode('.', $block);
-
- // Get a reference to the data array for this block that depends on the
- // current indices of all parent blocks.
- $varref = $this->generate_block_data_ref($namespace, false);
-
- // Create the for loop code to iterate over this block.
- $tag_template_php = '$_' . $tag_args . '_count = (isset(' . $varref . ')) ? sizeof(' . $varref . ') : 0;';
- }
-
- $tag_template_php .= 'if ($_' . $tag_args . '_count) {';
-
- /**
- * The following uses foreach for iteration instead of a for loop, foreach is faster but requires PHP to make a copy of the contents of the array which uses more memory
- * <code>
- * if (!$offset)
- * {
- * $tag_template_php .= 'foreach (' . $varref . ' as $_' . $tag_args . '_i => $_' . $tag_args . '_val){';
- * }
- * </code>
- */
-
- $tag_template_php .= 'for ($_' . $tag_args . '_i = ' . $loop_start . '; $_' . $tag_args . '_i < ' . $loop_end . '; ++$_' . $tag_args . '_i){';
- $tag_template_php .= '$_' . $tag_args . '_val = &' . $varref . '[$_' . $tag_args . '_i];';
-
- return $tag_template_php;
- }
-
- /**
- * Compile a general expression - much of this is from Smarty with
- * some adaptions for our block level methods
- *
- * @param string $tag_args Expression (tag arguments) in source template
- * @return string compiled template code
- */
- private function compile_expression($tag_args)
- {
- $match = array();
- preg_match_all('/(?:
- "[^"\\\\]*(?:\\\\.[^"\\\\]*)*" |
- \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\' |
- [(),] |
- [^\s(),]+)/x', $tag_args, $match);
-
- $tokens = $match[0];
- $is_arg_stack = array();
-
- for ($i = 0, $size = sizeof($tokens); $i < $size; $i++)
- {
- $token = &$tokens[$i];
-
- switch ($token)
- {
- case '!==':
- case '===':
- case '<<':
- case '>>':
- case '|':
- case '^':
- case '&':
- case '~':
- case ')':
- case ',':
- case '+':
- case '-':
- case '*':
- case '/':
- case '@':
- break;
-
- case '==':
- case 'eq':
- $token = '==';
- break;
-
- case '!=':
- case '<>':
- case 'ne':
- case 'neq':
- $token = '!=';
- break;
-
- case '<':
- case 'lt':
- $token = '<';
- break;
-
- case '<=':
- case 'le':
- case 'lte':
- $token = '<=';
- break;
-
- case '>':
- case 'gt':
- $token = '>';
- break;
-
- case '>=':
- case 'ge':
- case 'gte':
- $token = '>=';
- break;
-
- case '&&':
- case 'and':
- $token = '&&';
- break;
-
- case '||':
- case 'or':
- $token = '||';
- break;
-
- case '!':
- case 'not':
- $token = '!';
- break;
-
- case '%':
- case 'mod':
- $token = '%';
- break;
-
- case '(':
- array_push($is_arg_stack, $i);
- break;
-
- case 'is':
- $is_arg_start = ($tokens[$i-1] == ')') ? array_pop($is_arg_stack) : $i-1;
- $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start));
-
- $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1));
-
- array_splice($tokens, $is_arg_start, sizeof($tokens), $new_tokens);
-
- $i = $is_arg_start;
-
- // no break
-
- default:
- $varrefs = array();
- if (preg_match('#^((?:' . self::REGEX_NS . '\.)+)?(\$)?(?=[A-Z])([A-Z0-9\-_]+)#s', $token, $varrefs))
- {
- if (!empty($varrefs[1]))
- {
- $namespace = substr($varrefs[1], 0, -1);
- $dot_pos = strrchr($namespace, '.');
- if ($dot_pos !== false)
- {
- $namespace = substr($dot_pos, 1);
- }
-
- // S_ROW_COUNT is deceptive, it returns the current row number not the number of rows
- // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM
- switch ($varrefs[3])
- {
- case 'S_ROW_NUM':
- case 'S_ROW_COUNT':
- $token = "\$_${namespace}_i";
- break;
-
- case 'S_NUM_ROWS':
- $token = "\$_${namespace}_count";
- break;
-
- case 'S_FIRST_ROW':
- $token = "(\$_${namespace}_i == 0)";
- break;
-
- case 'S_LAST_ROW':
- $token = "(\$_${namespace}_i == \$_${namespace}_count - 1)";
- break;
-
- case 'S_BLOCK_NAME':
- $token = "'$namespace'";
- break;
-
- default:
- $token = $this->generate_block_data_ref(substr($varrefs[1], 0, -1), true, $varrefs[2]) . '[\'' . $varrefs[3] . '\']';
- $token = '(isset(' . $token . ') ? ' . $token . ' : null)';
- break;
- }
- }
- else
- {
- $token = ($varrefs[2]) ? '$_tpldata[\'DEFINE\'][\'.\'][\'' . $varrefs[3] . '\']' : '$_rootref[\'' . $varrefs[3] . '\']';
- $token = '(isset(' . $token . ') ? ' . $token . ' : null)';
- }
-
- }
- else if (preg_match('#^\.((?:' . self::REGEX_NS . '\.?)+)$#s', $token, $varrefs))
- {
- // Allow checking if loops are set with .loopname
- // It is also possible to check the loop count by doing <!-- IF .loopname > 1 --> for example
- $blocks = explode('.', $varrefs[1]);
-
- // If the block is nested, we have a reference that we can grab.
- // If the block is not nested, we just go and grab the block from _tpldata
- if (sizeof($blocks) > 1)
- {
- $block = array_pop($blocks);
- $namespace = implode('.', $blocks);
- $varref = $this->generate_block_data_ref($namespace, true);
-
- // Add the block reference for the last child.
- $varref .= "['" . $block . "']";
- }
- else
- {
- $varref = '$_tpldata';
-
- // Add the block reference for the last child.
- $varref .= "['" . $blocks[0] . "']";
- }
- $token = "(isset($varref) ? sizeof($varref) : 0)";
- }
-
- break;
- }
- }
-
- return $tokens;
- }
-
- /**
- * Compile IF tags
- *
- * @param string $tag_args Expression given with IF in source template
- * @param bool $elseif True if compiling an IF tag, false if compiling an ELSEIF tag
- * @return string compiled template code
- */
- private function compile_tag_if($tag_args, $elseif)
- {
- $tokens = $this->compile_expression($tag_args);
-
- $tpl = ($elseif) ? '} else if (' : 'if (';
-
- $tpl .= implode(' ', $tokens);
- $tpl .= ') { ';
-
- return $tpl;
- }
-
- /**
- * Compile DEFINE tags
- *
- * @param string $tag_args Expression given with DEFINE in source template
- * @param bool $op True if compiling a DEFINE tag, false if compiling an UNDEFINE tag
- * @return string compiled template code
- */
- private function compile_tag_define($tag_args, $op)
- {
- $match = array();
- preg_match('#^((?:' . self::REGEX_NS . '\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (.*?))?$#', $tag_args, $match);
-
- if (empty($match[2]) || (!isset($match[3]) && $op))
- {
- return '';
- }
-
- if (!$op)
- {
- return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');';
- }
-
- $parsed_statement = implode(' ', $this->compile_expression($match[3]));
-
- return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $parsed_statement . ';';
- }
-
- /**
- * Compile INCLUDE tag
- *
- * @param string $tag_args Expression given with INCLUDE in source template
- * @return string compiled template code
- */
- private function compile_tag_include($tag_args)
- {
- // Process dynamic includes
- if (strpos($tag_args, '{') !== false)
- {
- return $this->parse_dynamic_path($tag_args, '_tpl_include');
- }
-
- return "\$_template->_tpl_include('$tag_args');";
- }
-
- /**
- * Compile INCLUDE_PHP tag
- *
- * @param string $tag_args Expression given with INCLUDEPHP in source template
- * @return string compiled template code
- */
- private function compile_tag_include_php($tag_args)
- {
- if (strpos($tag_args, '{') !== false)
- {
- return $this->parse_dynamic_path($tag_args, '_php_include');
- }
-
- return "\$_template->_php_include('$tag_args');";
- }
-
- /**
- * parse expression
- * This is from Smarty
- */
- private function _parse_is_expr($is_arg, $tokens)
- {
- $expr_end = 0;
- $negate_expr = false;
-
- if (($first_token = array_shift($tokens)) == 'not')
- {
- $negate_expr = true;
- $expr_type = array_shift($tokens);
- }
- else
- {
- $expr_type = $first_token;
- }
-
- switch ($expr_type)
- {
- case 'even':
- if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by')
- {
- $expr_end++;
- $expr_arg = $tokens[$expr_end++];
- $expr = "!(($is_arg / $expr_arg) & 1)";
- }
- else
- {
- $expr = "!($is_arg & 1)";
- }
- break;
-
- case 'odd':
- if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by')
- {
- $expr_end++;
- $expr_arg = $tokens[$expr_end++];
- $expr = "(($is_arg / $expr_arg) & 1)";
- }
- else
- {
- $expr = "($is_arg & 1)";
- }
- break;
-
- case 'div':
- if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by')
- {
- $expr_end++;
- $expr_arg = $tokens[$expr_end++];
- $expr = "!($is_arg % $expr_arg)";
- }
- break;
- }
-
- if ($negate_expr)
- {
- if ($expr[0] == '!')
- {
- // Negated expression, de-negate it.
- $expr = substr($expr, 1);
- }
- else
- {
- $expr = "!($expr)";
- }
- }
-
- array_splice($tokens, 0, $expr_end, $expr);
-
- return $tokens;
- }
-
- /**
- * Compile INCLUDEJS tag
- *
- * @param string $tag_args Expression given with INCLUDEJS in source template
- * @return string compiled template code
- */
- private function compile_tag_include_js($tag_args)
- {
- // Process dynamic includes
- if (strpos($tag_args, '{') !== false)
- {
- return $this->parse_dynamic_path($tag_args, '_js_include');
- }
-
- // Locate file
- $filename = $this->locator->get_first_file_location(array($tag_args), false, true);
-
- if ($filename === false)
- {
- // File does not exist, find it during run time
- return ' $_template->_js_include(\'' . addslashes($tag_args) . '\', true); ';
- }
-
- if (substr($filename, 0, strlen($this->phpbb_root_path)) != $this->phpbb_root_path)
- {
- // Absolute path, include as is
- return ' $_template->_js_include(\'' . addslashes($filename) . '\', false, false); ';
- }
-
- // Relative path, remove root path from it
- $filename = substr($filename, strlen($this->phpbb_root_path));
- return ' $_template->_js_include(\'' . addslashes($filename) . '\', false, true); ';
- }
-
- /**
- * Generates a reference to the given variable inside the given (possibly nested)
- * block namespace. This is a string of the form:
- * ' . $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . '
- * It's ready to be inserted into an "echo" line in one of the templates.
- *
- * @param string $namespace Namespace to access (expects a trailing "." on the namespace)
- * @param string $varname Variable name to use
- * @param bool $expr Returns whether the source was an expression type
- * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable
- * @return string Code to access variable or echo it if $echo is true
- */
- private function generate_block_varref($namespace, $varname, &$expr, $defop = false)
- {
- // Strip the trailing period.
- $namespace = substr($namespace, 0, -1);
-
- if (($pos = strrpos($namespace, '.')) !== false)
- {
- $local_namespace = substr($namespace, $pos + 1);
- }
- else
- {
- $local_namespace = $namespace;
- }
-
- $expr = true;
-
- // S_ROW_COUNT is deceptive, it returns the current row number now the number of rows
- // hence S_ROW_COUNT is deprecated in favour of S_ROW_NUM
- switch ($varname)
- {
- case 'S_ROW_NUM':
- case 'S_ROW_COUNT':
- $varref = "\$_${local_namespace}_i";
- break;
-
- case 'S_NUM_ROWS':
- $varref = "\$_${local_namespace}_count";
- break;
-
- case 'S_FIRST_ROW':
- $varref = "(\$_${local_namespace}_i == 0)";
- break;
-
- case 'S_LAST_ROW':
- $varref = "(\$_${local_namespace}_i == \$_${local_namespace}_count - 1)";
- break;
-
- case 'S_BLOCK_NAME':
- $varref = "'$local_namespace'";
- break;
-
- default:
- // Get a reference to the data block for this namespace.
- $varref = $this->generate_block_data_ref($namespace, true, $defop);
- // Prepend the necessary code to stick this in an echo line.
-
- // Append the variable reference.
- $varref .= "['$varname']";
-
- $expr = false;
- break;
- }
- // @todo Test the !$expr more
-
- return $varref;
- }
-
- /**
- * Generates a reference to the array of data values for the given
- * (possibly nested) block namespace. This is a string of the form:
- * $_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN']
- *
- * @param string $blockname Block to access (does not expect a trailing "." on the blockname)
- * @param bool $include_last_iterator If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above.
- * @param bool $defop If true this is a variable created with the DEFINE construct, otherwise template variable
- * @return string Code to access variable
- */
- private function generate_block_data_ref($blockname, $include_last_iterator, $defop = false)
- {
- // Get an array of the blocks involved.
- $blocks = explode('.', $blockname);
- $blockcount = sizeof($blocks) - 1;
-
- // DEFINE is not an element of any referenced variable, we must use _tpldata to access it
- if ($defop)
- {
- $varref = '$_tpldata[\'DEFINE\']';
- // Build up the string with everything but the last child.
- for ($i = 0; $i < $blockcount; $i++)
- {
- $varref .= "['" . $blocks[$i] . "'][\$_" . $blocks[$i] . '_i]';
- }
- // Add the block reference for the last child.
- $varref .= "['" . $blocks[$blockcount] . "']";
- // Add the iterator for the last child if requried.
- if ($include_last_iterator)
- {
- $varref .= '[$_' . $blocks[$blockcount] . '_i]';
- }
- return $varref;
- }
- else if ($include_last_iterator)
- {
- return '$_'. $blocks[$blockcount] . '_val';
- }
- else
- {
- return '$_'. $blocks[$blockcount - 1] . '_val[\''. $blocks[$blockcount]. '\']';
- }
- }
-}
diff --git a/phpBB/includes/template/locator.php b/phpBB/includes/template/locator.php
deleted file mode 100644
index 42db91efb2..0000000000
--- a/phpBB/includes/template/locator.php
+++ /dev/null
@@ -1,163 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-
-/**
-* Resource locator interface.
-*
-* Objects implementing this interface maintain mapping from template handles
-* to source template file paths and locate templates.
-*
-* Locates style files.
-*
-* Resource locator is aware of styles tree, and can return actual
-* filesystem paths (i.e., the "child" style or the "parent" styles)
-* depending on what files exist.
-*
-* Root paths stored in locator are paths to style directories. Templates are
-* stored in subdirectory that $template_path points to.
-*
-* @package phpBB3
-*/
-interface phpbb_template_locator
-{
- /**
- * Sets the template filenames for handles. $filename_array
- * should be a hash of handle => filename pairs.
- *
- * @param array $filname_array Should be a hash of handle => filename pairs.
- */
- public function set_filenames(array $filename_array);
-
- /**
- * Determines the filename for a template handle.
- *
- * The filename comes from array used in a set_filenames call,
- * which should have been performed prior to invoking this function.
- * Return value is a file basename (without path).
- *
- * @param $handle string Template handle
- * @return string Filename corresponding to the template handle
- */
- public function get_filename_for_handle($handle);
-
- /**
- * Determines the source file path for a template handle without
- * regard for styles tree.
- *
- * This function returns the path in "primary" style directory
- * corresponding to the given template handle. That path may or
- * may not actually exist on the filesystem. Because this function
- * does not perform stat calls to determine whether the path it
- * returns actually exists, it is faster than get_source_file_for_handle.
- *
- * Use get_source_file_for_handle to obtain the actual path that is
- * guaranteed to exist (which might come from the parent style
- * directory if primary style has parent styles).
- *
- * This function will trigger an error if the handle was never
- * associated with a template file via set_filenames.
- *
- * @param $handle string Template handle
- * @return string Path to source file path in primary style directory
- */
- public function get_virtual_source_file_for_handle($handle);
-
- /**
- * Determines the source file path for a template handle, accounting
- * for styles tree and verifying that the path exists.
- *
- * This function returns the actual path that may be compiled for
- * the specified template handle. It will trigger an error if
- * the template handle was never associated with a template path
- * via set_filenames or if the template file does not exist on the
- * filesystem.
- *
- * Use get_virtual_source_file_for_handle to just resolve a template
- * handle to a path without any filesystem or styles tree checks.
- *
- * @param string $handle Template handle (i.e. "friendly" template name)
- * @param bool $find_all If true, each root path will be checked and function
- * will return array of files instead of string and will not
- * trigger a error if template does not exist
- * @return string Source file path
- */
- public function get_source_file_for_handle($handle, $find_all = false);
-
- /**
- * Obtains a complete filesystem path for a file in a style.
- *
- * This function traverses the style tree (selected style and
- * its parents in order, if inheritance is being used) and finds
- * the first file on the filesystem matching specified relative path,
- * or the first of the specified paths if more than one path is given.
- *
- * This function can be used to determine filesystem path of any
- * file under any style, with the consequence being that complete
- * relative to the style directory path must be provided as an argument.
- *
- * In particular, this function can be used to locate templates
- * and javascript files.
- *
- * For locating templates get_first_template_location should be used
- * as it prepends the configured template path to the template basename.
- *
- * Note: "selected style" is whatever style the style resource locator
- * is configured for.
- *
- * The return value then will be a path, relative to the current
- * directory or absolute, to the first existing file in the selected
- * style or its closest parent.
- *
- * If the selected style does not have the file being searched,
- * (and if inheritance is involved, none of the parents have it either),
- * false will be returned.
- *
- * Multiple files can be specified, in which case the first file in
- * the list that can be found on the filesystem is returned.
- *
- * If multiple files are specified and inheritance is involved,
- * first each of the specified files is checked in the selected style,
- * then each of the specified files is checked in the immediate parent,
- * etc.
- *
- * Specifying true for $return_default will cause the function to
- * return the first path which was checked for existence in the event
- * that the template file was not found, instead of false.
- * This is always a path in the selected style itself, not any of its
- * parents.
- *
- * If $return_full_path is false, then instead of returning a usable
- * path (when the file is found) the file's path relative to the style
- * directory will be returned. This is the same path as was given to
- * the function as a parameter. This can be used to check which of the
- * files specified in $files exists. Naturally this requires passing
- * more than one file in $files.
- *
- * @param array $files List of files to locate.
- * @param bool $return_default Determines what to return if file does not
- * exist. If true, function will return location where file is
- * supposed to be. If false, function will return false.
- * @param bool $return_full_path If true, function will return full path
- * to file. If false, function will return file name. This
- * parameter can be used to check which one of set of files
- * is available.
- * @return string or boolean Source file path if file exists or $return_default is
- * true. False if file does not exist and $return_default is false
- */
- public function get_first_file_location($files, $return_default = false, $return_full_path = true);
-}
diff --git a/phpBB/includes/template/renderer.php b/phpBB/includes/template/renderer.php
deleted file mode 100644
index 30e234a733..0000000000
--- a/phpBB/includes/template/renderer.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Template renderer interface.
-*
-* Objects implementing this interface encapsulate a means of displaying
-* a template.
-*
-* @package phpBB3
-*/
-interface phpbb_template_renderer
-{
- /**
- * Displays the template managed by this renderer.
- *
- * @param phpbb_template_context $context Template context to use
- * @param array $lang Language entries to use
- */
- public function render($context, $lang);
-}
diff --git a/phpBB/includes/template/renderer_eval.php b/phpBB/includes/template/renderer_eval.php
deleted file mode 100644
index f8e4cb7b10..0000000000
--- a/phpBB/includes/template/renderer_eval.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Template renderer that stores compiled template's php code and
-* displays it via eval.
-*
-* @package phpBB3
-*/
-class phpbb_template_renderer_eval implements phpbb_template_renderer
-{
- /**
- * Template code to be eval'ed.
- */
- private $code;
-
- /**
- * Constructor. Stores provided code for future evaluation.
- * Template includes are delegated to template object $template.
- *
- * @param string $code php code of the template
- * @param phpbb_template $template template object
- */
- public function __construct($code, $template)
- {
- $this->code = $code;
- $this->template = $template;
- }
-
- /**
- * Displays the template managed by this renderer by eval'ing php code
- * of the template.
- *
- * @param phpbb_template_context $context Template context to use
- * @param array $lang Language entries to use
- */
- public function render($context, $lang)
- {
- $_template = $this->template;
- $_tpldata = &$context->get_data_ref();
- $_rootref = &$context->get_root_ref();
- $_lang = $lang;
-
- eval(' ?>' . $this->code . '<?php ');
- }
-}
diff --git a/phpBB/includes/template/renderer_include.php b/phpBB/includes/template/renderer_include.php
deleted file mode 100644
index f5c9026abf..0000000000
--- a/phpBB/includes/template/renderer_include.php
+++ /dev/null
@@ -1,60 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2011 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-
-/**
-* Template renderer that stores path to php file with template code
-* and displays it by including the file.
-*
-* @package phpBB3
-*/
-class phpbb_template_renderer_include implements phpbb_template_renderer
-{
- /**
- * Template path to be included.
- */
- private $path;
-
- /**
- * Constructor. Stores path to the template for future inclusion.
- * Template includes are delegated to template object $template.
- *
- * @param string $path path to the template
- */
- public function __construct($path, $template)
- {
- $this->path = $path;
- $this->template = $template;
- }
-
- /**
- * Displays the template managed by this renderer by including
- * the php file containing the template.
- *
- * @param phpbb_template_context $context Template context to use
- * @param array $lang Language entries to use
- */
- public function render($context, $lang)
- {
- $_template = $this->template;
- $_tpldata = &$context->get_data_ref();
- $_rootref = &$context->get_root_ref();
- $_lang = $lang;
-
- include($this->path);
- }
-}
diff --git a/phpBB/includes/template/template.php b/phpBB/includes/template/template.php
deleted file mode 100644
index 5396ddbfad..0000000000
--- a/phpBB/includes/template/template.php
+++ /dev/null
@@ -1,484 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2005 phpBB Group, sections (c) 2001 ispi of Lincoln Inc
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* @todo
-* IMG_ for image substitution?
-* {IMG_[key]:[alt]:[type]}
-* {IMG_ICON_CONTACT:CONTACT:full} -> $user->img('icon_contact', 'CONTACT', 'full');
-*
-* More in-depth...
-* yadayada
-*/
-
-/**
-* Base Template class.
-* @package phpBB3
-*/
-class phpbb_template
-{
- /**
- * Template context.
- * Stores template data used during template rendering.
- * @var phpbb_template_context
- */
- private $context;
-
- /**
- * Path of the cache directory for the template
- * @var string
- */
- public $cachepath = '';
-
- /**
- * phpBB root path
- * @var string
- */
- private $phpbb_root_path;
-
- /**
- * PHP file extension
- * @var string
- */
- private $php_ext;
-
- /**
- * phpBB config instance
- * @var phpbb_config
- */
- private $config;
-
- /**
- * Current user
- * @var phpbb_user
- */
- private $user;
-
- /**
- * Template locator
- * @var phpbb_template_locator
- */
- private $locator;
-
- /**
- * Constructor.
- *
- * @param string $phpbb_root_path phpBB root path
- * @param user $user current user
- * @param phpbb_template_locator $locator template locator
- * @param phpbb_template_context $context template context
- */
- public function __construct($phpbb_root_path, $php_ext, $config, $user, phpbb_template_locator $locator, phpbb_template_context $context)
- {
- $this->phpbb_root_path = $phpbb_root_path;
- $this->php_ext = $php_ext;
- $this->config = $config;
- $this->user = $user;
- $this->locator = $locator;
- $this->context = $context;
- }
-
- /**
- * Sets the template filenames for handles.
- *
- * @param array $filname_array Should be a hash of handle => filename pairs.
- */
- public function set_filenames(array $filename_array)
- {
- $this->locator->set_filenames($filename_array);
-
- return true;
- }
-
- /**
- * Clears all variables and blocks assigned to this template.
- */
- public function destroy()
- {
- $this->context->clear();
- }
-
- /**
- * Reset/empty complete block
- *
- * @param string $blockname Name of block to destroy
- */
- public function destroy_block_vars($blockname)
- {
- $this->context->destroy_block_vars($blockname);
- }
-
- /**
- * Display a template for provided handle.
- *
- * The template will be loaded and compiled, if necessary, first.
- *
- * This function calls hooks.
- *
- * @param string $handle Handle to display
- * @return bool True on success, false on failure
- */
- public function display($handle)
- {
- $result = $this->call_hook($handle, __FUNCTION__);
- if ($result !== false)
- {
- return $result[0];
- }
-
- return $this->load_and_render($handle);
- }
-
- /**
- * Loads a template for $handle, compiling it if necessary, and
- * renders the template.
- *
- * @param string $handle Template handle to render
- * @return bool True on success, false on failure
- */
- private function load_and_render($handle)
- {
- $renderer = $this->_tpl_load($handle);
-
- if ($renderer)
- {
- $renderer->render($this->context, $this->get_lang());
- return true;
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Calls hook if any is defined.
- *
- * @param string $handle Template handle being displayed.
- * @param string $method Method name of the caller.
- */
- private function call_hook($handle, $method)
- {
- global $phpbb_hook;
-
- if (!empty($phpbb_hook) && $phpbb_hook->call_hook(array(__CLASS__, $method), $handle, $this))
- {
- if ($phpbb_hook->hook_return(array(__CLASS__, $method)))
- {
- $result = $phpbb_hook->hook_return_result(array(__CLASS__, $method));
- return array($result);
- }
- }
-
- return false;
- }
-
- /**
- * Obtains language array.
- * This is either lang property of $user property, or if
- * it is not set an empty array.
- * @return array language entries
- */
- public function get_lang()
- {
- if (isset($this->user->lang))
- {
- $lang = $this->user->lang;
- }
- else
- {
- $lang = array();
- }
- return $lang;
- }
-
- /**
- * Display the handle and assign the output to a template variable
- * or return the compiled result.
- *
- * @param string $handle Handle to operate on
- * @param string $template_var Template variable to assign compiled handle to
- * @param bool $return_content If true return compiled handle, otherwise assign to $template_var
- * @return bool|string false on failure, otherwise if $return_content is true return string of the compiled handle, otherwise return true
- */
- public function assign_display($handle, $template_var = '', $return_content = true)
- {
- ob_start();
- $result = $this->display($handle);
- $contents = ob_get_clean();
- if ($result === false)
- {
- return false;
- }
-
- if ($return_content)
- {
- return $contents;
- }
-
- $this->assign_var($template_var, $contents);
-
- return true;
- }
-
- /**
- * Obtains a template renderer for a template identified by specified
- * handle. The template renderer can display the template later.
- *
- * Template source will first be compiled into php code.
- * If template cache is writable the compiled php code will be stored
- * on filesystem and template will not be subsequently recompiled.
- * If template cache is not writable template source will be recompiled
- * every time it is needed. DEBUG define and load_tplcompile
- * configuration setting may be used to force templates to be always
- * recompiled.
- *
- * Returns an object implementing phpbb_template_renderer, or null
- * if template loading or compilation failed. Call render() on the
- * renderer to display the template. This will result in template
- * contents sent to the output stream (unless, of course, output
- * buffering is in effect).
- *
- * @param string $handle Handle of the template to load
- * @return phpbb_template_renderer Template renderer object, or null on failure
- * @uses phpbb_template_compile is used to compile template source
- */
- private function _tpl_load($handle)
- {
- $output_file = $this->_compiled_file_for_handle($handle);
-
- $recompile = defined('DEBUG') ||
- !file_exists($output_file) ||
- @filesize($output_file) === 0;
-
- if ($recompile || $this->config['load_tplcompile'])
- {
- // Set only if a recompile or an mtime check are required.
- $source_file = $this->locator->get_source_file_for_handle($handle);
-
- if (!$recompile && @filemtime($output_file) < @filemtime($source_file))
- {
- $recompile = true;
- }
- }
-
- // Recompile page if the original template is newer, otherwise load the compiled version
- if (!$recompile)
- {
- return new phpbb_template_renderer_include($output_file, $this);
- }
-
- $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->locator, $this->phpbb_root_path);
-
- if ($compile->compile_file_to_file($source_file, $output_file) !== false)
- {
- $renderer = new phpbb_template_renderer_include($output_file, $this);
- }
- else if (($code = $compile->compile_file($source_file)) !== false)
- {
- $renderer = new phpbb_template_renderer_eval($code, $this);
- }
- else
- {
- $renderer = null;
- }
-
- return $renderer;
- }
-
- /**
- * Determines compiled file path for handle $handle.
- *
- * @param string $handle Template handle (i.e. "friendly" template name)
- * @return string Compiled file path
- */
- private function _compiled_file_for_handle($handle)
- {
- $source_file = $this->locator->get_filename_for_handle($handle);
- $compiled_file = $this->cachepath . str_replace('/', '.', $source_file) . '.' . $this->php_ext;
- return $compiled_file;
- }
-
- /**
- * Assign key variable pairs from an array
- *
- * @param array $vararray A hash of variable name => value pairs
- */
- public function assign_vars(array $vararray)
- {
- foreach ($vararray as $key => $val)
- {
- $this->assign_var($key, $val);
- }
- }
-
- /**
- * Assign a single scalar value to a single key.
- *
- * Value can be a string, an integer or a boolean.
- *
- * @param string $varname Variable name
- * @param string $varval Value to assign to variable
- */
- public function assign_var($varname, $varval)
- {
- $this->context->assign_var($varname, $varval);
- }
-
- /**
- * Append text to the string value stored in a key.
- *
- * Text is appended using the string concatenation operator (.).
- *
- * @param string $varname Variable name
- * @param string $varval Value to append to variable
- */
- public function append_var($varname, $varval)
- {
- $this->context->append_var($varname, $varval);
- }
-
- // Docstring is copied from phpbb_template_context method with the same name.
- /**
- * Assign key variable pairs from an array to a specified block
- * @param string $blockname Name of block to assign $vararray to
- * @param array $vararray A hash of variable name => value pairs
- */
- public function assign_block_vars($blockname, array $vararray)
- {
- return $this->context->assign_block_vars($blockname, $vararray);
- }
-
- // Docstring is copied from phpbb_template_context method with the same name.
- /**
- * Change already assigned key variable pair (one-dimensional - single loop entry)
- *
- * An example of how to use this function:
- * {@example alter_block_array.php}
- *
- * @param string $blockname the blockname, for example 'loop'
- * @param array $vararray the var array to insert/add or merge
- * @param mixed $key Key to search for
- *
- * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position]
- *
- * int: Position [the position to change or insert at directly given]
- *
- * If key is false the position is set to 0
- * If key is true the position is set to the last entry
- *
- * @param string $mode Mode to execute (valid modes are 'insert' and 'change')
- *
- * If insert, the vararray is inserted at the given position (position counting from zero).
- * If change, the current block gets merged with the vararray (resulting in new key/value pairs be added and existing keys be replaced by the new value).
- *
- * Since counting begins by zero, inserting at the last position will result in this array: array(vararray, last positioned array)
- * and inserting at position 1 will result in this array: array(first positioned array, vararray, following vars)
- *
- * @return bool false on error, true on success
- */
- public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert')
- {
- return $this->context->alter_block_array($blockname, $vararray, $key, $mode);
- }
-
- /**
- * Include a separate template.
- *
- * This function is marked public due to the way the template
- * implementation uses it. It is actually an implementation function
- * and should not be considered part of template class's public API.
- *
- * @param string $filename Template filename to include
- * @param bool $include True to include the file, false to just load it
- * @uses template_compile is used to compile uncached templates
- */
- public function _tpl_include($filename, $include = true)
- {
- $this->locator->set_filenames(array($filename => $filename));
-
- if (!$this->load_and_render($filename))
- {
- // trigger_error cannot be used here, as the output already started
- echo 'template->_tpl_include(): Failed including ' . htmlspecialchars($handle) . "\n";
- }
- }
-
- /**
- * Include a PHP file.
- *
- * If a relative path is passed in $filename, it is considered to be
- * relative to board root ($phpbb_root_path). Absolute paths are
- * also allowed.
- *
- * This function is marked public due to the way the template
- * implementation uses it. It is actually an implementation function
- * and should not be considered part of template class's public API.
- *
- * @param string $filename Path to PHP file to include
- */
- public function _php_include($filename)
- {
- if (phpbb_is_absolute($filename))
- {
- $file = $filename;
- }
- else
- {
- $file = $this->phpbb_root_path . $filename;
- }
-
- if (!file_exists($file))
- {
- // trigger_error cannot be used here, as the output already started
- echo 'template->_php_include(): File ' . htmlspecialchars($file) . " does not exist\n";
- return;
- }
- include($file);
- }
-
- /**
- * Include JS file
- *
- * @param string $file file name
- * @param bool $locate True if file needs to be located
- * @param bool $relative True if path is relative to phpBB root directory. Ignored if $locate == true
- */
- public function _js_include($file, $locate = false, $relative = false)
- {
- // Locate file
- if ($locate)
- {
- $located = $this->locator->get_first_file_location(array($file), false, true);
- if ($located)
- {
- $file = $located;
- }
- }
- else if ($relative)
- {
- $file = $this->phpbb_root_path . $file;
- }
-
- $file .= (strpos($file, '?') === false) ? '?' : '&';
- $file .= 'assets_version=' . $this->config['assets_version'];
-
- // Add HTML code
- $code = '<script src="' . htmlspecialchars($file) . '"></script>';
- $this->context->append_var('SCRIPTS', $code);
- }
-}
diff --git a/phpBB/includes/ucp/info/ucp_notifications.php b/phpBB/includes/ucp/info/ucp_notifications.php
new file mode 100644
index 0000000000..98d8b9db61
--- /dev/null
+++ b/phpBB/includes/ucp/info/ucp_notifications.php
@@ -0,0 +1,35 @@
+<?php
+/**
+*
+* @package notifications
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @package module_install
+*/
+class ucp_notifications_info
+{
+ function module()
+ {
+ return array(
+ 'filename' => 'ucp_notifications',
+ 'title' => 'UCP_NOTIFICATION_OPTIONS',
+ 'version' => '1.0.0',
+ 'modes' => array(
+ 'notification_options' => array('title' => 'UCP_NOTIFICATION_OPTIONS', 'auth' => '', 'cat' => array('UCP_PREFS')),
+ 'notification_list' => array('title' => 'UCP_NOTIFICATION_LIST', 'auth' => '', 'cat' => array('UCP_MAIN')),
+ ),
+ );
+ }
+
+ function install()
+ {
+ }
+
+ function uninstall()
+ {
+ }
+}
diff --git a/phpBB/includes/ucp/info/ucp_profile.php b/phpBB/includes/ucp/info/ucp_profile.php
index 3581a7f533..e974cea713 100644
--- a/phpBB/includes/ucp/info/ucp_profile.php
+++ b/phpBB/includes/ucp/info/ucp_profile.php
@@ -21,7 +21,7 @@ class ucp_profile_info
'modes' => array(
'profile_info' => array('title' => 'UCP_PROFILE_PROFILE_INFO', 'auth' => 'acl_u_chgprofileinfo', 'cat' => array('UCP_PROFILE')),
'signature' => array('title' => 'UCP_PROFILE_SIGNATURE', 'auth' => 'acl_u_sig', 'cat' => array('UCP_PROFILE')),
- 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => 'cfg_allow_avatar && (cfg_allow_avatar_local || cfg_allow_avatar_remote || cfg_allow_avatar_upload || cfg_allow_avatar_remote_upload)', 'cat' => array('UCP_PROFILE')),
+ 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => 'cfg_allow_avatar', 'cat' => array('UCP_PROFILE')),
'reg_details' => array('title' => 'UCP_PROFILE_REG_DETAILS', 'auth' => '', 'cat' => array('UCP_PROFILE')),
'autologin_keys'=> array('title' => 'UCP_PROFILE_AUTOLOGIN_KEYS', 'auth' => '', 'cat' => array('UCP_PROFILE')),
),
diff --git a/phpBB/includes/ucp/ucp_activate.php b/phpBB/includes/ucp/ucp_activate.php
index a0d0baf10f..898dacd831 100644
--- a/phpBB/includes/ucp/ucp_activate.php
+++ b/phpBB/includes/ucp/ucp_activate.php
@@ -50,7 +50,7 @@ class ucp_activate
trigger_error('ALREADY_ACTIVATED');
}
- if (($user_row['user_inactive_reason'] == INACTIVE_MANUAL) || $user_row['user_actkey'] != $key)
+ if ($user_row['user_inactive_reason'] == INACTIVE_MANUAL || $user_row['user_actkey'] !== $key)
{
trigger_error('WRONG_ACTIVATION');
}
@@ -114,7 +114,7 @@ class ucp_activate
$messenger->template('admin_welcome_activated', $user_row['user_lang']);
- $messenger->to($user_row['user_email'], $user_row['username']);
+ $messenger->set_addresses($user_row);
$messenger->anti_abuse_headers($config, $user);
diff --git a/phpBB/includes/ucp/ucp_groups.php b/phpBB/includes/ucp/ucp_groups.php
index 9652986cf2..8620e33e47 100644
--- a/phpBB/includes/ucp/ucp_groups.php
+++ b/phpBB/includes/ucp/ucp_groups.php
@@ -25,9 +25,9 @@ class ucp_groups
function main($id, $mode)
{
- global $config, $phpbb_root_path, $phpEx;
+ global $config, $phpbb_root_path, $phpEx, $phpbb_admin_path;
global $db, $user, $auth, $cache, $template;
- global $request;
+ global $request, $phpbb_container;
$user->add_lang('groups');
@@ -212,8 +212,7 @@ class ucp_groups
{
$messenger->template('group_request', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($row['username']),
@@ -417,9 +416,11 @@ class ucp_groups
if ($group_id)
{
- $sql = 'SELECT *
- FROM ' . GROUPS_TABLE . "
- WHERE group_id = $group_id";
+ $sql = 'SELECT g.*, t.teampage_position AS group_teampage
+ FROM ' . GROUPS_TABLE . ' g
+ LEFT JOIN ' . TEAMPAGE_TABLE . ' t
+ ON (t.group_id = g.group_id)
+ WHERE g.group_id = ' . $group_id;
$result = $db->sql_query($sql);
$group_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
@@ -438,7 +439,7 @@ class ucp_groups
$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') : '<img src="' . $phpbb_root_path . 'adm/images/no_avatar.gif" alt="" />';
+ $avatar = phpbb_get_group_avatar($group_row, 'GROUP_AVATAR', true);
$template->assign_vars(array(
'GROUP_NAME' => ($group_type == GROUP_SPECIAL) ? $user->lang['G_' . $group_name] : $group_name,
@@ -447,8 +448,8 @@ class ucp_groups
'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' => (empty($avatar) ? '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />' : $avatar),
+ 'AVATAR_IMAGE' => (empty($avatar) ? '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />' : $avatar),
'AVATAR_WIDTH' => (isset($group_row['group_avatar_width'])) ? $group_row['group_avatar_width'] : '',
'AVATAR_HEIGHT' => (isset($group_row['group_avatar_height'])) ? $group_row['group_avatar_height'] : '',
));
@@ -483,10 +484,20 @@ class ucp_groups
$error = array();
- $avatar_select = basename(request_var('avatar_select', ''));
- $category = basename(request_var('category', ''));
+ // Setup avatar data for later
+ $avatars_enabled = false;
+ $avatar_drivers = null;
+ $avatar_data = null;
+ $avatar_error = array();
+
+ if ($config['allow_avatar'])
+ {
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers();
- $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false;
+ // This is normalised data, without the group_ prefix
+ $avatar_data = phpbb_avatar_manager::clean_row($group_row);
+ }
// Did we submit?
if ($update)
@@ -505,90 +516,44 @@ class ucp_groups
'receive_pm' => isset($_REQUEST['group_receive_pm']) ? 1 : 0,
'message_limit' => request_var('group_message_limit', 0),
'max_recipients'=> request_var('group_max_recipients', 0),
+ 'legend' => $group_row['group_legend'],
+ 'teampage' => $group_row['group_teampage'],
);
- $data['uploadurl'] = request_var('uploadurl', '');
- $data['remotelink'] = request_var('remotelink', '');
- $data['width'] = request_var('width', '');
- $data['height'] = request_var('height', '');
- $delete = request_var('delete', '');
-
- $uploadfile = $request->file('uploadfile');
- if (!empty($uploadfile['tmp_name']) || $data['uploadurl'] || $data['remotelink'])
+ if ($config['allow_avatar'])
{
- // Avatar stuff
- $var_ary = array(
- 'uploadurl' => array('string', true, 5, 255),
- 'remotelink' => array('string', true, 5, 255),
- 'width' => array('string', true, 1, 3),
- 'height' => array('string', true, 1, 3),
- );
+ // Handle avatar
+ $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', ''));
+ $config_name = preg_replace('#^avatar\.driver.#', '', $driver_name);
- if (!($error = validate_data($data, $var_ary)))
+ if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete'))
{
- $data['user_id'] = "g$group_id";
+ $driver = $phpbb_avatar_manager->get_driver($driver_name);
+ $result = $driver->process_form($request, $template, $user, $avatar_data, $avatar_error);
- if ((!empty($uploadfile['tmp_name']) || $data['uploadurl']) && $can_upload)
+ if ($result && empty($avatar_error))
{
- list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_upload($data, $error);
- }
- else if ($data['remotelink'])
- {
- list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_remote($data, $error);
- }
- }
- }
- else if ($avatar_select && $config['allow_avatar_local'])
- {
- // check avatar gallery
- if (is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category))
- {
- $submit_ary['avatar_type'] = AVATAR_GALLERY;
+ $result['avatar_type'] = $driver_name;
- list($submit_ary['avatar_width'], $submit_ary['avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . $avatar_select);
- $submit_ary['avatar'] = $category . '/' . $avatar_select;
- }
- }
- else if ($delete)
- {
- $submit_ary['avatar'] = '';
- $submit_ary['avatar_type'] = $submit_ary['avatar_width'] = $submit_ary['avatar_height'] = 0;
- }
- else if ($data['width'] && $data['height'])
- {
- // Only update the dimensions?
- if ($config['avatar_max_width'] || $config['avatar_max_height'])
- {
- if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
+ $submit_ary = array_merge($submit_ary, $result);
}
}
-
- if (!sizeof($error))
+ else
{
- if ($config['avatar_min_width'] || $config['avatar_min_height'])
+ if ($driver = $phpbb_avatar_manager->get_driver($user->data['user_avatar_type']))
{
- if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
- }
+ $driver->delete($avatar_data);
}
- }
- if (!sizeof($error))
- {
- $submit_ary['avatar_width'] = $data['width'];
- $submit_ary['avatar_height'] = $data['height'];
+ // Removing the avatar
+ $submit_ary['avatar_type'] = '';
+ $submit_ary['avatar'] = '';
+ $submit_ary['avatar_width'] = 0;
+ $submit_ary['avatar_height'] = 0;
}
- }
- if ((isset($submit_ary['avatar']) && $submit_ary['avatar'] && (!isset($group_row['group_avatar']))) || $delete)
- {
- if (isset($group_row['group_avatar']) && $group_row['group_avatar'])
- {
- avatar_delete('group', $group_row, true);
- }
+ // Merge any avatars errors into the primary error array
+ $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error));
}
if (!check_form_key('ucp_groups'))
@@ -596,29 +561,40 @@ class ucp_groups
$error[] = $user->lang['FORM_INVALID'];
}
+ // Validate submitted colour value
+ if ($colour_error = validate_data($submit_ary, array('colour' => array('hex_colour', true))))
+ {
+ // Replace "error" string with its real, localised form
+ $error = array_merge($error, $colour_error);
+ }
+
if (!sizeof($error))
{
// 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.
+ // However there are some attributes that need to be set everytime,
+ // otherwise the group gets removed from the feature.
+ $set_attributes = array('legend', 'teampage');
$group_attributes = array();
$test_variables = array(
'rank' => 'int',
'colour' => 'string',
'avatar' => 'string',
- 'avatar_type' => 'int',
+ 'avatar_type' => 'string',
'avatar_width' => 'int',
'avatar_height' => 'int',
'receive_pm' => 'int',
'legend' => 'int',
+ 'teampage' => 'int',
'message_limit' => 'int',
'max_recipients'=> 'int',
);
foreach ($test_variables as $test => $type)
{
- if (isset($submit_ary[$test]) && ($action == 'add' || $group_row['group_' . $test] != $submit_ary[$test]))
+ if (isset($submit_ary[$test]) && ($action == 'add' || $group_row['group_' . $test] != $submit_ary[$test] || isset($group_attributes['group_avatar']) && strpos($test, 'avatar') === 0 || in_array($test, $set_attributes)))
{
settype($submit_ary[$test], $type);
$group_attributes['group_' . $test] = $group_row['group_' . $test] = $submit_ary[$test];
@@ -628,6 +604,7 @@ class ucp_groups
if (!($error = group_create($group_id, $group_type, $group_name, $group_desc, $group_attributes, $allow_desc_bbcode, $allow_desc_urls, $allow_desc_smilies)))
{
$cache->destroy('sql', GROUPS_TABLE);
+ $cache->destroy('sql', TEAMPAGE_TABLE);
$message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED';
trigger_error($user->lang[$message] . $return_page);
@@ -636,6 +613,7 @@ class ucp_groups
if (sizeof($error))
{
+ $error = array_map(array(&$user, 'lang'), $error);
$group_rank = $submit_ary['rank'];
$group_desc_data = array(
@@ -683,28 +661,51 @@ class ucp_groups
$type_closed = ($group_type == GROUP_CLOSED) ? ' checked="checked"' : '';
$type_hidden = ($group_type == GROUP_HIDDEN) ? ' checked="checked"' : '';
- $display_gallery = (isset($_POST['display_gallery'])) ? true : false;
-
- if ($config['allow_avatar'] && $config['allow_avatar_local'] && $display_gallery)
+ // Load up stuff for avatars
+ if ($config['allow_avatar'])
{
- avatar_gallery($category, $avatar_select, 4);
+ $avatars_enabled = false;
+ $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $avatar_data['avatar_type']));
+
+ foreach ($avatar_drivers as $current_driver)
+ {
+ $driver = $phpbb_avatar_manager->get_driver($current_driver);
+
+ $avatars_enabled = true;
+ $template->set_filenames(array(
+ 'avatar' => $driver->get_template_name(),
+ ));
+
+ if ($driver->prepare_form($request, $template, $user, $avatar_data, $avatar_error))
+ {
+ $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver);
+ $driver_upper = strtoupper($driver_name);
+ $template->assign_block_vars('avatar_drivers', array(
+ 'L_TITLE' => $user->lang($driver_upper . '_TITLE'),
+ 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'),
+
+ 'DRIVER' => $driver_name,
+ 'SELECTED' => $current_driver == $selected_driver,
+ 'OUTPUT' => $template->assign_display('avatar'),
+ ));
+ }
+ }
}
- $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;
+ if (isset($phpbb_avatar_manager) && !$update)
+ {
+ // Merge any avatars errors into the primary error array
+ $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error));
+ }
$template->assign_vars(array(
'S_EDIT' => true,
'S_INCLUDE_SWATCH' => true,
- 'S_FORM_ENCTYPE' => ($config['allow_avatar'] && $can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) ? ' enctype="multipart/form-data"' : '',
+ 'S_FORM_ENCTYPE' => ' 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'] && $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_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
+ 'S_GROUP_MANAGE' => true,
'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
'GROUP_RECEIVE_PM' => (isset($group_row['group_receive_pm']) && $group_row['group_receive_pm']) ? ' checked="checked"' : '',
@@ -717,7 +718,6 @@ class ucp_groups
'S_DESC_SMILIES_CHECKED'=> $group_desc_data['allow_smilies'],
'S_RANK_OPTIONS' => $rank_options,
- 'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'],
'GROUP_TYPE_FREE' => GROUP_FREE,
'GROUP_TYPE_OPEN' => GROUP_OPEN,
@@ -730,7 +730,7 @@ class ucp_groups
'GROUP_CLOSED' => $type_closed,
'GROUP_HIDDEN' => $type_hidden,
- 'U_SWATCH' => append_sid("{$phpbb_root_path}adm/swatch.$phpEx", 'form=ucp&amp;name=group_colour'),
+ 'U_SWATCH' => append_sid("{$phpbb_admin_path}swatch.$phpEx", 'form=ucp&amp;name=group_colour'),
'S_UCP_ACTION' => $this->u_action . "&amp;action=$action&amp;g=$group_id",
'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(),
));
diff --git a/phpBB/includes/ucp/ucp_main.php b/phpBB/includes/ucp/ucp_main.php
index 94fd59433b..615b567134 100644
--- a/phpBB/includes/ucp/ucp_main.php
+++ b/phpBB/includes/ucp/ucp_main.php
@@ -642,7 +642,7 @@ class ucp_main
*/
function assign_topiclist($mode = 'subscribed', $forbidden_forum_ary = array())
{
- global $user, $db, $template, $config, $cache, $auth, $phpbb_root_path, $phpEx;
+ global $user, $db, $template, $config, $cache, $auth, $phpbb_root_path, $phpEx, $phpbb_container;
$table = ($mode == 'subscribed') ? TOPICS_WATCH_TABLE : BOOKMARKS_TABLE;
$start = request_var('start', 0);
@@ -768,6 +768,8 @@ class ucp_main
}
}
+ $phpbb_content_visibility = $phpbb_container->get('content.visibility');
+
foreach ($topic_list as $topic_id)
{
$row = &$rowset[$topic_id];
@@ -778,7 +780,7 @@ class ucp_main
$unread_topic = (isset($topic_tracking_info[$topic_id]) && $row['topic_last_post_time'] > $topic_tracking_info[$topic_id]) ? true : false;
// Replies
- $replies = ($auth->acl_get('m_approve', $forum_id)) ? $row['topic_replies_real'] : $row['topic_replies'];
+ $replies = $phpbb_content_visibility->get_count('topic_posts', $row, $forum_id) - 1;
if ($row['topic_status'] == ITEM_MOVED && !empty($row['topic_moved_id']))
{
diff --git a/phpBB/includes/ucp/ucp_notifications.php b/phpBB/includes/ucp/ucp_notifications.php
new file mode 100644
index 0000000000..72c41776b3
--- /dev/null
+++ b/phpBB/includes/ucp/ucp_notifications.php
@@ -0,0 +1,230 @@
+<?php
+/**
+*
+* @package notifications
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+class ucp_notifications
+{
+ public $u_action;
+
+ public function main($id, $mode)
+ {
+ global $config, $template, $user, $request, $phpbb_container;
+ global $phpbb_root_path, $phpEx;
+
+ add_form_key('ucp_notification');
+
+ $start = $request->variable('start', 0);
+ $form_time = min($request->variable('form_time', 0), time());
+
+ $phpbb_notifications = $phpbb_container->get('notification_manager');
+
+ switch ($mode)
+ {
+ case 'notification_options':
+ $subscriptions = $phpbb_notifications->get_global_subscriptions(false);
+
+ // Add/remove subscriptions
+ if ($request->is_set_post('submit'))
+ {
+ if (!check_form_key('ucp_notification'))
+ {
+ trigger_error('FORM_INVALID');
+ }
+
+ $notification_methods = $phpbb_notifications->get_subscription_methods();
+
+ foreach($phpbb_notifications->get_subscription_types() as $group => $subscription_types)
+ {
+ foreach($subscription_types as $type => $data)
+ {
+ foreach($notification_methods as $method => $method_data)
+ {
+ if ($request->is_set_post($type . '_' . $method_data['id']) && (!isset($subscriptions[$type]) || !in_array($method_data['id'], $subscriptions[$type])))
+ {
+ $phpbb_notifications->add_subscription($type, 0, $method_data['id']);
+ }
+ else if (!$request->is_set_post($type . '_' . $method_data['id']) && isset($subscriptions[$type]) && in_array($method_data['id'], $subscriptions[$type]))
+ {
+ $phpbb_notifications->delete_subscription($type, 0, $method_data['id']);
+ }
+ }
+
+ if ($request->is_set_post($type . '_notification') && !isset($subscriptions[$type]))
+ {
+ $phpbb_notifications->add_subscription($type);
+ }
+ else if (!$request->is_set_post($type . '_notification') && isset($subscriptions[$type]))
+ {
+ $phpbb_notifications->delete_subscription($type);
+ }
+ }
+ }
+
+ meta_refresh(3, $this->u_action);
+ $message = $user->lang['PREFERENCES_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
+ trigger_error($message);
+ }
+
+ $this->output_notification_methods('notification_methods', $phpbb_notifications, $template, $user);
+
+ $this->output_notification_types($subscriptions, 'notification_types', $phpbb_notifications, $template, $user);
+
+ $this->tpl_name = 'ucp_notifications';
+ $this->page_title = 'UCP_NOTIFICATION_OPTIONS';
+ break;
+
+ case 'notification_list':
+ default:
+ // Mark all items read
+ if ($request->variable('mark', '') == 'all' && (confirm_box(true) || check_link_hash($request->variable('token', ''), 'mark_all_notifications_read')))
+ {
+ if (confirm_box(true))
+ {
+ $phpbb_notifications->mark_notifications_read(false, false, $user->data['user_id'], $form_time);
+
+ meta_refresh(3, $this->u_action);
+ $message = $user->lang['NOTIFICATIONS_MARK_ALL_READ_SUCCESS'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
+ trigger_error($message);
+ }
+ else
+ {
+ confirm_box(false, 'NOTIFICATIONS_MARK_ALL_READ', build_hidden_fields(array(
+ 'mark' => 'all',
+ 'form_time' => $form_time,
+ )));
+ }
+ }
+
+ // Mark specific notifications read
+ if ($request->is_set_post('submit'))
+ {
+ if (!check_form_key('ucp_notification'))
+ {
+ trigger_error('FORM_INVALID');
+ }
+
+ $mark_read = $request->variable('mark', array(0));
+
+ if (!empty($mark_read))
+ {
+ $phpbb_notifications->mark_notifications_read_by_id($mark_read, $form_time);
+ }
+ }
+
+ $notifications = $phpbb_notifications->load_notifications(array(
+ 'start' => $start,
+ 'limit' => $config['topics_per_page'],
+ 'count_total' => true,
+ ));
+
+ foreach ($notifications['notifications'] as $notification)
+ {
+ $template->assign_block_vars('notification_list', $notification->prepare_for_display());
+ }
+
+ $base_url = append_sid("{$phpbb_root_path}ucp.$phpEx", "i=ucp_notifications&amp;mode=notification_list");
+ phpbb_generate_template_pagination($template, $base_url, 'pagination', 'start', $notifications['total_count'], $config['topics_per_page'], $start);
+
+ $template->assign_vars(array(
+ 'PAGE_NUMBER' => phpbb_on_page($template, $user, $base_url, $notifications['total_count'], $config['topics_per_page'], $start),
+ 'TOTAL_COUNT' => $user->lang('NOTIFICATIONS_COUNT', $notifications['total_count']),
+ 'U_MARK_ALL' => $base_url . '&amp;mark=all&amp;token=' . generate_link_hash('mark_all_notifications_read'),
+ ));
+
+ $this->tpl_name = 'ucp_notifications';
+ $this->page_title = 'UCP_NOTIFICATION_LIST';
+ break;
+ }
+
+ $template->assign_vars(array(
+ 'TITLE' => $user->lang($this->page_title),
+ 'TITLE_EXPLAIN' => $user->lang($this->page_title . '_EXPLAIN'),
+
+ 'MODE' => $mode,
+
+ 'FORM_TIME' => time(),
+ ));
+ }
+
+ /**
+ * Output all the notification types to the template
+ *
+ * @param string $block
+ * @param phpbb_notification_manager $phpbb_notifications
+ * @param phpbb_template $template
+ * @param phpbb_user $user
+ */
+ public function output_notification_types($subscriptions, $block = 'notification_types', phpbb_notification_manager $phpbb_notifications, phpbb_template $template, phpbb_user $user)
+ {
+ $notification_methods = $phpbb_notifications->get_subscription_methods();
+
+ foreach($phpbb_notifications->get_subscription_types() as $group => $subscription_types)
+ {
+ $template->assign_block_vars($block, array(
+ 'GROUP_NAME' => $user->lang($group),
+ ));
+
+ foreach($subscription_types as $type => $data)
+ {
+ $template->assign_block_vars($block, array(
+ 'TYPE' => $type,
+
+ 'NAME' => $user->lang($data['lang']),
+ 'EXPLAIN' => (isset($user->lang[$data['lang'] . '_EXPLAIN'])) ? $user->lang($data['lang'] . '_EXPLAIN') : '',
+
+ 'SUBSCRIBED' => (isset($subscriptions[$type])) ? true : false,
+ ));
+
+ foreach($notification_methods as $method => $method_data)
+ {
+ $template->assign_block_vars($block . '.notification_methods', array(
+ 'METHOD' => $method_data['id'],
+
+ 'NAME' => $user->lang($method_data['lang']),
+
+ 'SUBSCRIBED' => (isset($subscriptions[$type]) && in_array($method_data['id'], $subscriptions[$type])) ? true : false,
+ ));
+ }
+ }
+ }
+
+ $template->assign_vars(array(
+ strtoupper($block) . '_COLS' => sizeof($notification_methods) + 2,
+ ));
+ }
+
+ /**
+ * Output all the notification methods to the template
+ *
+ * @param string $block
+ * @param phpbb_notification_manager $phpbb_notifications
+ * @param phpbb_template $template
+ * @param phpbb_user $user
+ */
+ public function output_notification_methods($block = 'notification_methods', phpbb_notification_manager $phpbb_notifications, phpbb_template $template, phpbb_user $user)
+ {
+ $notification_methods = $phpbb_notifications->get_subscription_methods();
+
+ foreach($notification_methods as $method => $method_data)
+ {
+ $template->assign_block_vars($block, array(
+ 'METHOD' => $method_data['id'],
+
+ 'NAME' => $user->lang($method_data['lang']),
+ ));
+ }
+ }
+}
diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php
index 75b17a4a01..a1b2bb61f9 100644
--- a/phpBB/includes/ucp/ucp_pm_compose.php
+++ b/phpBB/includes/ucp/ucp_pm_compose.php
@@ -265,19 +265,16 @@ function compose_pm($id, $mode, $action, $user_folders = array())
// Passworded forum?
if ($post['forum_id'])
{
- $sql = 'SELECT forum_password
+ $sql = 'SELECT forum_id, forum_name, forum_password
FROM ' . FORUMS_TABLE . '
WHERE forum_id = ' . (int) $post['forum_id'];
$result = $db->sql_query($sql);
- $forum_password = (string) $db->sql_fetchfield('forum_password');
+ $forum_data = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- if ($forum_password)
+ if (!empty($forum_data['forum_password']))
{
- login_forum_box(array(
- 'forum_id' => $post['forum_id'],
- 'forum_password' => $forum_password,
- ));
+ login_forum_box($forum_data);
}
}
}
@@ -353,7 +350,7 @@ function compose_pm($id, $mode, $action, $user_folders = array())
$message_attachment = 0;
$message_text = $message_subject = '';
- if ($to_user_id && $action == 'post')
+ if ($to_user_id && $to_user_id != ANONYMOUS && $action == 'post')
{
$address_list['u'][$to_user_id] = 'to';
}
diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php
index c85b05f144..c7b4489daf 100644
--- a/phpBB/includes/ucp/ucp_pm_viewmessage.php
+++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php
@@ -76,17 +76,8 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
$user_info = get_user_information($author_id, $message_row);
// Parse the message and subject
- $message = censor_text($message_row['message_text']);
-
- // Second parse bbcode here
- if ($message_row['bbcode_bitfield'])
- {
- $bbcode->bbcode_second_pass($message, $message_row['bbcode_uid'], $message_row['bbcode_bitfield']);
- }
-
- // Always process smilies after parsing bbcodes
- $message = bbcode_nl2br($message);
- $message = smiley_text($message);
+ $parse_flags = ($message_row['bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
+ $message = generate_text_for_display($message_row['message_text'], $message_row['bbcode_uid'], $message_row['bbcode_bitfield'], $parse_flags, true);
// Replace naughty words such as farty pants
$message_row['message_subject'] = censor_text($message_row['message_subject']);
@@ -94,8 +85,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
// Editing information
if ($message_row['message_edit_count'] && $config['display_last_edited'])
{
- $l_edit_time_total = ($message_row['message_edit_count'] == 1) ? $user->lang['EDITED_TIME_TOTAL'] : $user->lang['EDITED_TIMES_TOTAL'];
- $l_edited_by = '<br /><br />' . sprintf($l_edit_time_total, (!$message_row['message_edit_user']) ? $message_row['username'] : $message_row['message_edit_user'], $user->format_date($message_row['message_edit_time'], false, true), $message_row['message_edit_count']);
+ $l_edited_by = '<br /><br />' . $user->lang('EDITED_TIMES_TOTAL', (int) $message_row['message_edit_count'], (!$message_row['message_edit_user']) ? $message_row['username'] : $message_row['message_edit_user'], $user->format_date($message_row['message_edit_time'], false, true));
}
else
{
@@ -161,21 +151,8 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
// End signature parsing, only if needed
if ($signature)
{
- $signature = censor_text($signature);
-
- if ($user_info['user_sig_bbcode_bitfield'])
- {
- if ($bbcode === false)
- {
- include($phpbb_root_path . 'includes/bbcode.' . $phpEx);
- $bbcode = new bbcode($user_info['user_sig_bbcode_bitfield']);
- }
-
- $bbcode->bbcode_second_pass($signature, $user_info['user_sig_bbcode_uid'], $user_info['user_sig_bbcode_bitfield']);
- }
-
- $signature = bbcode_nl2br($signature);
- $signature = smiley_text($signature);
+ $parse_flags = ($user_info['user_sig_bbcode_bitfield'] ? OPTION_FLAG_BBCODE : 0) | OPTION_FLAG_SMILIES;
+ $signature = generate_text_for_display($signature, $user_info['user_sig_bbcode_uid'], $user_info['user_sig_bbcode_bitfield'], $parse_flags, true);
}
$url = append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=pm');
@@ -371,12 +348,12 @@ function get_user_information($user_id, $user_row)
}
}
- if (!function_exists('get_user_avatar'))
+ if (!function_exists('phpbb_get_user_avatar'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
- $user_row['avatar'] = ($user->optionget('viewavatars')) ? get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']) : '';
+ $user_row['avatar'] = ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($user_row) : '';
get_user_rank($user_row['user_rank'], $user_row['user_posts'], $user_row['rank_title'], $user_row['rank_image'], $user_row['rank_image_src']);
diff --git a/phpBB/includes/ucp/ucp_prefs.php b/phpBB/includes/ucp/ucp_prefs.php
index 23892c2c8c..e80cc2dce3 100644
--- a/phpBB/includes/ucp/ucp_prefs.php
+++ b/phpBB/includes/ucp/ucp_prefs.php
@@ -26,7 +26,7 @@ class ucp_prefs
function main($id, $mode)
{
- global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx;
+ global $config, $db, $user, $auth, $template, $phpbb_dispatcher, $phpbb_root_path, $phpEx;
$submit = (isset($_POST['submit'])) ? true : false;
$error = $data = array();
@@ -46,8 +46,6 @@ class ucp_prefs
'viewemail' => request_var('viewemail', (bool) $user->data['user_allow_viewemail']),
'massemail' => request_var('massemail', (bool) $user->data['user_allow_massemail']),
'hideonline' => request_var('hideonline', (bool) !$user->data['user_allow_viewonline']),
- 'notifypm' => request_var('notifypm', (bool) $user->data['user_notify_pm']),
- 'popuppm' => request_var('popuppm', (bool) $user->optionget('popuppm')),
'allowpm' => request_var('allowpm', (bool) $user->data['user_allow_pm']),
);
@@ -57,6 +55,20 @@ class ucp_prefs
$data['notifymethod'] = NOTIFY_BOTH;
}
+ /**
+ * Add UCP edit global settings data before they are assigned to the template or submitted
+ *
+ * To assign data to the template, use $template->assign_vars()
+ *
+ * @event core.ucp_prefs_personal_data
+ * @var bool submit Do we display the form only
+ * or did the user press submit
+ * @var array data Array with current ucp options data
+ * @since 3.1-A1
+ */
+ $vars = array('submit', 'data');
+ extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_personal_data', compact($vars)));
+
if ($submit)
{
if ($config['override_user_style'])
@@ -81,15 +93,12 @@ class ucp_prefs
if (!sizeof($error))
{
- $user->optionset('popuppm', $data['popuppm']);
-
$sql_ary = array(
'user_allow_pm' => $data['allowpm'],
'user_allow_viewemail' => $data['viewemail'],
'user_allow_massemail' => $data['massemail'],
'user_allow_viewonline' => ($auth->acl_get('u_hideonline')) ? !$data['hideonline'] : $user->data['user_allow_viewonline'],
'user_notify_type' => $data['notifymethod'],
- 'user_notify_pm' => $data['notifypm'],
'user_options' => $user->data['user_options'],
'user_dateformat' => $data['dateformat'],
@@ -98,6 +107,17 @@ class ucp_prefs
'user_style' => $data['style'],
);
+ /**
+ * Update UCP edit global settings data on form submit
+ *
+ * @event core.ucp_prefs_personal_update_data
+ * @var array data Submitted display options data
+ * @var array sql_ary Display options data we udpate
+ * @since 3.1-A1
+ */
+ $vars = array('data', 'sql_ary');
+ extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_personal_update_data', compact($vars)));
+
$sql = 'UPDATE ' . USERS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
WHERE user_id = ' . $user->data['user_id'];
@@ -172,8 +192,6 @@ class ucp_prefs
'S_MASS_EMAIL' => $data['massemail'],
'S_ALLOW_PM' => $data['allowpm'],
'S_HIDE_ONLINE' => $data['hideonline'],
- 'S_NOTIFY_PM' => $data['notifypm'],
- 'S_POPUP_PM' => $data['popuppm'],
'DATE_FORMAT' => $data['dateformat'],
'A_DATE_FORMAT' => addslashes($data['dateformat']),
@@ -216,6 +234,20 @@ class ucp_prefs
'wordcensor' => request_var('wordcensor', (bool) $user->optionget('viewcensors')),
);
+ /**
+ * Add UCP edit display options data before they are assigned to the template or submitted
+ *
+ * To assign data to the template, use $template->assign_vars()
+ *
+ * @event core.ucp_prefs_view_data
+ * @var bool submit Do we display the form only
+ * or did the user press submit
+ * @var array data Array with current ucp options data
+ * @since 3.1-A1
+ */
+ $vars = array('submit', 'data');
+ extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_view_data', compact($vars)));
+
if ($submit)
{
$error = validate_data($data, array(
@@ -254,6 +286,17 @@ class ucp_prefs
'user_post_show_days' => $data['post_st'],
);
+ /**
+ * Update UCP edit display options data on form submit
+ *
+ * @event core.ucp_prefs_view_update_data
+ * @var array data Submitted display options data
+ * @var array sql_ary Display options data we udpate
+ * @since 3.1-A1
+ */
+ $vars = array('data', 'sql_ary');
+ extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_view_update_data', compact($vars)));
+
$sql = 'UPDATE ' . USERS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
WHERE user_id = ' . $user->data['user_id'];
@@ -274,7 +317,7 @@ class ucp_prefs
$limit_topic_days = array(0 => $user->lang['ALL_TOPICS'], 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_topic_text = array('a' => $user->lang['AUTHOR'], 't' => $user->lang['POST_TIME'], 'r' => $user->lang['REPLIES'], 's' => $user->lang['SUBJECT'], 'v' => $user->lang['VIEWS']);
- $sort_by_topic_sql = array('a' => 't.topic_first_poster_name', 't' => 't.topic_last_post_time', 'r' => 't.topic_replies', 's' => 't.topic_title', 'v' => 't.topic_views');
+ $sort_by_topic_sql = array('a' => 't.topic_first_poster_name', 't' => 't.topic_last_post_time', 'r' => 't.topic_posts_approved', 's' => 't.topic_title', 'v' => 't.topic_views');
// Post ordering options
$limit_post_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']);
@@ -342,6 +385,20 @@ class ucp_prefs
);
add_form_key('ucp_prefs_post');
+ /**
+ * Add UCP edit posting defaults data before they are assigned to the template or submitted
+ *
+ * To assign data to the template, use $template->assign_vars()
+ *
+ * @event core.ucp_prefs_post_data
+ * @var bool submit Do we display the form only
+ * or did the user press submit
+ * @var array data Array with current ucp options data
+ * @since 3.1-A1
+ */
+ $vars = array('submit', 'data');
+ extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_post_data', compact($vars)));
+
if ($submit)
{
if (check_form_key('ucp_prefs_post'))
@@ -355,6 +412,17 @@ class ucp_prefs
'user_notify' => $data['notify'],
);
+ /**
+ * Update UCP edit posting defaults data on form submit
+ *
+ * @event core.ucp_prefs_post_update_data
+ * @var array data Submitted display options data
+ * @var array sql_ary Display options data we udpate
+ * @since 3.1-A1
+ */
+ $vars = array('data', 'sql_ary');
+ extract($phpbb_dispatcher->trigger_event('core.ucp_prefs_post_update_data', compact($vars)));
+
$sql = 'UPDATE ' . USERS_TABLE . '
SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
WHERE user_id = ' . $user->data['user_id'];
diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php
index e7cea06a45..e55569fdd5 100644
--- a/phpBB/includes/ucp/ucp_profile.php
+++ b/phpBB/includes/ucp/ucp_profile.php
@@ -28,8 +28,9 @@ class ucp_profile
function main($id, $mode)
{
- global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx;
+ global $cache, $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx;
global $request;
+ global $phpbb_container;
$user->add_lang('posting');
@@ -174,8 +175,7 @@ class ucp_profile
while ($row = $db->sql_fetchrow($result))
{
$messenger->template('admin_activate', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($data['username']),
@@ -546,81 +546,135 @@ class ucp_profile
// Build custom bbcodes array
display_custom_bbcodes();
+ // Generate smiley listing
+ generate_smilies('inline', 0);
+
break;
case 'avatar':
+ if (!function_exists('phpbb_get_user_avatar'))
+ {
+ include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ }
- include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ add_form_key('ucp_avatar');
- $display_gallery = request_var('display_gallery', '0');
- $avatar_select = basename(request_var('avatar_select', ''));
- $category = basename(request_var('category', ''));
+ $avatars_enabled = false;
- $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_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;
+ if ($config['allow_avatar'] && $auth->acl_get('u_chgavatar'))
+ {
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers();
- add_form_key('ucp_avatar');
+ // This is normalised data, without the user_ prefix
+ $avatar_data = phpbb_avatar_manager::clean_row($user->data);
- if ($submit)
- {
- if (check_form_key('ucp_avatar'))
+ if ($submit)
{
- if (avatar_process_user($error, false, $can_upload))
+ if (check_form_key('ucp_avatar'))
{
- meta_refresh(3, $this->u_action);
- $message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
- trigger_error($message);
+ $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', ''));
+
+ if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete'))
+ {
+ $driver = $phpbb_avatar_manager->get_driver($driver_name);
+ $result = $driver->process_form($request, $template, $user, $avatar_data, $error);
+
+ if ($result && empty($error))
+ {
+ // Success! Lets save the result in the database
+ $result = array(
+ 'user_avatar_type' => $driver_name,
+ 'user_avatar' => $result['avatar'],
+ 'user_avatar_width' => $result['avatar_width'],
+ 'user_avatar_height' => $result['avatar_height'],
+ );
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $result) . '
+ WHERE user_id = ' . (int) $user->data['user_id'];
+
+ $db->sql_query($sql);
+
+ meta_refresh(3, $this->u_action);
+ $message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
+ trigger_error($message);
+ }
+ }
+ else
+ {
+ if ($driver = $phpbb_avatar_manager->get_driver($user->data['user_avatar_type']))
+ {
+ $driver->delete($avatar_data);
+ }
+
+ $result = array(
+ 'user_avatar' => '',
+ 'user_avatar_type' => '',
+ 'user_avatar_width' => 0,
+ 'user_avatar_height' => 0,
+ );
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $result) . '
+ WHERE user_id = ' . (int) $user->data['user_id'];
+
+ $db->sql_query($sql);
+
+ meta_refresh(3, $this->u_action);
+ $message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
+ trigger_error($message);
+ }
+ }
+ else
+ {
+ $error[] = 'FORM_INVALID';
}
}
- else
+
+ $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user->data['user_avatar_type']));
+
+ foreach ($avatar_drivers as $current_driver)
{
- $error[] = 'FORM_INVALID';
+ $driver = $phpbb_avatar_manager->get_driver($current_driver);
+
+ $avatars_enabled = true;
+ $template->set_filenames(array(
+ 'avatar' => $driver->get_template_name(),
+ ));
+
+ if ($driver->prepare_form($request, $template, $user, $avatar_data, $error))
+ {
+ $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver);
+ $driver_upper = strtoupper($driver_name);
+
+ $template->assign_block_vars('avatar_drivers', array(
+ 'L_TITLE' => $user->lang($driver_upper . '_TITLE'),
+ 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'),
+
+ 'DRIVER' => $driver_name,
+ 'SELECTED' => $current_driver == $selected_driver,
+ 'OUTPUT' => $template->assign_display('avatar'),
+ ));
+ }
}
- // Replace "error" strings with their real, localised form
- $error = array_map(array($user, 'lang'), $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'];
- }
+ // Replace "error" strings with their real, localised form
+ $error = $phpbb_avatar_manager->localize_errors($user, $error);
+
+ $avatar = phpbb_get_user_avatar($user->data, 'USER_AVATAR', true);
$template->assign_vars(array(
'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
- '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&amp;mode=avatar&amp;display_gallery=1'),
+ 'AVATAR' => $avatar,
- 'S_FORM_ENCTYPE' => ($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) ? ' enctype="multipart/form-data"' : '',
+ 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"',
'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(),
- ));
- if ($config['allow_avatar'] && $display_gallery && $auth->acl_get('u_chgavatar') && $config['allow_avatar_local'])
- {
- avatar_gallery($category, $avatar_select, 4);
- }
- else if ($config['allow_avatar'])
- {
- $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 && $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)
- );
- }
+ 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
+ ));
break;
diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php
index c57aec00a0..7bc7ac8191 100644
--- a/phpBB/includes/ucp/ucp_register.php
+++ b/phpBB/includes/ucp/ucp_register.php
@@ -38,7 +38,7 @@ class ucp_register
include($phpbb_root_path . 'includes/functions_profile_fields.' . $phpEx);
$coppa = $request->is_set('coppa') ? (int) $request->variable('coppa', false) : false;
- $agreed = (int) $request->variable('agreed', false);
+ $agreed = $request->variable('agreed', false);
$submit = $request->is_set_post('submit');
$change_lang = request_var('change_lang', '');
$user_lang = request_var('lang', $user->lang_name);
@@ -63,7 +63,7 @@ class ucp_register
$submit = false;
// Setting back agreed to let the user view the agreement in his/her language
- $agreed = ($request->variable('change_lang', false)) ? 0 : $agreed;
+ $agreed = false;
}
$user->lang_name = $user_lang = $use_lang;
@@ -89,7 +89,7 @@ class ucp_register
$add_coppa = ($coppa !== false) ? '&amp;coppa=' . $coppa : '';
$s_hidden_fields = array(
- 'change_lang' => $change_lang,
+ 'change_lang' => '',
);
// If we change the language, we want to pass on some more possible parameter.
@@ -384,8 +384,7 @@ class ucp_register
while ($row = $db->sql_fetchrow($result))
{
$messenger->template('admin_activate', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($data['username']),
@@ -457,6 +456,7 @@ class ucp_register
'S_LANG_OPTIONS' => language_select($data['lang']),
'S_TZ_OPTIONS' => $timezone_selects['tz_select'],
'S_TZ_DATE_OPTIONS' => $timezone_selects['tz_dates'],
+ 'S_TZ_PRESELECT' => !$submit,
'S_CONFIRM_REFRESH' => ($config['enable_confirm'] && $config['confirm_refresh']) ? true : false,
'S_REGISTRATION' => true,
'S_COPPA' => $coppa,
diff --git a/phpBB/includes/ucp/ucp_remind.php b/phpBB/includes/ucp/ucp_remind.php
index 4f65ed1866..bdbf693ddd 100644
--- a/phpBB/includes/ucp/ucp_remind.php
+++ b/phpBB/includes/ucp/ucp_remind.php
@@ -29,6 +29,11 @@ class ucp_remind
global $config, $phpbb_root_path, $phpEx;
global $db, $user, $auth, $template;
+ if (!$config['allow_password_reset'])
+ {
+ trigger_error($user->lang('UCP_PASSWORD_RESET_DISABLED', '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'));
+ }
+
$username = request_var('username', '', true);
$email = strtolower(request_var('email', ''));
$submit = (isset($_POST['submit'])) ? true : false;
@@ -94,8 +99,9 @@ class ucp_remind
$messenger->template('user_activate_passwd', $user_row['user_lang']);
- $messenger->to($user_row['user_email'], $user_row['username']);
- $messenger->im($user_row['user_jabber'], $user_row['username']);
+ $messenger->set_addresses($user_row);
+
+ $messenger->anti_abuse_headers($config, $user);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($user_row['username']),
diff --git a/phpBB/includes/ucp/ucp_resend.php b/phpBB/includes/ucp/ucp_resend.php
index 5f1e3a92c3..ab396cdec9 100644
--- a/phpBB/includes/ucp/ucp_resend.php
+++ b/phpBB/includes/ucp/ucp_resend.php
@@ -91,7 +91,7 @@ class ucp_resend
if ($config['require_activation'] == USER_ACTIVATION_SELF || $coppa)
{
$messenger->template(($coppa) ? 'coppa_resend_inactive' : 'user_resend_inactive', $user_row['user_lang']);
- $messenger->to($user_row['user_email'], $user_row['username']);
+ $messenger->set_addresses($user_row);
$messenger->anti_abuse_headers($config, $user);
@@ -126,8 +126,7 @@ class ucp_resend
while ($row = $db->sql_fetchrow($result))
{
$messenger->template('admin_activate', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->anti_abuse_headers($config, $user);
diff --git a/phpBB/includes/update_helpers.php b/phpBB/includes/update_helpers.php
deleted file mode 100644
index 69d678b2f8..0000000000
--- a/phpBB/includes/update_helpers.php
+++ /dev/null
@@ -1,112 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2012 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*/
-
-/**
-* phpBB Update Helpers
-*/
-class phpbb_update_helpers
-{
- /**
- * Determine the new timezone for a given phpBB 3.0 timezone and
- * "Daylight Saving Time" option
- *
- * @param $timezone float Users timezone in 3.0
- * @param $dst int Users daylight saving time
- * @return string Users new php Timezone which is used since 3.1
- */
- function convert_phpbb30_timezone($timezone, $dst)
- {
- $offset = $timezone + $dst;
-
- switch ($timezone)
- {
- case '-12':
- return 'Etc/GMT+' . abs($offset); //'[UTC - 12] Baker Island Time'
- case '-11':
- return 'Etc/GMT+' . abs($offset); //'[UTC - 11] Niue Time, Samoa Standard Time'
- case '-10':
- return 'Etc/GMT+' . abs($offset); //'[UTC - 10] Hawaii-Aleutian Standard Time, Cook Island Time'
- case '-9.5':
- return 'Pacific/Marquesas'; //'[UTC - 9:30] Marquesas Islands Time'
- case '-9':
- return 'Etc/GMT+' . abs($offset); //'[UTC - 9] Alaska Standard Time, Gambier Island Time'
- case '-8':
- return 'Etc/GMT+' . abs($offset); //'[UTC - 8] Pacific Standard Time'
- case '-7':
- return 'Etc/GMT+' . abs($offset); //'[UTC - 7] Mountain Standard Time'
- case '-6':
- return 'Etc/GMT+' . abs($offset); //'[UTC - 6] Central Standard Time'
- case '-5':
- return 'Etc/GMT+' . abs($offset); //'[UTC - 5] Eastern Standard Time'
- case '-4.5':
- return 'America/Caracas'; //'[UTC - 4:30] Venezuelan Standard Time'
- case '-4':
- return 'Etc/GMT+' . abs($offset); //'[UTC - 4] Atlantic Standard Time'
- case '-3.5':
- return 'America/St_Johns'; //'[UTC - 3:30] Newfoundland Standard Time'
- case '-3':
- return 'Etc/GMT+' . abs($offset); //'[UTC - 3] Amazon Standard Time, Central Greenland Time'
- case '-2':
- return 'Etc/GMT+' . abs($offset); //'[UTC - 2] Fernando de Noronha Time, South Georgia &amp; the South Sandwich Islands Time'
- case '-1':
- return 'Etc/GMT+' . abs($offset); //'[UTC - 1] Azores Standard Time, Cape Verde Time, Eastern Greenland Time'
- case '0':
- return (!$dst) ? 'UTC' : 'Etc/GMT-1'; //'[UTC] Western European Time, Greenwich Mean Time'
- case '1':
- return 'Etc/GMT-' . $offset; //'[UTC + 1] Central European Time, West African Time'
- case '2':
- return 'Etc/GMT-' . $offset; //'[UTC + 2] Eastern European Time, Central African Time'
- case '3':
- return 'Etc/GMT-' . $offset; //'[UTC + 3] Moscow Standard Time, Eastern African Time'
- case '3.5':
- return 'Asia/Tehran'; //'[UTC + 3:30] Iran Standard Time'
- case '4':
- return 'Etc/GMT-' . $offset; //'[UTC + 4] Gulf Standard Time, Samara Standard Time'
- case '4.5':
- return 'Asia/Kabul'; //'[UTC + 4:30] Afghanistan Time'
- case '5':
- return 'Etc/GMT-' . $offset; //'[UTC + 5] Pakistan Standard Time, Yekaterinburg Standard Time'
- case '5.5':
- return 'Asia/Kolkata'; //'[UTC + 5:30] Indian Standard Time, Sri Lanka Time'
- case '5.75':
- return 'Asia/Kathmandu'; //'[UTC + 5:45] Nepal Time'
- case '6':
- return 'Etc/GMT-' . $offset; //'[UTC + 6] Bangladesh Time, Bhutan Time, Novosibirsk Standard Time'
- case '6.5':
- return 'Indian/Cocos'; //'[UTC + 6:30] Cocos Islands Time, Myanmar Time'
- case '7':
- return 'Etc/GMT-' . $offset; //'[UTC + 7] Indochina Time, Krasnoyarsk Standard Time'
- case '8':
- return 'Etc/GMT-' . $offset; //'[UTC + 8] Chinese Standard Time, Australian Western Standard Time, Irkutsk Standard Time'
- case '8.75':
- return 'Australia/Eucla'; //'[UTC + 8:45] Southeastern Western Australia Standard Time'
- case '9':
- return 'Etc/GMT-' . $offset; //'[UTC + 9] Japan Standard Time, Korea Standard Time, Chita Standard Time'
- case '9.5':
- return 'Australia/ACT'; //'[UTC + 9:30] Australian Central Standard Time'
- case '10':
- return 'Etc/GMT-' . $offset; //'[UTC + 10] Australian Eastern Standard Time, Vladivostok Standard Time'
- case '10.5':
- return 'Australia/Lord_Howe'; //'[UTC + 10:30] Lord Howe Standard Time'
- case '11':
- return 'Etc/GMT-' . $offset; //'[UTC + 11] Solomon Island Time, Magadan Standard Time'
- case '11.5':
- return 'Pacific/Norfolk'; //'[UTC + 11:30] Norfolk Island Time'
- case '12':
- return 'Etc/GMT-12'; //'[UTC + 12] New Zealand Time, Fiji Time, Kamchatka Standard Time'
- case '12.75':
- return 'Pacific/Chatham'; //'[UTC + 12:45] Chatham Islands Time'
- case '13':
- return 'Pacific/Tongatapu'; //'[UTC + 13] Tonga Time, Phoenix Islands Time'
- case '14':
- return 'Pacific/Kiritimati'; //'[UTC + 14] Line Island Time'
- default:
- return 'UTC';
- }
- }
-}
diff --git a/phpBB/includes/user.php b/phpBB/includes/user.php
deleted file mode 100644
index 9ddd806b27..0000000000
--- a/phpBB/includes/user.php
+++ /dev/null
@@ -1,857 +0,0 @@
-<?php
-/**
-*
-* @package phpBB3
-* @copyright (c) 2005 phpBB Group
-* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
-*
-*/
-
-/**
-* @ignore
-*/
-if (!defined('IN_PHPBB'))
-{
- exit;
-}
-
-/**
-* Base user class
-*
-* This is the overarching class which contains (through session extend)
-* all methods utilised for user functionality during a session.
-*
-* @package phpBB3
-*/
-class phpbb_user extends phpbb_session
-{
- var $lang = array();
- var $help = array();
- var $style = array();
- var $date_format;
-
- /**
- * DateTimeZone object holding the timezone of the user
- */
- public $timezone;
-
- var $lang_name = false;
- var $lang_id = false;
- var $lang_path;
- var $img_lang;
- var $img_array = array();
-
- // 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);
-
- /**
- * Constructor to set the lang path
- */
- function __construct()
- {
- global $phpbb_root_path;
-
- $this->lang_path = $phpbb_root_path . 'language/';
- }
-
- /**
- * Function to set custom language path (able to use directory outside of phpBB)
- *
- * @param string $lang_path New language path used.
- * @access public
- */
- function set_custom_lang_path($lang_path)
- {
- $this->lang_path = $lang_path;
-
- if (substr($this->lang_path, -1) != '/')
- {
- $this->lang_path .= '/';
- }
- }
-
- /**
- * Setup basic user-specific items (style, language, ...)
- */
- function setup($lang_set = false, $style_id = false)
- {
- global $db, $phpbb_style, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache;
- global $phpbb_dispatcher;
-
- if ($this->data['user_id'] != ANONYMOUS)
- {
- $user_lang_name = (file_exists($this->lang_path . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']);
- $user_date_format = $this->data['user_dateformat'];
- $user_timezone = $this->data['user_timezone'];
- }
- else
- {
- $user_lang_name = basename($config['default_lang']);
- $user_date_format = $config['default_dateformat'];
- $user_timezone = $config['board_timezone'];
-
- /**
- * If a guest user is surfing, we try to guess his/her language first by obtaining the browser language
- * If re-enabled we need to make sure only those languages installed are checked
- * Commented out so we do not loose the code.
-
- if ($request->header('Accept-Language'))
- {
- $accept_lang_ary = explode(',', $request->header('Accept-Language'));
-
- foreach ($accept_lang_ary as $accept_lang)
- {
- // Set correct format ... guess full xx_YY form
- $accept_lang = substr($accept_lang, 0, 2) . '_' . strtoupper(substr($accept_lang, 3, 2));
- $accept_lang = basename($accept_lang);
-
- if (file_exists($this->lang_path . $accept_lang . "/common.$phpEx"))
- {
- $user_lang_name = $config['default_lang'] = $accept_lang;
- break;
- }
- else
- {
- // No match on xx_YY so try xx
- $accept_lang = substr($accept_lang, 0, 2);
- $accept_lang = basename($accept_lang);
-
- if (file_exists($this->lang_path . $accept_lang . "/common.$phpEx"))
- {
- $user_lang_name = $config['default_lang'] = $accept_lang;
- break;
- }
- }
- }
- }
- */
- }
-
- $user_data = $this->data;
-
- /**
- * Event to load language files and modify user data on every page
- *
- * @event core.user_setup
- * @var array user_data Array with user's data row
- * @var string user_lang_name Basename of the user's langauge
- * @var string user_date_format User's date/time format
- * @var string user_timezone User's timezone, should be one of
- * http://www.php.net/manual/en/timezones.php
- * @var mixed lang_set String or array of language files
- * @var mixed style_id Style we are going to display
- * @since 3.1-A1
- */
- $vars = array('user_data', 'user_lang_name', 'user_date_format', 'user_timezone', 'lang_set', 'style_id');
- extract($phpbb_dispatcher->trigger_event('core.user_setup', compact($vars)));
-
- $this->data = $user_data;
- $this->lang_name = $user_lang_name;
- $this->date_format = $user_date_format;
-
- try
- {
- $this->timezone = new DateTimeZone($user_timezone);
- }
- catch (Exception $e)
- {
- // If the timezone the user has selected is invalid, we fall back to UTC.
- $this->timezone = new DateTimeZone('UTC');
- }
-
- // We include common language file here to not load it every time a custom language file is included
- $lang = &$this->lang;
-
- // Do not suppress error if in DEBUG mode
- $include_result = (defined('DEBUG')) ? (include $this->lang_path . $this->lang_name . "/common.$phpEx") : (@include $this->lang_path . $this->lang_name . "/common.$phpEx");
-
- if ($include_result === false)
- {
- die('Language file ' . $this->lang_path . $this->lang_name . "/common.$phpEx" . " couldn't be opened.");
- }
-
- $this->add_lang($lang_set);
- unset($lang_set);
-
- $style_request = request_var('style', 0);
- if ($style_request && $auth->acl_get('a_styles') && !defined('ADMIN_START'))
- {
- global $SID, $_EXTRA_URL;
-
- $style_id = $style_request;
- $SID .= '&amp;style=' . $style_id;
- $_EXTRA_URL = array('style=' . $style_id);
- }
- else
- {
- // Set up style
- $style_id = ($style_id) ? $style_id : ((!$config['override_user_style']) ? $this->data['user_style'] : $config['default_style']);
- }
-
- $sql = 'SELECT *
- FROM ' . STYLES_TABLE . " s
- WHERE s.style_id = $style_id";
- $result = $db->sql_query($sql, 3600);
- $this->style = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
-
- // User has wrong style
- if (!$this->style && $style_id == $this->data['user_style'])
- {
- $style_id = $this->data['user_style'] = $config['default_style'];
-
- $sql = 'UPDATE ' . USERS_TABLE . "
- SET user_style = $style_id
- WHERE user_id = {$this->data['user_id']}";
- $db->sql_query($sql);
-
- $sql = 'SELECT *
- FROM ' . STYLES_TABLE . " s
- WHERE s.style_id = $style_id";
- $result = $db->sql_query($sql, 3600);
- $this->style = $db->sql_fetchrow($result);
- $db->sql_freeresult($result);
- }
-
- if (!$this->style)
- {
- trigger_error('Could not get style data', E_USER_ERROR);
- }
-
- // Now parse the cfg file and cache it
- $parsed_items = $cache->obtain_cfg_items($this->style);
-
- $check_for = array(
- 'pagination_sep' => (string) ', '
- );
-
- foreach ($check_for as $key => $default_value)
- {
- $this->style[$key] = (isset($parsed_items[$key])) ? $parsed_items[$key] : $default_value;
- settype($this->style[$key], gettype($default_value));
-
- if (is_string($default_value))
- {
- $this->style[$key] = htmlspecialchars($this->style[$key]);
- }
- }
-
- $phpbb_style->set_style();
-
- $this->img_lang = $this->lang_name;
-
- // Call phpbb_user_session_handler() in case external application want to "bend" some variables or replace classes...
- // After calling it we continue script execution...
- phpbb_user_session_handler();
-
- // If this function got called from the error handler we are finished here.
- if (defined('IN_ERROR_HANDLER'))
- {
- return;
- }
-
- // 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') && !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_'))
- {
- $message = 'REMOVE_INSTALL';
- }
- else
- {
- $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE';
- }
- trigger_error($message);
- }
-
- // Is board disabled and user not an admin or moderator?
- if ($config['board_disable'] && !defined('IN_LOGIN') && !$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
- {
- if ($this->data['is_bot'])
- {
- send_status_line(503, 'Service Unavailable');
- }
-
- $message = (!empty($config['board_disable_msg'])) ? $config['board_disable_msg'] : 'BOARD_DISABLE';
- trigger_error($message);
- }
-
- // Is load exceeded?
- if ($config['limit_load'] && $this->load !== false)
- {
- if ($this->load > floatval($config['limit_load']) && !defined('IN_LOGIN') && !defined('IN_ADMIN'))
- {
- // Set board disabled to true to let the admins/mods get the proper notification
- $config['board_disable'] = '1';
-
- if (!$auth->acl_gets('a_', 'm_') && !$auth->acl_getf_global('m_'))
- {
- if ($this->data['is_bot'])
- {
- send_status_line(503, 'Service Unavailable');
- }
- trigger_error('BOARD_UNAVAILABLE');
- }
- }
- }
-
- if (isset($this->data['session_viewonline']))
- {
- // Make sure the user is able to hide his session
- if (!$this->data['session_viewonline'])
- {
- // Reset online status if not allowed to hide the session...
- if (!$auth->acl_get('u_hideonline'))
- {
- $sql = 'UPDATE ' . SESSIONS_TABLE . '
- SET session_viewonline = 1
- WHERE session_user_id = ' . $this->data['user_id'];
- $db->sql_query($sql);
- $this->data['session_viewonline'] = 1;
- }
- }
- else if (!$this->data['user_allow_viewonline'])
- {
- // the user wants to hide and is allowed to -> cloaking device on.
- if ($auth->acl_get('u_hideonline'))
- {
- $sql = 'UPDATE ' . SESSIONS_TABLE . '
- SET session_viewonline = 0
- WHERE session_user_id = ' . $this->data['user_id'];
- $db->sql_query($sql);
- $this->data['session_viewonline'] = 0;
- }
- }
- }
-
-
- // 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'] && !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")
- {
- redirect(append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&amp;mode=reg_details'));
- }
- }
-
- return;
- }
-
- /**
- * More advanced language substitution
- * Function to mimic sprintf() with the possibility of using phpBB's language system to substitute nullar/singular/plural forms.
- * Params are the language key and the parameters to be substituted.
- * This function/functionality is inspired by SHS` and Ashe.
- *
- * Example call: <samp>$user->lang('NUM_POSTS_IN_QUEUE', 1);</samp>
- *
- * If the first parameter is an array, the elements are used as keys and subkeys to get the language entry:
- * Example: <samp>$user->lang(array('datetime', 'AGO'), 1)</samp> uses $user->lang['datetime']['AGO'] as language entry.
- */
- function lang()
- {
- $args = func_get_args();
- $key = $args[0];
-
- if (is_array($key))
- {
- $lang = &$this->lang[array_shift($key)];
-
- foreach ($key as $_key)
- {
- $lang = &$lang[$_key];
- }
- }
- else
- {
- $lang = &$this->lang[$key];
- }
-
- // Return if language string does not exist
- if (!isset($lang) || (!is_string($lang) && !is_array($lang)))
- {
- return $key;
- }
-
- // If the language entry is a string, we simply mimic sprintf() behaviour
- if (is_string($lang))
- {
- if (sizeof($args) == 1)
- {
- return $lang;
- }
-
- // Replace key with language entry and simply pass along...
- $args[0] = $lang;
- return call_user_func_array('sprintf', $args);
- }
- else if (sizeof($lang) == 0)
- {
- // If the language entry is an empty array, we just return the language key
- return $args[0];
- }
-
- // It is an array... now handle different nullar/singular/plural forms
- $key_found = false;
-
- // We now get the first number passed and will select the key based upon this number
- for ($i = 1, $num_args = sizeof($args); $i < $num_args; $i++)
- {
- if (is_int($args[$i]) || is_float($args[$i]))
- {
- if ($args[$i] == 0 && isset($lang[0]))
- {
- // We allow each translation using plural forms to specify a version for the case of 0 things,
- // so that "0 users" may be displayed as "No users".
- $key_found = 0;
- break;
- }
- else
- {
- $use_plural_form = $this->get_plural_form($args[$i]);
- if (isset($lang[$use_plural_form]))
- {
- // The key we should use exists, so we use it.
- $key_found = $use_plural_form;
- }
- else
- {
- // If the key we need to use does not exist, we fall back to the previous one.
- $numbers = array_keys($lang);
-
- foreach ($numbers as $num)
- {
- if ($num > $use_plural_form)
- {
- break;
- }
-
- $key_found = $num;
- }
- }
- break;
- }
- }
- }
-
- // Ok, let's check if the key was found, else use the last entry (because it is mostly the plural form)
- if ($key_found === false)
- {
- $numbers = array_keys($lang);
- $key_found = end($numbers);
- }
-
- // Use the language string we determined and pass it to sprintf()
- $args[0] = $lang[$key_found];
- return call_user_func_array('sprintf', $args);
- }
-
- /**
- * Determine which plural form we should use.
- * For some languages this is not as simple as for English.
- *
- * @param $number int|float The number we want to get the plural case for. Float numbers are floored.
- * @param $force_rule mixed False to use the plural rule of the language package
- * or an integer to force a certain plural rule
- * @return int The plural-case we need to use for the number plural-rule combination
- */
- function get_plural_form($number, $force_rule = false)
- {
- $number = (int) $number;
-
- // Default to English system
- $plural_rule = ($force_rule !== false) ? $force_rule : ((isset($this->lang['PLURAL_RULE'])) ? $this->lang['PLURAL_RULE'] : 1);
-
- return phpbb_get_plural_form($plural_rule, $number);
- }
-
- /**
- * Add Language Items - use_db and use_help are assigned where needed (only use them to force inclusion)
- *
- * @param mixed $lang_set specifies the language entries to include
- * @param bool $use_db internal variable for recursion, do not use
- * @param bool $use_help internal variable for recursion, do not use
- * @param string $ext_name The extension to load language from, or empty for core files
- *
- * Examples:
- * <code>
- * $lang_set = array('posting', 'help' => 'faq');
- * $lang_set = array('posting', 'viewtopic', 'help' => array('bbcode', 'faq'))
- * $lang_set = array(array('posting', 'viewtopic'), 'help' => array('bbcode', 'faq'))
- * $lang_set = 'posting'
- * $lang_set = array('help' => 'faq', 'db' => array('help:faq', 'posting'))
- * </code>
- */
- function add_lang($lang_set, $use_db = false, $use_help = false, $ext_name = '')
- {
- global $phpEx;
-
- if (is_array($lang_set))
- {
- foreach ($lang_set as $key => $lang_file)
- {
- // Please do not delete this line.
- // We have to force the type here, else [array] language inclusion will not work
- $key = (string) $key;
-
- if ($key == 'db')
- {
- $this->add_lang($lang_file, true, $use_help, $ext_name);
- }
- else if ($key == 'help')
- {
- $this->add_lang($lang_file, $use_db, true, $ext_name);
- }
- else if (!is_array($lang_file))
- {
- $this->set_lang($this->lang, $this->help, $lang_file, $use_db, $use_help, $ext_name);
- }
- else
- {
- $this->add_lang($lang_file, $use_db, $use_help, $ext_name);
- }
- }
- unset($lang_set);
- }
- else if ($lang_set)
- {
- $this->set_lang($this->lang, $this->help, $lang_set, $use_db, $use_help, $ext_name);
- }
- }
-
- /**
- * Add Language Items from an extension - use_db and use_help are assigned where needed (only use them to force inclusion)
- *
- * @param string $ext_name The extension to load language from, or empty for core files
- * @param mixed $lang_set specifies the language entries to include
- * @param bool $use_db internal variable for recursion, do not use
- * @param bool $use_help internal variable for recursion, do not use
- */
- function add_lang_ext($ext_name, $lang_set, $use_db = false, $use_help = false)
- {
- if ($ext_name === '/')
- {
- $ext_name = '';
- }
-
- $this->add_lang($lang_set, $use_db, $use_help, $ext_name);
- }
-
- /**
- * Set language entry (called by add_lang)
- * @access private
- */
- function set_lang(&$lang, &$help, $lang_file, $use_db = false, $use_help = false, $ext_name = '')
- {
- global $phpbb_root_path, $phpEx;
-
- // Make sure the language name is set (if the user setup did not happen it is not set)
- if (!$this->lang_name)
- {
- global $config;
- $this->lang_name = basename($config['default_lang']);
- }
-
- // $lang == $this->lang
- // $help == $this->help
- // - add appropriate variables here, name them as they are used within the language file...
- if (!$use_db)
- {
- if ($use_help && strpos($lang_file, '/') !== false)
- {
- $filename = dirname($lang_file) . '/help_' . basename($lang_file);
- }
- else
- {
- $filename = (($use_help) ? 'help_' : '') . $lang_file;
- }
-
- if ($ext_name)
- {
- global $phpbb_extension_manager;
- $ext_path = $phpbb_extension_manager->get_extension_path($ext_name, true);
-
- $lang_path = $ext_path . 'language/';
- }
- else
- {
- $lang_path = $this->lang_path;
- }
-
- if (strpos($phpbb_root_path . $filename, $lang_path . $this->lang_name . '/') === 0)
- {
- $language_filename = $phpbb_root_path . $filename;
- }
- else
- {
- $language_filename = $lang_path . $this->lang_name . '/' . $filename . '.' . $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($lang_path . 'en', $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, $ext_name);
- }
- 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, $ext_name);
- }
-
- // Reset the lang name
- $this->lang_name = (file_exists($lang_path . $this->data['user_lang'] . "/common.$phpEx")) ? $this->data['user_lang'] : basename($config['default_lang']);
- return;
- }
-
- // Do not suppress error if in DEBUG mode
- $include_result = (defined('DEBUG')) ? (include $language_filename) : (@include $language_filename);
-
- if ($include_result === false)
- {
- trigger_error('Language file ' . $language_filename . ' couldn\'t be opened.', E_USER_ERROR);
- }
- }
- else if ($use_db)
- {
- // Get Database Language Strings
- // Put them into $lang if nothing is prefixed, put them into $help if help: is prefixed
- // For example: help:faq, posting
- }
- }
-
- /**
- * Format user date
- *
- * @param int $gmepoch unix timestamp
- * @param string $format date format in date() notation. | used to indicate relative dates, for example |d m Y|, h:i is translated to Today, h:i.
- * @param bool $forcedate force non-relative date format.
- *
- * @return mixed translated date
- */
- function format_date($gmepoch, $format = false, $forcedate = false)
- {
- static $utc;
-
- if (!isset($utc))
- {
- $utc = new DateTimeZone('UTC');
- }
-
- $time = new phpbb_datetime($this, "@$gmepoch", $utc);
- $time->setTimezone($this->timezone);
-
- return $time->format($format, $forcedate);
- }
-
- /**
- * Create a phpbb_datetime object in the context of the current user
- *
- * @since 3.1
- * @param string $time String in a format accepted by strtotime().
- * @param DateTimeZone $timezone Time zone of the time.
- * @return phpbb_datetime Date time object linked to the current users locale
- */
- public function create_datetime($time = 'now', DateTimeZone $timezone = null)
- {
- $timezone = $timezone ?: $this->timezone;
- return new phpbb_datetime($this, $time, $timezone);
- }
-
- /**
- * Get the UNIX timestamp for a datetime in the users timezone, so we can store it in the database.
- *
- * @param string $format Format of the entered date/time
- * @param string $time Date/time with the timezone applied
- * @param DateTimeZone $timezone Timezone of the date/time, falls back to timezone of current user
- * @return int Returns the unix timestamp
- */
- public function get_timestamp_from_format($format, $time, DateTimeZone $timezone = null)
- {
- $timezone = $timezone ?: $this->timezone;
- $date = DateTime::createFromFormat($format, $time, $timezone);
- return ($date !== false) ? $date->format('U') : false;
- }
-
- /**
- * Get language id currently used by the user
- */
- function get_iso_lang_id()
- {
- global $config, $db;
-
- if (!empty($this->lang_id))
- {
- return $this->lang_id;
- }
-
- if (!$this->lang_name)
- {
- $this->lang_name = $config['default_lang'];
- }
-
- $sql = 'SELECT lang_id
- FROM ' . LANG_TABLE . "
- WHERE lang_iso = '" . $db->sql_escape($this->lang_name) . "'";
- $result = $db->sql_query($sql);
- $this->lang_id = (int) $db->sql_fetchfield('lang_id');
- $db->sql_freeresult($result);
-
- return $this->lang_id;
- }
-
- /**
- * Get users profile fields
- */
- function get_profile_fields($user_id)
- {
- global $db;
-
- if (isset($this->profile_fields))
- {
- return;
- }
-
- $sql = 'SELECT *
- FROM ' . PROFILE_FIELDS_DATA_TABLE . "
- WHERE user_id = $user_id";
- $result = $db->sql_query_limit($sql, 1);
- $this->profile_fields = (!($row = $db->sql_fetchrow($result))) ? array() : $row;
- $db->sql_freeresult($result);
- }
-
- /**
- * Specify/Get image
- */
- function img($img, $alt = '')
- {
- $alt = (!empty($this->lang[$alt])) ? $this->lang[$alt] : $alt;
- return '<span class="imageset ' . $img . '">' . $alt . '</span>';
- }
-
- /**
- * Get option bit field from user options.
- *
- * @param int $key option key, as defined in $keyoptions property.
- * @param int $data bit field value to use, or false to use $this->data['user_options']
- * @return bool true if the option is set in the bit field, false otherwise
- */
- function optionget($key, $data = false)
- {
- $var = ($data !== false) ? $data : $this->data['user_options'];
- return phpbb_optionget($this->keyoptions[$key], $var);
- }
-
- /**
- * Set option bit field for user options.
- *
- * @param int $key Option key, as defined in $keyoptions property.
- * @param bool $value True to set the option, false to clear the option.
- * @param int $data Current bit field value, or false to use $this->data['user_options']
- * @return int|bool If $data is false, the bit field is modified and
- * written back to $this->data['user_options'], and
- * return value is true if the bit field changed and
- * false otherwise. If $data is not false, the new
- * bitfield value is returned.
- */
- function optionset($key, $value, $data = false)
- {
- $var = ($data !== false) ? $data : $this->data['user_options'];
-
- $new_var = phpbb_optionset($this->keyoptions[$key], $value, $var);
-
- if ($data === false)
- {
- if ($new_var != $var)
- {
- $this->data['user_options'] = $new_var;
- return true;
- }
- else
- {
- return false;
- }
- }
- else
- {
- return $new_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;
- }
-
- /**
- * Returns all password protected forum ids the user is currently NOT authenticated for.
- *
- * @return array Array of forum ids
- * @access public
- */
- function get_passworded_forums()
- {
- global $db;
-
- $sql = 'SELECT f.forum_id, 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($this->session_id) . "')
- WHERE f.forum_password <> ''";
- $result = $db->sql_query($sql);
-
- $forum_ids = array();
- while ($row = $db->sql_fetchrow($result))
- {
- $forum_id = (int) $row['forum_id'];
-
- if ($row['user_id'] != $this->data['user_id'])
- {
- $forum_ids[$forum_id] = $forum_id;
- }
- }
- $db->sql_freeresult($result);
-
- return $forum_ids;
- }
-}