diff options
150 files changed, 2576 insertions, 490 deletions
diff --git a/.gitignore b/.gitignore index 4093aeb56d..c757210654 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ /phpunit.xml /phpBB/cache/*.html /phpBB/cache/*.php -/phpBB/cache/queue.php.lock +/phpBB/cache/*.lock /phpBB/composer.phar /phpBB/config.php /phpBB/config_dev.php diff --git a/phpBB/adm/index.php b/phpBB/adm/index.php index e20bbe4bec..0f84af6f9e 100644 --- a/phpBB/adm/index.php +++ b/phpBB/adm/index.php @@ -52,7 +52,7 @@ $mode = request_var('mode', ''); // Set custom style for admin area $phpbb_style->set_ext_dir_prefix('adm/'); -$phpbb_style->set_custom_style('admin', $phpbb_admin_path . 'style', ''); +$phpbb_style->set_custom_style('admin', $phpbb_admin_path . 'style', array(), ''); $template->assign_var('T_ASSETS_PATH', $phpbb_root_path . 'assets'); $template->assign_var('T_TEMPLATE_PATH', $phpbb_admin_path . 'style'); diff --git a/phpBB/adm/style/acp_forums.html b/phpBB/adm/style/acp_forums.html index 9a3706c2f0..d6c06bf6d8 100644 --- a/phpBB/adm/style/acp_forums.html +++ b/phpBB/adm/style/acp_forums.html @@ -241,6 +241,7 @@ <dt><label for="topics_per_page">{L_FORUM_TOPICS_PAGE}{L_COLON}</label><br /><span>{L_FORUM_TOPICS_PAGE_EXPLAIN}</span></dt> <dd><input type="text" id="topics_per_page" name="topics_per_page" value="{TOPICS_PER_PAGE}" size="4" maxlength="4" /></dd> </dl> + <!-- EVENT acp_forums_normal_settings_append --> </fieldset> <fieldset> diff --git a/phpBB/adm/style/acp_main.html b/phpBB/adm/style/acp_main.html index 8b591294d4..b644862ce1 100644 --- a/phpBB/adm/style/acp_main.html +++ b/phpBB/adm/style/acp_main.html @@ -76,6 +76,8 @@ </div> <!-- ENDIF --> + <!-- EVENT acp_main_notice_after --> + <table cellspacing="1"> <caption>{L_FORUM_STATS}</caption> <col class="col1" /><col class="col2" /><col class="col1" /><col class="col2" /> @@ -202,6 +204,8 @@ <dd><input type="hidden" name="action" value="purge_cache" /><input class="button2" type="submit" id="action_purge_cache" name="action_purge_cache" value="{L_RUN}" /></dd> </dl> </form> + + <!-- EVENT acp_main_actions_append --> </fieldset> <!-- ENDIF --> diff --git a/phpBB/adm/style/acp_users_overview.html b/phpBB/adm/style/acp_users_overview.html index b7e3a9822e..a8e862c141 100644 --- a/phpBB/adm/style/acp_users_overview.html +++ b/phpBB/adm/style/acp_users_overview.html @@ -53,6 +53,7 @@ <dt><label for="password_confirm">{L_CONFIRM_PASSWORD}{L_COLON}</label><br /><span>{L_CONFIRM_PASSWORD_EXPLAIN}</span></dt> <dd><input type="password" id="password_confirm" name="password_confirm" value="" autocomplete="off" /></dd> </dl> +<!-- EVENT acp_users_overview_options_append --> <p class="quick"> <input class="button1" type="submit" name="update" value="{L_SUBMIT}" /> diff --git a/phpBB/adm/style/overall_footer.html b/phpBB/adm/style/overall_footer.html index 2bc9ee52d7..2a8b46d458 100644 --- a/phpBB/adm/style/overall_footer.html +++ b/phpBB/adm/style/overall_footer.html @@ -42,5 +42,7 @@ <!-- INCLUDEJS ajax.js --> {SCRIPTS} +<!-- EVENT acp_overall_footer_after --> + </body> </html> diff --git a/phpBB/adm/style/overall_header.html b/phpBB/adm/style/overall_header.html index f7902e6d2e..8170931221 100644 --- a/phpBB/adm/style/overall_header.html +++ b/phpBB/adm/style/overall_header.html @@ -155,6 +155,7 @@ function switch_menu() // ]]> </script> +<!-- EVENT acp_overall_header_head_append --> </head> <body class="{S_CONTENT_DIRECTION}"> diff --git a/phpBB/adm/style/simple_footer.html b/phpBB/adm/style/simple_footer.html index 1d5c62b0a3..906a9bebed 100644 --- a/phpBB/adm/style/simple_footer.html +++ b/phpBB/adm/style/simple_footer.html @@ -18,6 +18,7 @@ <script type="text/javascript" src="{T_JQUERY_LINK}"></script> <!-- IF S_JQUERY_FALLBACK --><script type="text/javascript">window.jQuery || document.write(unescape('%3Cscript src="{T_ASSETS_PATH}/javascript/jquery.js?assets_version={T_ASSETS_VERSION}" type="text/javascript"%3E%3C/script%3E'));</script><!-- ENDIF --> +<!-- EVENT acp_simple_footer_after --> </body> </html> diff --git a/phpBB/adm/style/simple_header.html b/phpBB/adm/style/simple_header.html index 0ba445ca2a..6e0c360600 100644 --- a/phpBB/adm/style/simple_header.html +++ b/phpBB/adm/style/simple_header.html @@ -101,6 +101,7 @@ function find_username(url) // ]]> </script> +<!-- EVENT acp_simple_header_head_append --> </head> <body class="{S_CONTENT_DIRECTION}"> diff --git a/phpBB/adm/swatch.php b/phpBB/adm/swatch.php index 86498a255f..c01651e0f0 100644 --- a/phpBB/adm/swatch.php +++ b/phpBB/adm/swatch.php @@ -24,7 +24,7 @@ $user->setup(); $phpbb_admin_path = (defined('PHPBB_ADMIN_PATH')) ? PHPBB_ADMIN_PATH : './'; // Set custom template for admin area -$phpbb_style->set_custom_style('admin', $phpbb_admin_path . 'style', ''); +$phpbb_style->set_custom_style('admin', $phpbb_admin_path . 'style', array(), ''); $template->set_filenames(array( 'body' => 'colour_swatch.html') diff --git a/phpBB/assets/javascript/core.js b/phpBB/assets/javascript/core.js index f7d6688f68..c18bec7035 100644 --- a/phpBB/assets/javascript/core.js +++ b/phpBB/assets/javascript/core.js @@ -342,12 +342,6 @@ phpbb.ajaxify = function(options) { var alert; alert = phpbb.alert(dark.attr('data-ajax-error-title'), dark.attr('data-ajax-error-text')); - - setTimeout(function () { - dark.fadeOut(phpbb.alert_time, function() { - alert.hide(); - }); - }, 5000); } // If the element is a form, POST must be used and some extra data must diff --git a/phpBB/common.php b/phpBB/common.php index e99b9edee5..add0b07726 100644 --- a/phpBB/common.php +++ b/phpBB/common.php @@ -71,7 +71,6 @@ require($phpbb_root_path . 'includes/functions_content.' . $phpEx); require($phpbb_root_path . 'includes/functions_container.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); -require($phpbb_root_path . 'includes/db/' . ltrim($dbms, 'dbal_') . '.' . $phpEx); require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); // Set PHP error handler to ours diff --git a/phpBB/config/cron_tasks.yml b/phpBB/config/cron_tasks.yml index 74f57e449d..d1954b1877 100644 --- a/phpBB/config/cron_tasks.yml +++ b/phpBB/config/cron_tasks.yml @@ -6,6 +6,8 @@ services: - %core.php_ext% - @config - @dbal.conn + calls: + - [set_name, [cron.task.core.prune_all_forums]] tags: - { name: cron.task } @@ -16,6 +18,8 @@ services: - %core.php_ext% - @config - @dbal.conn + calls: + - [set_name, [cron.task.core.prune_forum]] tags: - { name: cron.task } @@ -25,6 +29,8 @@ services: - %core.root_path% - %core.php_ext% - @config + calls: + - [set_name, [cron.task.core.queue]] tags: - { name: cron.task } @@ -33,6 +39,8 @@ services: arguments: - @config - @cache.driver + calls: + - [set_name, [cron.task.core.tidy_cache]] tags: - { name: cron.task } @@ -42,6 +50,8 @@ services: - %core.root_path% - %core.php_ext% - @config + calls: + - [set_name, [cron.task.core.tidy_database]] tags: - { name: cron.task } @@ -54,6 +64,8 @@ services: - @config - @dbal.conn - @user + calls: + - [set_name, [cron.task.core.tidy_search]] tags: - { name: cron.task } @@ -62,6 +74,8 @@ services: arguments: - @config - @user + calls: + - [set_name, [cron.task.core.tidy_sessions]] tags: - { name: cron.task } @@ -71,5 +85,7 @@ services: - %core.root_path% - %core.php_ext% - @config + calls: + - [set_name, [cron.task.core.tidy_warnings]] tags: - { name: cron.task } diff --git a/phpBB/config/services.yml b/phpBB/config/services.yml index 242fe7f1d2..febdc5acb8 100644 --- a/phpBB/config/services.yml +++ b/phpBB/config/services.yml @@ -180,6 +180,7 @@ services: - @user - @style.resource_locator - @template_context + - @ext.manager template_context: class: phpbb_template_context diff --git a/phpBB/docs/coding-guidelines.html b/phpBB/docs/coding-guidelines.html index eb569d12d5..14c2281323 100644 --- a/phpBB/docs/coding-guidelines.html +++ b/phpBB/docs/coding-guidelines.html @@ -72,6 +72,7 @@ <ol style="list-style-type: lower-roman;"> <li><a href="#templates">General Templating</a></li> <li><a href="#stylestree">Styles Tree</a></li> + <li><a href="#template-events">Template Events</a></li> </ol></li> <li><a href="#charsets">Character Sets and Encodings</a></li> <li><a href="#translation">Translation (<abbr title="Internationalisation">i18n</abbr>/<abbr title="Localisation">L10n</abbr>) Guidelines</a> @@ -1678,6 +1679,57 @@ version = 3.1.0 parent = prosilver </pre></div> + <a name="template-events"></a><h3>4.iii. Template Events</h3> + <p>Template events must follow this format: <code><!-- EVENT event_name --></code></p> + <p>Using the above example, files named <code>event_name.html</code> located within extensions will be injected into the location of the event.</p> + + <h4>Template event naming guidelines:</h4> + <ul> + <li>An event name must be all lowercase, with each word separated by an underscore.</li> + <li>An event name must briefly describe the location and purpose of the event.</li> + <li>An event name must end with one of the following suffixes:</li> + <ul> + <li><code>_prepend</code> - This event adds an item to the beginning of a block of related items, or adds to the beginning of individual items in a block.</li> + <li><code>_append</code> - This event adds an item to the end of a block of related items, or adds to the end of individual items in a block.</li> + <li><code>_before</code> - This event adds content directly before the specified block</li> + <li><code>_after</code> - This event adds content directly after the specified block</li> + </ul> + </ul> + + <h4>Template event documentation</h4> + <p>Events must be documented in <code>phpBB/docs/events.md</code> in alphabetical order based on the event name. The format is as follows:</p> + + <ul><li>An event found in only one template file: + <div class="codebox"><pre>event_name +=== +* Location: styles/<style_name>/template/filename.html +* Purpose: A brief description of what this event should be used for. +This may span multiple lines. +</pre></div></li> + <li>An event found in multiple template files: + <div class="codebox"><pre>event_name +=== +* Locations: + + first/file/path.html + + second/file/path.html +* Purpose: Same as above. +</pre></div> + <li>An event that is found multiple times in a file should have the number of instances in parenthesis next to the filename. + <div class="codebox"><pre>event_name +=== +* Locations: + + first/file/path.html (2) + + second/file/path.html +* Purpose: Same as above. +</pre></div></li> + <li>An actual example event documentation: + <div class="codebox"><pre>forumlist_body_last_post_title_prepend +==== +* Locations: + + styles/prosilver/template/forumlist_body.html + + styles/subsilver2/template/forumlist_body.html +* Purpose: Add content before the post title of the latest post in a forum on the forum list.</pre></div></ul><br /> + </div> <div class="back2top"><a href="#wrap" class="top">Back to Top</a></div> diff --git a/phpBB/docs/events.md b/phpBB/docs/events.md new file mode 100644 index 0000000000..f0b3b81822 --- /dev/null +++ b/phpBB/docs/events.md @@ -0,0 +1,132 @@ +acp_forums_normal_settings_append +=== +* Location: adm/style/acp_forums.html +* Purpose: Add settings to forums + +acp_main_actions_append +=== +* Location: adm/style/acp_main.html +* Purpose: Add actions to the ACP main page below the cache purge action + +acp_main_notice_after +=== +* Location: adm/style/acp_main.html +* Purpose: Add notices or other blocks in the ACP below other configuration notices + +acp_overall_footer_after +=== +* Location: adm/style/overall_footer.html +* Purpose: Add content below the footer in the ACP + +acp_overall_header_head_append +=== +* Location: adm/style/overall_header.html +* Add assets within the `<head>` tags in the ACP + +acp_simple_footer_after +=== +* Location: adm/style/simple_footer.html +* Purpose: Add content below the simple footer in the ACP + +acp_simple_header_head_append +=== +* Location: adm/style/overall_header.html +* Add assets within the `<head>` tags in the simple header of the ACP + +acp_users_overview_options_append +=== +* Location: adm/style/acp_users.html +* Purpose: Add options and settings on user overview page + +forumlist_body_last_post_title_prepend +==== +* Locations: + + styles/prosilver/template/forumlist_body.html + + styles/subsilver2/template/forumlist_body.html +* Purpose: Add content before the post title of the latest post in a forum on the forum list. + +index_body_stat_blocks_before +=== +* Locations: + + styles/prosilver/template/index_body.html + + styles/subsilver2/template/index_body.html +* Purpose: Add new statistic blocks above the Who Is Online and Board Statistics blocks + +overall_footer_after +=== +* Locations: + + styles/prosilver/template/overall_footer.html + + styles/subsilver2/template/overall_footer.html +* Purpose: Add content at the end of the file, directly prior to the `</body>` tag + +overall_footer_breadcrumb_append +=== +* Location: styles/prosilver/template/overall_footer.html +* Purpose: Add links to the list of breadcrumbs in the footer + +overall_footer_copyright_append +=== +* Locations: + + styles/prosilver/template/overall_footer.html + + styles/subsilver2/template/overall_footer.html +* Purpose: Add content after the copyright line (no new line by default), before the ACP link + +overall_footer_copyright_prepend +=== +* Locations: + + styles/prosilver/template/overall_footer.html + + styles/subsilver2/template/overall_footer.html +* Purpose: Add content before the copyright line + +overall_header_breadcrumb_append +=== +* Locations: + + styles/prosilver/template/overall_header.html + + styles/subsilver2/template/breadcrumbs.html +* Purpose: Add links to the list of breadcrumbs in the header + +overall_header_head_append +=== +* Locations: + + styles/prosilver/template/overall_header.html + + styles/subsilver2/template/overall_header.html +* Purpose: Add asset calls directly before the `</head>` tag + +overall_header_navigation_append +=== +* Location: styles/prosilver/template/overall_header.html +* Purpose: Add links after the navigation links in the header + +overall_header_navigation_prepend +=== +* Location: styles/prosilver/template/overall_header.html +* Purpose: Add links before the navigation links in the header + +posting_editor_options_prepend +=== +* Locations: + + styles/prosilver/template/posting_editor.html + + styles/prosilver/template/posting_body.html +* Purpose: Add posting options on the posting screen + +simple_footer_after +=== +* Location: styles/prosilver/template/simple_footer.html +* Purpose: Add content directly prior to the `</body>` tag of the simple footer + +ucp_pm_viewmessage_print_head_append +=== +* Location: styles/prosilver/template/ucp_pm_viewmessage_print.html +* Purpose: Add asset calls directly before the `</head>` tag of the Print PM screen + +viewtopic_print_head_append +=== +* Location: styles/prosilver/template/viewtopic_print.html +* Purpose: Add asset calls directly before the `</head>` tag of the Print Topic screen + +viewtopic_topic_title_prepend +=== +* Locations: + + styles/prosilver/template/viewtopic_body.html + + styles/subsilver2/template/viewtopic_body.html +* Purpose: Add content directly before the topic title link on the View topic screen diff --git a/phpBB/download/file.php b/phpBB/download/file.php index 73b9e0a9f2..8c282e36d7 100644 --- a/phpBB/download/file.php +++ b/phpBB/download/file.php @@ -43,7 +43,6 @@ if (isset($_GET['avatar'])) require($phpbb_root_path . 'includes/class_loader.' . $phpEx); - require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); require($phpbb_root_path . 'includes/functions.' . $phpEx); require($phpbb_root_path . 'includes/functions_container.' . $phpEx); diff --git a/phpBB/includes/acp/info/acp_extensions.php b/phpBB/includes/acp/info/acp_extensions.php index f5953fb1dd..03d7059165 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_EXTENSIONS_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_EXTENSIONS_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/bbcode.php b/phpBB/includes/bbcode.php index b9ffa8091c..e8681420d4 100644 --- a/phpBB/includes/bbcode.php +++ b/phpBB/includes/bbcode.php @@ -134,7 +134,7 @@ class bbcode $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()); + $template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, new phpbb_template_context(), $phpbb_extension_manager); $style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, $style_path_provider, $template); $style->set_style(); $template->set_filenames(array('bbcode.html' => 'bbcode.html')); diff --git a/phpBB/includes/cache/driver/file.php b/phpBB/includes/cache/driver/file.php index 691abe0438..85decbe3e8 100644 --- a/phpBB/includes/cache/driver/file.php +++ b/phpBB/includes/cache/driver/file.php @@ -367,12 +367,10 @@ class phpbb_cache_driver_file extends phpbb_cache_driver_base } /** - * Save sql query + * {@inheritDoc} */ - function sql_save($query, $query_result, $ttl) + function sql_save(phpbb_db_driver $db, $query, $query_result, $ttl) { - global $db; - // Remove extra spaces and tabs $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); diff --git a/phpBB/includes/cache/driver/interface.php b/phpBB/includes/cache/driver/interface.php index d403bbcd71..53f684d1c8 100644 --- a/phpBB/includes/cache/driver/interface.php +++ b/phpBB/includes/cache/driver/interface.php @@ -85,6 +85,7 @@ interface phpbb_cache_driver_interface * result to persistent storage. In other words, there is no need * to call save() afterwards. * + * @param phpbb_db_driver $db Database connection * @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 @@ -95,7 +96,7 @@ interface phpbb_cache_driver_interface * representing the query should be returned. Otherwise * the original $query_result should be returned. */ - public function sql_save($query, $query_result, $ttl); + public function sql_save(phpbb_db_driver $db, $query, $query_result, $ttl); /** * Check if result for a given SQL query exists in cache. diff --git a/phpBB/includes/cache/driver/memory.php b/phpBB/includes/cache/driver/memory.php index c39f9f7850..f77a1df316 100644 --- a/phpBB/includes/cache/driver/memory.php +++ b/phpBB/includes/cache/driver/memory.php @@ -283,12 +283,10 @@ abstract class phpbb_cache_driver_memory extends phpbb_cache_driver_base } /** - * Save sql query + * {@inheritDoc} */ - function sql_save($query, $query_result, $ttl) + function sql_save(phpbb_db_driver $db, $query, $query_result, $ttl) { - global $db; - // Remove extra spaces and tabs $query = preg_replace('/[\n\r\s\t]+/', ' ', $query); $hash = md5($query); diff --git a/phpBB/includes/cache/driver/null.php b/phpBB/includes/cache/driver/null.php index 687604d14f..2fadc27ba3 100644 --- a/phpBB/includes/cache/driver/null.php +++ b/phpBB/includes/cache/driver/null.php @@ -105,9 +105,9 @@ class phpbb_cache_driver_null extends phpbb_cache_driver_base } /** - * Save sql query + * {@inheritDoc} */ - function sql_save($query, $query_result, $ttl) + function sql_save(phpbb_db_driver $db, $query, $query_result, $ttl) { return $query_result; } diff --git a/phpBB/includes/config/db.php b/phpBB/includes/config/db.php index 45f9f1cb21..b18369a479 100644 --- a/phpBB/includes/config/db.php +++ b/phpBB/includes/config/db.php @@ -29,7 +29,7 @@ class phpbb_config_db extends phpbb_config /** * Database connection - * @var dbal + * @var phpbb_db_driver */ protected $db; @@ -42,11 +42,11 @@ class phpbb_config_db extends phpbb_config /** * Creates a configuration container with a default set of values * - * @param dbal $db Database connection + * @param phpbb_db_driver $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) + public function __construct(phpbb_db_driver $db, phpbb_cache_driver_interface $cache, $table) { $this->db = $db; $this->cache = $cache; diff --git a/phpBB/includes/cron/task/core/prune_all_forums.php b/phpBB/includes/cron/task/core/prune_all_forums.php index ee0b5f7626..2c5d38cec0 100644 --- a/phpBB/includes/cron/task/core/prune_all_forums.php +++ b/phpBB/includes/cron/task/core/prune_all_forums.php @@ -37,9 +37,9 @@ class phpbb_cron_task_core_prune_all_forums extends phpbb_cron_task_base * @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 + * @param phpbb_db_driver $db The db connection */ - public function __construct($phpbb_root_path, $php_ext, phpbb_config $config, dbal $db) + public function __construct($phpbb_root_path, $php_ext, phpbb_config $config, phpbb_db_driver $db) { $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; diff --git a/phpBB/includes/cron/task/core/prune_forum.php b/phpBB/includes/cron/task/core/prune_forum.php index fa7a761d88..e3c497f072 100644 --- a/phpBB/includes/cron/task/core/prune_forum.php +++ b/phpBB/includes/cron/task/core/prune_forum.php @@ -47,9 +47,9 @@ class phpbb_cron_task_core_prune_forum extends phpbb_cron_task_base implements p * @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 + * @param phpbb_db_driver $db The db connection */ - public function __construct($phpbb_root_path, $php_ext, phpbb_config $config, dbal $db) + public function __construct($phpbb_root_path, $php_ext, phpbb_config $config, phpbb_db_driver $db) { $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; diff --git a/phpBB/includes/cron/task/core/tidy_search.php b/phpBB/includes/cron/task/core/tidy_search.php index fdbe31346e..3ec25aa021 100644 --- a/phpBB/includes/cron/task/core/tidy_search.php +++ b/phpBB/includes/cron/task/core/tidy_search.php @@ -38,10 +38,10 @@ class phpbb_cron_task_core_tidy_search extends phpbb_cron_task_base * @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_db_driver $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) + public function __construct($phpbb_root_path, $php_ext, phpbb_auth $auth, phpbb_config $config, phpbb_db_driver $db, phpbb_user $user) { $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; diff --git a/phpBB/includes/db/db_tools.php b/phpBB/includes/db/db_tools.php index 6df3aac9ce..2bb016cebd 100644 --- a/phpBB/includes/db/db_tools.php +++ b/phpBB/includes/db/db_tools.php @@ -300,7 +300,7 @@ class phpbb_db_tools /** * Constructor. Set DB Object and set {@link $return_statements return_statements}. * - * @param phpbb_dbal $db DBAL object + * @param phpbb_db_driver $db Database connection * @param bool $return_statements True if only statements should be returned and no SQL being executed */ function phpbb_db_tools(&$db, $return_statements = false) diff --git a/phpBB/includes/db/dbal.php b/phpBB/includes/db/driver/driver.php index ef1dd7d14d..25daa7243d 100644 --- a/phpBB/includes/db/dbal.php +++ b/phpBB/includes/db/driver/driver.php @@ -19,7 +19,7 @@ if (!defined('IN_PHPBB')) * Database Abstraction Layer * @package dbal */ -class dbal +class phpbb_db_driver { var $db_connect_id; var $query_result; @@ -72,17 +72,17 @@ class dbal /** * Constructor */ - function dbal() + function __construct() { $this->num_queries = array( - 'cached' => 0, - 'normal' => 0, - 'total' => 0, + '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); + $this->sql_layer = substr(get_class($this), strlen('phpbb_db_driver_')); // Do not change this please! This variable is used to easy the use of it - and is hardcoded. $this->any_char = chr(0) . '%'; @@ -1042,8 +1042,3 @@ class dbal 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/driver/firebird.php index 5728eb901c..4767b29f63 100644 --- a/phpBB/includes/db/firebird.php +++ b/phpBB/includes/db/driver/firebird.php @@ -15,14 +15,12 @@ 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 +class phpbb_db_driver_firebird extends phpbb_db_driver { var $last_query_text = ''; var $service_handle = false; @@ -272,7 +270,7 @@ class dbal_firebird extends dbal 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); + $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { diff --git a/phpBB/includes/db/mssql.php b/phpBB/includes/db/driver/mssql.php index 235c48d3f0..215c6345c6 100644 --- a/phpBB/includes/db/mssql.php +++ b/phpBB/includes/db/driver/mssql.php @@ -15,14 +15,12 @@ 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 +class phpbb_db_driver_mssql extends phpbb_db_driver { var $connect_error = ''; @@ -170,7 +168,7 @@ class dbal_mssql extends dbal 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); + $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { diff --git a/phpBB/includes/db/mssql_odbc.php b/phpBB/includes/db/driver/mssql_odbc.php index 2194de4a5e..7d93f939a2 100644 --- a/phpBB/includes/db/mssql_odbc.php +++ b/phpBB/includes/db/driver/mssql_odbc.php @@ -15,8 +15,6 @@ 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... @@ -28,7 +26,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); * * @package dbal */ -class dbal_mssql_odbc extends dbal +class phpbb_db_driver_mssql_odbc extends phpbb_db_driver { var $last_query_text = ''; var $connect_error = ''; @@ -199,7 +197,7 @@ class dbal_mssql_odbc extends dbal 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); + $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { diff --git a/phpBB/includes/db/mssqlnative.php b/phpBB/includes/db/driver/mssqlnative.php index 4a969828e7..f88c702d07 100644 --- a/phpBB/includes/db/mssqlnative.php +++ b/phpBB/includes/db/driver/mssqlnative.php @@ -19,8 +19,6 @@ 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. @@ -193,7 +191,7 @@ class result_mssqlnative /** * @package dbal */ -class dbal_mssqlnative extends dbal +class phpbb_db_driver_mssqlnative extends phpbb_db_driver { var $m_insert_id = NULL; var $last_query_text = ''; @@ -339,7 +337,7 @@ class dbal_mssqlnative extends dbal 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); + $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { diff --git a/phpBB/includes/db/mysql.php b/phpBB/includes/db/driver/mysql.php index dcdeec0401..30f78c9231 100644 --- a/phpBB/includes/db/mysql.php +++ b/phpBB/includes/db/driver/mysql.php @@ -15,8 +15,6 @@ if (!defined('IN_PHPBB')) exit; } -include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); - /** * MySQL4 Database Abstraction Layer * Compatible with: @@ -26,7 +24,7 @@ include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); * MySQL 5.0+ * @package dbal */ -class dbal_mysql extends dbal +class phpbb_db_driver_mysql extends phpbb_db_driver { var $multi_insert = true; var $connect_error = ''; @@ -208,7 +206,7 @@ class dbal_mysql extends dbal 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); + $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { diff --git a/phpBB/includes/db/mysqli.php b/phpBB/includes/db/driver/mysqli.php index 5713b1992c..4f45c5781c 100644 --- a/phpBB/includes/db/mysqli.php +++ b/phpBB/includes/db/driver/mysqli.php @@ -15,15 +15,13 @@ 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 +class phpbb_db_driver_mysqli extends phpbb_db_driver { var $multi_insert = true; var $connect_error = ''; @@ -203,7 +201,7 @@ class dbal_mysqli extends dbal if ($cache_ttl) { - $this->query_result = $cache->sql_save($query, $this->query_result, $cache_ttl); + $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } } else if (defined('DEBUG')) diff --git a/phpBB/includes/db/oracle.php b/phpBB/includes/db/driver/oracle.php index 4a2b107865..53f9dd71e0 100644 --- a/phpBB/includes/db/oracle.php +++ b/phpBB/includes/db/driver/oracle.php @@ -15,13 +15,11 @@ 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 +class phpbb_db_driver_oracle extends phpbb_db_driver { var $last_query_text = ''; var $connect_error = ''; @@ -448,7 +446,7 @@ class dbal_oracle extends dbal 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); + $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { diff --git a/phpBB/includes/db/postgres.php b/phpBB/includes/db/driver/postgres.php index 8dfbfc3b60..cca97c9c0e 100644 --- a/phpBB/includes/db/postgres.php +++ b/phpBB/includes/db/driver/postgres.php @@ -15,19 +15,12 @@ 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 +class phpbb_db_driver_postgres extends phpbb_db_driver { var $last_query_text = ''; var $connect_error = ''; @@ -218,7 +211,7 @@ class dbal_postgres extends dbal 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); + $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { diff --git a/phpBB/includes/db/sqlite.php b/phpBB/includes/db/driver/sqlite.php index 06e368d586..155409b665 100644 --- a/phpBB/includes/db/sqlite.php +++ b/phpBB/includes/db/driver/sqlite.php @@ -15,14 +15,12 @@ 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 +class phpbb_db_driver_sqlite extends phpbb_db_driver { var $connect_error = ''; @@ -154,7 +152,7 @@ class dbal_sqlite extends dbal 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); + $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl); } else if (strpos($query, 'SELECT') === 0 && $this->query_result) { diff --git a/phpBB/includes/di/extension/config.php b/phpBB/includes/di/extension/config.php index fb5ca90070..97a6290066 100644 --- a/phpBB/includes/di/extension/config.php +++ b/phpBB/includes/di/extension/config.php @@ -43,8 +43,8 @@ class phpbb_di_extension_config extends Extension 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('cache.driver.class', $this->convert_30_acm_type($acm_type)); + $container->setParameter('dbal.driver.class', phpbb_convert_30_dbms_to_31($dbms)); $container->setParameter('dbal.dbhost', $dbhost); $container->setParameter('dbal.dbuser', $dbuser); $container->setParameter('dbal.dbpasswd', $dbpasswd); @@ -66,12 +66,12 @@ class phpbb_di_extension_config extends Extension } /** - * Convert old (3.0) values to 3.1 class names + * Convert 3.0 ACM type to 3.1 cache driver class name * - * @param style $acm_type ACM type - * @return ACM type class + * @param string $acm_type ACM type + * @return cache driver class */ - protected function fix_acm_type($acm_type) + protected function convert_30_acm_type($acm_type) { if (preg_match('#^[a-z]+$#', $acm_type)) { diff --git a/phpBB/includes/di/service_collection.php b/phpBB/includes/di/service_collection.php index 60323c8dba..880cb46d4d 100644 --- a/phpBB/includes/di/service_collection.php +++ b/phpBB/includes/di/service_collection.php @@ -43,7 +43,7 @@ class phpbb_di_service_collection extends ArrayObject public function add($name) { $task = $this->container->get($name); - $task->set_name($name); + $this->offsetSet($name, $task); } } diff --git a/phpBB/includes/extension/manager.php b/phpBB/includes/extension/manager.php index bfd4edde93..67cc81e407 100644 --- a/phpBB/includes/extension/manager.php +++ b/phpBB/includes/extension/manager.php @@ -34,7 +34,7 @@ class phpbb_extension_manager /** * Creates a manager and loads information from database * - * @param dbal $db A database connection + * @param phpbb_db_driver $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. @@ -42,7 +42,7 @@ class phpbb_extension_manager * @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') + public function __construct(phpbb_db_driver $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; diff --git a/phpBB/includes/extension/metadata_manager.php b/phpBB/includes/extension/metadata_manager.php index ea85bd3c4e..36b0f8b184 100644 --- a/phpBB/includes/extension/metadata_manager.php +++ b/phpBB/includes/extension/metadata_manager.php @@ -34,12 +34,12 @@ class phpbb_extension_metadata_manager /** * Creates the metadata manager * - * @param dbal $db A database connection + * @param phpbb_db_driver $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) + public function __construct($ext_name, phpbb_db_driver $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; diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php index ebe9a9918d..8ef5284134 100644 --- a/phpBB/includes/functions.php +++ b/phpBB/includes/functions.php @@ -4894,12 +4894,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('&', '&', $data); + $data = str_replace('>', '>', $data); + $data = str_replace('<', '<', $data); + + $data = str_replace("\n", ' ', $data); + $data = str_replace("\r", ' ', $data); + $data = str_replace("\t", '	', $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('"', '"', $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; if (defined('HEADER_INC')) { @@ -5088,6 +5183,8 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0 $timezone_name = $user->lang['timezones'][$timezone_name]; } + $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 +5199,7 @@ 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, 'S_USER_NEW_PRIVMSG' => $user->data['user_new_privmsg'], 'S_USER_UNREAD_PRIVMSG' => $user->data['user_unread_privmsg'], @@ -5452,6 +5550,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 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..cd4c901b58 100644 --- a/phpBB/includes/functions_display.php +++ b/phpBB/includes/functions_display.php @@ -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>') @@ -313,6 +327,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 diff --git a/phpBB/includes/functions_download.php b/phpBB/includes/functions_download.php index fc6f1cc762..9ae647d806 100644 --- a/phpBB/includes/functions_download.php +++ b/phpBB/includes/functions_download.php @@ -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 * @@ -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 * diff --git a/phpBB/includes/functions_install.php b/phpBB/includes/functions_install.php index ab6b3ea009..2b4b7eb10d 100644 --- a/phpBB/includes/functions_install.php +++ b/phpBB/includes/functions_install.php @@ -28,7 +28,7 @@ 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, ), @@ -37,7 +37,7 @@ function get_available_dbms($dbms = false, $return_unavailable = false, $only_20 'SCHEMA' => 'mysql_41', 'MODULE' => 'mysqli', 'DELIM' => ';', - 'DRIVER' => 'mysqli', + 'DRIVER' => 'phpbb_db_driver_mysqli', 'AVAILABLE' => true, '2.0.x' => true, ), @@ -46,7 +46,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 +55,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 +64,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 +73,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 +82,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 +91,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 +100,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, ), @@ -205,26 +205,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 +226,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 +236,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 +289,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 +384,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 +406,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;"; diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php index a18aeddabd..d0a02567ad 100644 --- a/phpBB/includes/functions_messenger.php +++ b/phpBB/includes/functions_messenger.php @@ -210,7 +210,7 @@ class messenger { $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()); + $tpl = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, new phpbb_template_context(), $phpbb_extension_manager); $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; @@ -231,7 +231,7 @@ class messenger } } - $style->set_custom_style($template_lang . '_email', array($template_path, $fallback_template_path), ''); + $style->set_custom_style($template_lang . '_email', array($template_path, $fallback_template_path), array(), ''); $tpl->set_filenames(array( 'body' => $template_file . '.txt', diff --git a/phpBB/includes/functions_posting.php b/phpBB/includes/functions_posting.php index 171cf988ce..8aea27a9ef 100644 --- a/phpBB/includes/functions_posting.php +++ b/phpBB/includes/functions_posting.php @@ -1695,8 +1695,9 @@ function submit_post($mode, $subject, $username, $topic_type, &$poll, &$data, $u // The variable name should be $post_approved, because it indicates if the post is approved or not $post_approval = 1; - // Check the permissions for post approval. 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; 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/lock/db.php b/phpBB/includes/lock/db.php index 6e94dd5a85..ccdaed0b28 100644 --- a/phpBB/includes/lock/db.php +++ b/phpBB/includes/lock/db.php @@ -48,7 +48,7 @@ class phpbb_lock_db /** * A database connection - * @var dbal + * @var phpbb_db_driver */ private $db; @@ -59,9 +59,9 @@ class phpbb_lock_db * * @param string $config_name A config variable to be used for locking * @param array $config The phpBB configuration - * @param dbal $db A database connection + * @param phpbb_db_driver $db A database connection */ - public function __construct($config_name, phpbb_config $config, dbal $db) + public function __construct($config_name, phpbb_config $config, phpbb_db_driver $db) { $this->config_name = $config_name; $this->config = $config; diff --git a/phpBB/includes/mcp/mcp_forum.php b/phpBB/includes/mcp/mcp_forum.php index 4dd5e5856a..0fad9e2a22 100644 --- a/phpBB/includes/mcp/mcp_forum.php +++ b/phpBB/includes/mcp/mcp_forum.php @@ -430,13 +430,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 . '&t=' . $to_topic_id) . '">', '</a>'); diff --git a/phpBB/includes/mcp/mcp_main.php b/phpBB/includes/mcp/mcp_main.php index 95ca7c2e1b..c28b466bcf 100644 --- a/phpBB/includes/mcp/mcp_main.php +++ b/phpBB/includes/mcp/mcp_main.php @@ -1080,6 +1080,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,6 +1101,27 @@ function mcp_fork_topic($topic_ids) { $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) $new_topic_id, + 'user_id' => (int) $row['user_id'], + ); + } + $db->sql_freeresult($result); + + if (sizeof($sql_ary)) + { + $db->sql_multi_insert(BOOKMARKS_TABLE, $sql_ary); + } } // Sync new topics, parent forums and board stats diff --git a/phpBB/includes/mcp/mcp_topic.php b/phpBB/includes/mcp/mcp_topic.php index 63ff7bed72..e3dd5a6b57 100644 --- a/phpBB/includes/mcp/mcp_topic.php +++ b/phpBB/includes/mcp/mcp_topic.php @@ -521,6 +521,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 +666,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', $topic_ids, $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', $topic_id, $to_topic_id); } // Link to the new topic 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/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/search/fulltext_mysql.php b/phpBB/includes/search/fulltext_mysql.php index ff2e24aa05..324c214e91 100644 --- a/phpBB/includes/search/fulltext_mysql.php +++ b/phpBB/includes/search/fulltext_mysql.php @@ -41,8 +41,8 @@ class phpbb_search_fulltext_mysql extends phpbb_search_base protected $config; /** - * DBAL object - * @var dbal + * Database connection + * @var phpbb_db_driver */ protected $db; diff --git a/phpBB/includes/search/fulltext_native.php b/phpBB/includes/search/fulltext_native.php index 4623326fc7..53df8348ae 100644 --- a/phpBB/includes/search/fulltext_native.php +++ b/phpBB/includes/search/fulltext_native.php @@ -85,8 +85,8 @@ class phpbb_search_fulltext_native extends phpbb_search_base protected $config; /** - * DBAL object - * @var dbal + * Database connection + * @var phpbb_db_driver */ protected $db; diff --git a/phpBB/includes/search/fulltext_postgres.php b/phpBB/includes/search/fulltext_postgres.php index 2880610655..f22ee2ca16 100644 --- a/phpBB/includes/search/fulltext_postgres.php +++ b/phpBB/includes/search/fulltext_postgres.php @@ -66,8 +66,8 @@ class phpbb_search_fulltext_postgres extends phpbb_search_base protected $config; /** - * DBAL object - * @var dbal + * Database connection + * @var phpbb_db_driver */ protected $db; diff --git a/phpBB/includes/search/fulltext_sphinx.php b/phpBB/includes/search/fulltext_sphinx.php index dd5634b623..4bacf74f93 100644 --- a/phpBB/includes/search/fulltext_sphinx.php +++ b/phpBB/includes/search/fulltext_sphinx.php @@ -84,8 +84,8 @@ class phpbb_search_fulltext_sphinx protected $config; /** - * DBAL object - * @var dbal + * Database connection + * @var phpbb_db_driver */ protected $db; @@ -875,7 +875,7 @@ class phpbb_search_fulltext_sphinx </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> + <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> diff --git a/phpBB/includes/style/style.php b/phpBB/includes/style/style.php index effd496fb9..4703c3a219 100644 --- a/phpBB/includes/style/style.php +++ b/phpBB/includes/style/style.php @@ -91,16 +91,22 @@ class phpbb_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)); + + $names = array($style_path); foreach ($style_dirs as $dir) { - $paths[] = $this->get_style_path($dir); + $names[] = $dir; } + // Add 'all' path, used as last fallback path by events and extensions + //$names[] = 'all'; - // Add 'all' path, used as last fallback path by hooks and extensions - $paths[] = $this->get_style_path('all'); + $paths = array(); + foreach ($names as $name) + { + $paths[] = $this->get_style_path($name); + } - return $this->set_custom_style($style_path, $paths); + return $this->set_custom_style($style_path, $paths, $names); } /** @@ -110,18 +116,27 @@ class phpbb_style * * @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 array $names Array of names of templates in inheritance tree order, used by extensions. If empty, $name will be used. * @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) + public function set_custom_style($name, $paths, $names = array(), $template_path = false) { if (is_string($paths)) { $paths = array($paths); } + if (empty($names)) + { + $names = array($name); + } + $this->names = $names; + $this->provider->set_styles($paths); $this->locator->set_paths($this->provider); + $this->template->set_style_names($names); + if ($template_path !== false) { $this->locator->set_template_path($template_path); diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php index 22da21820e..fcdaf7abda 100644 --- a/phpBB/includes/template/compile.php +++ b/phpBB/includes/template/compile.php @@ -35,16 +35,23 @@ class phpbb_template_compile /** * Constructor. * - * @param bool @allow_php Whether PHP code will be allowed in templates (inline PHP code, PHP tag and INCLUDEPHP tag) + * @param bool $allow_php Whether PHP code will be allowed in templates (inline PHP code, PHP tag and INCLUDEPHP tag) + * @param array $style_names Name of style to which the template being compiled belongs and parents in style tree order * @param phpbb_style_resource_locator $locator Resource locator * @param string $phpbb_root_path Path to phpBB root directory + * @param phpbb_extension_manager $extension_manager Extension manager to use for finding template fragments in extensions; if null, template events will not be invoked + * @param phpbb_user $user Current user */ - public function __construct($allow_php, $locator, $phpbb_root_path) + public function __construct($allow_php, $style_names, $locator, $phpbb_root_path, $extension_manager = null, $user = null) { $this->filter_params = array( 'allow_php' => $allow_php, + 'style_names' => $style_names, 'locator' => $locator, - 'phpbb_root_path' => $phpbb_root_path + 'phpbb_root_path' => $phpbb_root_path, + 'extension_manager' => $extension_manager, + 'user' => $user, + 'template_compile' => $this, ); } diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php index 66d28242a3..f73ad28ba1 100644 --- a/phpBB/includes/template/filter.php +++ b/phpBB/includes/template/filter.php @@ -88,6 +88,37 @@ class phpbb_template_filter extends php_user_filter private $phpbb_root_path; /** + * Name of the style that the template being compiled and/or rendered + * belongs to, and its parents, in inheritance tree order. + * + * Used to invoke style-specific template events. + * + * @var array + */ + private $style_names; + + /** + * Extension manager. + * + * @var phpbb_extension_manager + */ + private $extension_manager; + + /** + * Current user + * + * @var phpbb_user + */ + private $user; + + /** + * Template compiler. + * + * @var phpbb_template_compile + */ + private $template_compile; + + /** * Stream filter * * Is invoked for evey chunk of the stream, allowing us @@ -138,8 +169,10 @@ class phpbb_template_filter extends php_user_filter /** * Initializer, called on creation. * - * Get the allow_php option, root directory and locator from params, + * Get the allow_php option, style_names, root directory and locator from params, * which are passed to stream_filter_append. + * + * @return boolean Returns true */ public function onCreate() { @@ -148,6 +181,13 @@ class phpbb_template_filter extends php_user_filter $this->allow_php = $this->params['allow_php']; $this->locator = $this->params['locator']; $this->phpbb_root_path = $this->params['phpbb_root_path']; + $this->style_names = $this->params['style_names']; + $this->extension_manager = $this->params['extension_manager']; + if (isset($this->params['user'])) + { + $this->user = $this->params['user']; + } + $this->template_compile = $this->params['template_compile']; return true; } @@ -229,7 +269,9 @@ class phpbb_template_filter extends php_user_filter } /** - * Callback for replacing matched tokens with PHP code + * Callback for replacing matched tokens with compiled template code. + * + * Compiled template code is an HTML stream with embedded PHP. * * @param array $matches Regular expression matches * @return string compiled template code @@ -317,6 +359,10 @@ class phpbb_template_filter extends php_user_filter return '<!-- ENDPHP -->'; break; + case 'EVENT': + return '<?php ' . $this->compile_tag_event($matches[2]) . '?>'; + break; + default: return $matches[0]; break; @@ -836,6 +882,97 @@ class phpbb_template_filter extends php_user_filter } /** + * Compile EVENT tag. + * + * $tag_args should be a single string identifying the event. + * The event name can contain letters, numbers and underscores only. + * If an invalid event name is specified, an E_USER_ERROR will be + * triggered. + * + * Event tags are only functional when the template engine has + * an instance of the extension manager. Extension manager would + * be called upon to find all extensions listening for the specified + * event, and to obtain additional template fragments. All such + * template fragments will be compiled and included in the generated + * compiled template code for the current template being compiled. + * + * The above means that whenever an extension is enabled or disabled, + * template cache should be cleared in order to update the compiled + * template code for the active set of template event listeners. + * + * This also means that extensions cannot return different template + * fragments at different times. Once templates are compiled, changing + * such template fragments would have no effect. + * + * @param string $tag_args EVENT tag arguments, as a string - for EVENT this is the event name + * @return string compiled template code + */ + private function compile_tag_event($tag_args) + { + if (!preg_match('/^\w+$/', $tag_args)) + { + // The event location is improperly formatted, + if ($this->user) + { + trigger_error($this->user->lang('ERR_TEMPLATE_EVENT_LOCATION', $tag_args), E_USER_ERROR); + } + else + { + trigger_error(sprintf('The specified template event location <em>[%s]</em> is improperly formatted.', $tag_args), E_USER_ERROR); + } + } + $location = $tag_args; + + if ($this->extension_manager) + { + $finder = $this->extension_manager->get_finder(); + + $files = $finder + ->extension_prefix($location) + ->extension_suffix('.html') + ->extension_directory("/styles/all/template") + ->get_files(); + + foreach ($this->style_names as $style_name) + { + $more_files = $finder + ->extension_prefix($location) + ->extension_suffix('.html') + ->extension_directory("/styles/" . $style_name . "/template") + ->get_files(); + if (!empty($more_files)) + { + $files = array_merge($files, $more_files); + break; + } + } + + $all_compiled = ''; + foreach ($files as $file) + { + $compiled = $this->template_compile->compile_file($file); + + if ($compiled === false) + { + if ($this->user) + { + trigger_error($this->user->lang('ERR_TEMPLATE_COMPILATION', phpbb_filter_root_path($file)), E_USER_ERROR); + } + else + { + trigger_error(sprintf('The file could not be compiled: %s', phpbb_filter_root_path($file)), E_USER_ERROR); + } + } + + $all_compiled .= $compiled; + } + // Need spaces inside php tags as php cannot grok + // < ?php? > sans the spaces + return ' ?' . '>' . $all_compiled . '<?php '; + } + } + + /** * parse expression * This is from Smarty */ diff --git a/phpBB/includes/template/locator.php b/phpBB/includes/template/locator.php index 42db91efb2..f6fd20bcc2 100644 --- a/phpBB/includes/template/locator.php +++ b/phpBB/includes/template/locator.php @@ -39,7 +39,7 @@ 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. + * @param array $filename_array Should be a hash of handle => filename pairs. */ public function set_filenames(array $filename_array); @@ -66,7 +66,7 @@ interface phpbb_template_locator * 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 + * 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 diff --git a/phpBB/includes/template/template.php b/phpBB/includes/template/template.php index 5396ddbfad..bbec768613 100644 --- a/phpBB/includes/template/template.php +++ b/phpBB/includes/template/template.php @@ -75,14 +75,32 @@ class phpbb_template private $locator; /** + * Extension manager. + * + * @var phpbb_extension_manager + */ + private $extension_manager; + + /** + * Name of the style that the template being compiled and/or rendered + * belongs to, and its parents, in inheritance tree order. + * + * Used to invoke style-specific template events. + * + * @var array + */ + private $style_names; + + /** * 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 + * @param phpbb_extension_manager $extension_manager extension manager, if null then template events will not be invoked */ - public function __construct($phpbb_root_path, $php_ext, $config, $user, phpbb_template_locator $locator, phpbb_template_context $context) + public function __construct($phpbb_root_path, $php_ext, $config, $user, phpbb_template_locator $locator, phpbb_template_context $context, phpbb_extension_manager $extension_manager = null) { $this->phpbb_root_path = $phpbb_root_path; $this->php_ext = $php_ext; @@ -90,12 +108,13 @@ class phpbb_template $this->user = $user; $this->locator = $locator; $this->context = $context; + $this->extension_manager = $extension_manager; } /** * Sets the template filenames for handles. * - * @param array $filname_array Should be a hash of handle => filename pairs. + * @param array $filename_array Should be a hash of handle => filename pairs. */ public function set_filenames(array $filename_array) { @@ -105,6 +124,18 @@ class phpbb_template } /** + * Sets the style names corresponding to style hierarchy being compiled + * and/or rendered. + * + * @param array $style_names List of style names in inheritance tree order + * @return null + */ + public function set_style_names(array $style_names) + { + $this->style_names = $style_names; + } + + /** * Clears all variables and blocks assigned to this template. */ public function destroy() @@ -282,7 +313,7 @@ class phpbb_template 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); + $compile = new phpbb_template_compile($this->config['tpl_allow_php'], $this->style_names, $this->locator, $this->phpbb_root_path, $this->extension_manager, $this->user); if ($compile->compile_file_to_file($source_file, $output_file) !== false) { diff --git a/phpBB/install/convertors/convert_phpbb20.php b/phpBB/install/convertors/convert_phpbb20.php index 68acea02b3..5f30625980 100644 --- a/phpBB/install/convertors/convert_phpbb20.php +++ b/phpBB/install/convertors/convert_phpbb20.php @@ -24,6 +24,8 @@ if (!defined('IN_PHPBB')) include($phpbb_root_path . 'config.' . $phpEx); unset($dbpasswd); +$dbms = phpbb_convert_30_dbms_to_31($dbms); + /** * $convertor_data provides some basic information about this convertor which is * used on the initial list of convertors and to populate the default settings diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php index 30592b995d..1698e7777a 100644 --- a/phpBB/install/database_update.php +++ b/phpBB/install/database_update.php @@ -83,7 +83,6 @@ phpbb_require_updated('includes/functions_content.' . $phpEx, true); require($phpbb_root_path . 'includes/functions_admin.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); -require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx); phpbb_require_updated('includes/db/db_tools.' . $phpEx); @@ -818,6 +817,70 @@ function _add_modules($modules_to_install) $_module->remove_cache_file(); } +/** +* Add a new permission, optionally copy permission setting from another +* +* @param auth_admin $auth_admin auth_admin object +* @param phpbb_db_driver $db Database object +* @param string $permission_name Name of the permission to add +* @param bool $is_global True is global, false is local +* @param string $copy_from Optional permission name from which to copy +* @return bool true on success, false on failure +*/ +function _add_permission(auth_admin $auth_admin, phpbb_db_driver $db, $permission_name, $is_global = true, $copy_from = '') +{ + // Only add a permission that don't already exist + if (!empty($auth_admin->acl_options['id'][$permission_name])) + { + return true; + } + + $permission_scope = $is_global ? 'global' : 'local'; + + $result = $auth_admin->acl_add_option(array( + $permission_scope => array($permission_name), + )); + + if (!$result) + { + return $result; + } + + // The permission has been added, now we can copy it if needed + if ($copy_from && isset($auth_admin->acl_options['id'][$copy_from])) + { + $old_id = $auth_admin->acl_options['id'][$copy_from]; + $new_id = $auth_admin->acl_options['id'][$permission_name]; + + $tables = array(ACL_GROUPS_TABLE, ACL_ROLES_DATA_TABLE, ACL_USERS_TABLE); + + foreach ($tables as $table) + { + $sql = 'SELECT * + FROM ' . $table . ' + WHERE auth_option_id = ' . $old_id; + $result = _sql($sql, $errored, $error_ary); + + $sql_ary = array(); + while ($row = $db->sql_fetchrow($result)) + { + $row['auth_option_id'] = $new_id; + $sql_ary[] = $row; + } + $db->sql_freeresult($result); + + if (sizeof($sql_ary)) + { + $db->sql_multi_insert($table, $sql_ary); + } + } + + $auth_admin->acl_clear_prefetch(); + } + + return true; +} + /**************************************************************************** * ADD YOUR DATABASE SCHEMA CHANGES HERE * *****************************************************************************/ @@ -2459,6 +2522,12 @@ function change_database_data(&$no_updates, $version) unset($next_legend); } + // Rename styles module to Customise + $sql = 'UPDATE ' . MODULES_TABLE . " + SET module_langname = 'ACP_CAT_CUSTOMISE' + WHERE module_langname = 'ACP_CAT_STYLES'"; + _sql($sql, $errored, $error_ary); + // Install modules $modules_to_install = array( 'position' => array( @@ -2496,10 +2565,67 @@ function change_database_data(&$no_updates, $version) 'auth' => '', 'cat' => 'UCP_PROFILE', ), + // To add a category, the mode and basename must be empty + // The mode is taken from the array key + '' => array( + 'base' => '', + 'class' => 'acp', + 'title' => 'ACP_EXTENSION_MANAGEMENT', + 'auth' => 'acl_a_extensions', + 'cat' => 'ACP_CAT_CUSTOMISE', + ), + 'extensions' => array( + 'base' => 'acp_extensions', + 'class' => 'acp', + 'title' => 'ACP_EXTENSIONS', + 'auth' => 'acl_a_extensions', + 'cat' => 'ACP_EXTENSION_MANAGEMENT', + ), + ); + + _add_modules($modules_to_install); + + // We need a separate array for the new language sub heading + // because it requires another empty key + $modules_to_install = array( + '' => array( + 'base' => '', + 'class' => 'acp', + 'title' => 'ACP_LANGUAGE', + 'auth' => 'acl_a_language', + 'cat' => 'ACP_CAT_CUSTOMISE', + ), ); _add_modules($modules_to_install); + // Move language management to new location in the Customise tab + // First get language module id + $sql = 'SELECT module_id FROM ' . MODULES_TABLE . " + WHERE module_basename = 'acp_language'"; + $result = $db->sql_query($sql); + $language_module_id = $db->sql_fetchfield('module_id'); + $db->sql_freeresult($result); + // Next get language management module id of the one just created + $sql = 'SELECT module_id FROM ' . MODULES_TABLE . " + WHERE module_langname = 'ACP_LANGUAGE'"; + $result = $db->sql_query($sql); + $language_management_module_id = $db->sql_fetchfield('module_id'); + $db->sql_freeresult($result); + + if (!class_exists('acp_modules')) + { + include($phpbb_root_path . 'includes/acp/acp_modules.' . $phpEx); + } + // acp_modules calls adm_back_link, which is undefined at this point + if (!function_exists('adm_back_link')) + { + include($phpbb_root_path . 'includes/functions_acp.' . $phpEx); + } + $module_manager = new acp_modules(); + $module_manager->module_class = 'acp'; + $module_manager->move_module($language_module_id, $language_management_module_id); + $sql = 'DELETE FROM ' . MODULES_TABLE . " WHERE (module_basename = 'styles' OR module_basename = 'acp_styles') AND (module_mode = 'imageset' OR module_mode = 'theme' OR module_mode = 'template')"; _sql($sql, $errored, $error_ary); @@ -2759,7 +2885,11 @@ function change_database_data(&$no_updates, $version) set_config('board_timezone', $update_helpers->convert_phpbb30_timezone($config['board_timezone'], $config['board_dst'])); // After we have calculated the timezones we can delete user_dst column from user table. - $db_tools->sql_column_remove(USERS_TABLE, 'user_dst'); + $statements = $db_tools->sql_column_remove(USERS_TABLE, 'user_dst'); + foreach ($statements as $sql) + { + _sql($sql, $errored, $error_ary); + } } if (!isset($config['site_home_url'])) @@ -2790,45 +2920,12 @@ function change_database_data(&$no_updates, $version) } $db->sql_freeresult($result); - // Add new permission u_chgprofileinfo and duplicate settings from u_sig + // Add new permissions include_once($phpbb_root_path . 'includes/acp/auth.' . $phpEx); $auth_admin = new auth_admin(); - // Only add the new permission if it does not already exist - if (empty($auth_admin->acl_options['id']['u_chgprofileinfo'])) - { - $auth_admin->acl_add_option(array('global' => array('u_chgprofileinfo'))); - - // Now the tricky part, filling the permission - $old_id = $auth_admin->acl_options['id']['u_sig']; - $new_id = $auth_admin->acl_options['id']['u_chgprofileinfo']; - - $tables = array(ACL_GROUPS_TABLE, ACL_ROLES_DATA_TABLE, ACL_USERS_TABLE); - - foreach ($tables as $table) - { - $sql = 'SELECT * - FROM ' . $table . ' - WHERE auth_option_id = ' . $old_id; - $result = _sql($sql, $errored, $error_ary); - - $sql_ary = array(); - while ($row = $db->sql_fetchrow($result)) - { - $row['auth_option_id'] = $new_id; - $sql_ary[] = $row; - } - $db->sql_freeresult($result); - - if (sizeof($sql_ary)) - { - $db->sql_multi_insert($table, $sql_ary); - } - } - - // Remove any old permission entries - $auth_admin->acl_clear_prefetch(); - } + _add_permission($auth_admin, $db, 'u_chgprofileinfo', true, 'u_sig'); + _add_permission($auth_admin, $db, 'a_extensions', true, 'a_styles'); // Update the auth setting for the module $sql = 'UPDATE ' . MODULES_TABLE . " diff --git a/phpBB/install/index.php b/phpBB/install/index.php index 09560946a6..2be5adaaac 100644 --- a/phpBB/install/index.php +++ b/phpBB/install/index.php @@ -215,7 +215,7 @@ $phpbb_style_path_provider = new phpbb_style_path_provider(); $template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $phpbb_style_resource_locator, new phpbb_template_context()); $phpbb_style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $phpbb_style_resource_locator, $phpbb_style_path_provider, $template); $phpbb_style->set_ext_dir_prefix('adm/'); -$phpbb_style->set_custom_style('admin', '../adm/style', ''); +$phpbb_style->set_custom_style('admin', '../adm/style', array(), ''); $template->assign_var('T_ASSETS_PATH', '../assets'); $template->assign_var('T_TEMPLATE_PATH', '../adm/style'); diff --git a/phpBB/install/install_convert.php b/phpBB/install/install_convert.php index 41de9de44c..9afe341ffa 100644 --- a/phpBB/install/install_convert.php +++ b/phpBB/install/install_convert.php @@ -121,10 +121,11 @@ class install_convert extends module require($phpbb_root_path . 'config.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); - require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); - $db = new $sql_db(); + $dbms = phpbb_convert_30_dbms_to_31($dbms); + + $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); unset($dbpasswd); @@ -209,10 +210,11 @@ class install_convert extends module require($phpbb_root_path . 'config.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); - require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); - $db = new $sql_db(); + $dbms = phpbb_convert_30_dbms_to_31($dbms); + + $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); unset($dbpasswd); @@ -332,10 +334,11 @@ class install_convert extends module require($phpbb_root_path . 'config.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); - require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); - $db = new $sql_db(); + $dbms = phpbb_convert_30_dbms_to_31($dbms); + + $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); unset($dbpasswd); @@ -425,8 +428,7 @@ class install_convert extends module if ($src_dbms != $dbms || $src_dbhost != $dbhost || $src_dbport != $dbport || $src_dbname != $dbname || $src_dbuser != $dbuser) { - $sql_db = 'dbal_' . $src_dbms; - $src_db = new $sql_db(); + $src_db = new $src_dbms(); $src_db->sql_connect($src_dbhost, $src_dbuser, htmlspecialchars_decode($src_dbpasswd), $src_dbname, $src_dbport, false, true); $same_db = false; } @@ -575,10 +577,11 @@ class install_convert extends module require($phpbb_root_path . 'config.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); - require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/functions_convert.' . $phpEx); - $db = new $sql_db(); + $dbms = phpbb_convert_30_dbms_to_31($dbms); + + $db = new $dbms(); $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, true); unset($dbpasswd); @@ -639,12 +642,8 @@ class install_convert extends module $src_db = $same_db = null; if ($convert->src_dbms != $dbms || $convert->src_dbhost != $dbhost || $convert->src_dbport != $dbport || $convert->src_dbname != $dbname || $convert->src_dbuser != $dbuser) { - if ($convert->src_dbms != $dbms) - { - require($phpbb_root_path . 'includes/db/' . $convert->src_dbms . '.' . $phpEx); - } - $sql_db = 'dbal_' . $convert->src_dbms; - $src_db = new $sql_db(); + $dbms = $convert->src_dbms; + $src_db = new $dbms(); $src_db->sql_connect($convert->src_dbhost, $convert->src_dbuser, htmlspecialchars_decode($convert->src_dbpasswd), $convert->src_dbname, $convert->src_dbport, false, true); $same_db = false; } diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php index 4b2fa046bc..14f6ca30fb 100644 --- a/phpBB/install/install_install.php +++ b/phpBB/install/install_install.php @@ -1118,11 +1118,8 @@ class install_install extends module $dbms = $available_dbms[$data['dbms']]['DRIVER']; - // Load the appropriate database class if not already loaded - include($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); - // Instantiate the database - $db = new $sql_db(); + $db = new $dbms(); $db->sql_connect($data['dbhost'], $data['dbuser'], htmlspecialchars_decode($data['dbpasswd']), $data['dbname'], $data['dbport'], false, false); // NOTE: trigger_error does not work here. @@ -1418,11 +1415,8 @@ class install_install extends module $dbms = $available_dbms[$data['dbms']]['DRIVER']; - // Load the appropriate database class if not already loaded - include($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); - // Instantiate the database - $db = new $sql_db(); + $db = new $dbms(); $db->sql_connect($data['dbhost'], $data['dbuser'], htmlspecialchars_decode($data['dbpasswd']), $data['dbname'], $data['dbport'], false, false); // NOTE: trigger_error does not work here. @@ -2095,9 +2089,10 @@ class install_install extends module 'ACP_PERMISSION_ROLES', 'ACP_PERMISSION_MASKS', ), - 'ACP_CAT_STYLES' => array( + 'ACP_CAT_CUSTOMISE' => array( 'ACP_STYLE_MANAGEMENT', - 'ACP_STYLE_COMPONENTS', + 'ACP_EXTENSIONS_MANAGEMENT', + 'ACP_LANGUAGE', ), 'ACP_CAT_MAINTENANCE' => array( 'ACP_FORUM_LOGS', diff --git a/phpBB/install/install_update.php b/phpBB/install/install_update.php index 7f40015002..53f9c52556 100644 --- a/phpBB/install/install_update.php +++ b/phpBB/install/install_update.php @@ -83,7 +83,6 @@ class install_update extends module // Init DB require($phpbb_root_path . 'config.' . $phpEx); - require($phpbb_root_path . 'includes/db/' . $dbms . '.' . $phpEx); require($phpbb_root_path . 'includes/constants.' . $phpEx); // Special options for conflicts/modified files @@ -92,7 +91,9 @@ class install_update extends module define('MERGE_NEW_FILE', 3); define('MERGE_MOD_FILE', 4); - $db = new $sql_db(); + $dbms = phpbb_convert_30_dbms_to_31($dbms); + + $db = new $dbms(); // Connect to DB $db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false); @@ -131,7 +132,7 @@ class install_update extends module } // Set custom template again. ;) - $phpbb_style->set_custom_style('admin', '../adm/style', ''); + $phpbb_style->set_custom_style('admin', '../adm/style', array(), ''); $template->assign_vars(array( 'S_USER_LANG' => $user->lang['USER_LANG'], diff --git a/phpBB/language/en/acp/common.php b/phpBB/language/en/acp/common.php index 5eb10d50b3..427e4f4d98 100644 --- a/phpBB/language/en/acp/common.php +++ b/phpBB/language/en/acp/common.php @@ -59,6 +59,7 @@ $lang = array_merge($lang, array( 'ACP_CAPTCHA' => 'CAPTCHA', + 'ACP_CAT_CUSTOMISE' => 'Customise', 'ACP_CAT_DATABASE' => 'Database', 'ACP_CAT_DOT_MODS' => '.MODs', 'ACP_CAT_FORUMS' => 'Forums', @@ -80,8 +81,10 @@ $lang = array_merge($lang, array( 'ACP_DISALLOW_USERNAMES' => 'Disallow usernames', 'ACP_EMAIL_SETTINGS' => 'Email settings', - 'ACP_EXTENSION_GROUPS' => 'Manage extension groups', - 'ACP_EXTENSIONS' => 'Manage board extensions', + 'ACP_EXTENSION_GROUPS' => 'Manage attachment extension groups', + 'ACP_EXTENSION_MANAGEMENT' => 'Extension management', + 'ACP_EXTENSIONS' => 'Extensions', + 'ACP_FORUM_BASED_PERMISSIONS' => 'Forum based permissions', 'ACP_FORUM_LOGS' => 'Forum logs', @@ -119,7 +122,7 @@ $lang = array_merge($lang, array( 'ACP_MANAGE_ATTACHMENTS' => 'Manage attachments', 'ACP_MANAGE_ATTACHMENTS_EXPLAIN' => 'Here you can list and delete files attached to posts and private messages.', - 'ACP_MANAGE_EXTENSIONS' => 'Manage extensions', + 'ACP_MANAGE_EXTENSIONS' => 'Manage attachment extensions', 'ACP_MANAGE_FORUMS' => 'Manage forums', 'ACP_MANAGE_RANKS' => 'Manage ranks', 'ACP_MANAGE_REASONS' => 'Manage report/denial reasons', @@ -166,7 +169,6 @@ $lang = array_merge($lang, array( 'ACP_SERVER_SETTINGS' => 'Server settings', 'ACP_SIGNATURE_SETTINGS' => 'Signature settings', 'ACP_SMILIES' => 'Smilies', - 'ACP_STYLE_COMPONENTS' => 'Style components', 'ACP_STYLE_MANAGEMENT' => 'Style management', 'ACP_STYLES' => 'Styles', 'ACP_STYLES_CACHE' => 'Purge Cache', diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php index fbb7b40d41..6277457af7 100644 --- a/phpBB/language/en/common.php +++ b/phpBB/language/en/common.php @@ -186,6 +186,8 @@ $lang = array_merge($lang, array( 'ERR_CONNECTING_SERVER' => 'Error connecting to the server.', 'ERR_JAB_AUTH' => 'Could not authorise on Jabber server.', 'ERR_JAB_CONNECT' => 'Could not connect to Jabber server.', + 'ERR_TEMPLATE_EVENT_LOCATION' => 'The specified template event location <em>[%s]</em> is improperly formatted.', + 'ERR_TEMPLATE_COMPILATION' => 'The file could not be compiled: %s', 'ERR_UNABLE_TO_LOGIN' => 'The specified username or password is incorrect.', 'ERR_UNWATCHING' => 'An error occured while trying to unsubscribe.', 'ERR_WATCHING' => 'An error occured while trying to subscribe.', diff --git a/phpBB/posting.php b/phpBB/posting.php index 2d3cb9ab44..d32f7e33d9 100644 --- a/phpBB/posting.php +++ b/phpBB/posting.php @@ -1116,8 +1116,9 @@ if ($submit || $preview || $refresh) $captcha->reset(); } - // Check the permissions for post approval. Moderators are not affected. - if ((!$auth->acl_get('f_noapprove', $data['forum_id']) && !$auth->acl_get('m_approve', $data['forum_id']) && empty($data['force_approved_state'])) || (isset($data['force_approved_state']) && !$data['force_approved_state'])) + // Check the permissions for post approval. + // Moderators must go through post approval like ordinary users. + if ((!$auth->acl_get('f_noapprove', $data['forum_id']) && empty($data['force_approved_state'])) || (isset($data['force_approved_state']) && !$data['force_approved_state'])) { meta_refresh(10, $redirect_url); $message = ($mode == 'edit') ? $user->lang['POST_EDITED_MOD'] : $user->lang['POST_STORED_MOD']; diff --git a/phpBB/styles/prosilver/template/ajax.js b/phpBB/styles/prosilver/template/ajax.js index fa31d3268f..6637df4c3d 100644 --- a/phpBB/styles/prosilver/template/ajax.js +++ b/phpBB/styles/prosilver/template/ajax.js @@ -2,6 +2,94 @@ "use strict"; +/** +* Close popup alert after a specified delay +* +* @param int Delay in ms until darkenwrapper's click event is triggered +*/ +phpbb.closeDarkenWrapper = function(delay) { + setTimeout(function() { + $('#darkenwrapper').trigger('click'); + }, delay); +}; + +// This callback will mark all forum icons read +phpbb.add_ajax_callback('mark_forums_read', function(res) { + var readTitle = res.NO_UNREAD_POSTS; + var unreadTitle = res.UNREAD_POSTS; + var iconsArray = { + 'forum_unread': 'forum_read', + 'forum_unread_subforum': 'forum_read_subforum', + 'forum_unread_locked': 'forum_read_locked', + }; + + $('li.row').find('dl[class*="forum_unread"]').each(function() { + var $this = $(this); + + $.each(iconsArray, function(unreadClass, readClass) { + if ($this.hasClass(unreadClass)) { + $this.removeClass(unreadClass).addClass(readClass); + } + }); + $this.children('dt[title="' + unreadTitle + '"]').attr('title', readTitle); + }); + + // Mark subforums read + $('a.subforum[class*="unread"]').removeClass('unread').addClass('read'); + + // Update mark forums read links + $('[data-ajax="mark_forums_read"]').attr('href', res.U_MARK_FORUMS); + + phpbb.closeDarkenWrapper(3000); +}); + +// This callback will mark all topic icons read +phpbb.add_ajax_callback('mark_topics_read', function(res) { + var readTitle = res.NO_UNREAD_POSTS; + var unreadTitle = res.UNREAD_POSTS; + var iconsArray = { + 'global_unread': 'global_read', + 'announce_unread': 'announce_read', + 'sticky_unread': 'sticky_read', + 'topic_unread': 'topic_read' + }; + var iconsState = ['', '_hot', '_hot_mine', '_locked', '_locked_mine', '_mine']; + var unreadClassSelectors = ''; + var classMap = {}; + var classNames = []; + + $.each(iconsArray, function(unreadClass, readClass) { + $.each(iconsState, function(key, value) { + // Only topics can be hot + if ((value == '_hot' || value == '_hot_mine') && unreadClass != 'topic_unread') { + return true; + } + classMap[unreadClass + value] = readClass + value; + classNames.push(unreadClass + value); + }); + }); + + unreadClassSelectors = '.' + classNames.join(',.'); + + $('li.row').find(unreadClassSelectors).each(function() { + var $this = $(this); + $.each(classMap, function(unreadClass, readClass) { + if ($this.hasClass(unreadClass)) { + $this.removeClass(unreadClass).addClass(readClass); + } + }); + $this.children('dt[title="' + unreadTitle + '"]').attr('title', readTitle); + }); + + // Remove link to first unread post + $('a').has('span.icon_topic_newest').remove(); + + // Update mark topics read links + $('[data-ajax="mark_topics_read"]').attr('href', res.U_MARK_TOPICS); + + phpbb.closeDarkenWrapper(3000); +}); + // This callback finds the post from the delete link, and removes it. phpbb.add_ajax_callback('post_delete', function() { var el = $(this), diff --git a/phpBB/styles/prosilver/template/forumlist_body.html b/phpBB/styles/prosilver/template/forumlist_body.html index 8762cb0c2e..539ed047c9 100644 --- a/phpBB/styles/prosilver/template/forumlist_body.html +++ b/phpBB/styles/prosilver/template/forumlist_body.html @@ -51,6 +51,7 @@ <!-- IF forumrow.U_UNAPPROVED_TOPICS --><a href="{forumrow.U_UNAPPROVED_TOPICS}">{UNAPPROVED_IMG}</a><!-- ENDIF --> <!-- IF forumrow.LAST_POST_TIME --><dfn>{L_LAST_POST}</dfn> <!-- IF forumrow.S_DISPLAY_SUBJECT --> + <!-- EVENT forumlist_body_last_post_title_prepend --> <a href="{forumrow.U_LAST_POST}" title="{forumrow.LAST_POST_SUBJECT}" class="lastsubject">{forumrow.LAST_POST_SUBJECT_TRUNCATED}</a> <br /> <!-- ENDIF --> {L_POST_BY_AUTHOR} {forumrow.LAST_POSTER_FULL} diff --git a/phpBB/styles/prosilver/template/index_body.html b/phpBB/styles/prosilver/template/index_body.html index 6babbf5997..57ad540a4a 100644 --- a/phpBB/styles/prosilver/template/index_body.html +++ b/phpBB/styles/prosilver/template/index_body.html @@ -8,7 +8,7 @@ <!-- IF S_DISPLAY_SEARCH --> <li><a href="{U_SEARCH_UNANSWERED}">{L_SEARCH_UNANSWERED}</a><!-- IF S_LOAD_UNREADS --> • <a href="{U_SEARCH_UNREAD}">{L_SEARCH_UNREAD}</a><!-- ENDIF --><!-- IF S_USER_LOGGED_IN --> • <a href="{U_SEARCH_NEW}">{L_SEARCH_NEW}</a><!-- ENDIF --> • <a href="{U_SEARCH_ACTIVE_TOPICS}">{L_SEARCH_ACTIVE_TOPICS}</a></li> <!-- ENDIF --> - <!-- IF not S_IS_BOT and U_MARK_FORUMS --><li class="rightside"><a href="{U_MARK_FORUMS}" accesskey="m" data-ajax="true">{L_MARK_FORUMS_READ}</a></li><!-- ENDIF --> + <!-- IF not S_IS_BOT and U_MARK_FORUMS --><li class="rightside"><a href="{U_MARK_FORUMS}" accesskey="m" data-ajax="mark_forums_read" data-overlay="false">{L_MARK_FORUMS_READ}</a></li><!-- ENDIF --> </ul> <!-- ENDIF --> @@ -29,6 +29,8 @@ </form> <!-- ENDIF --> +<!-- EVENT index_body_stat_blocks_before --> + <!-- IF S_DISPLAY_ONLINE_LIST --> <!-- IF U_VIEWONLINE --><h3><a href="{U_VIEWONLINE}">{L_WHO_IS_ONLINE}</a></h3><!-- ELSE --><h3>{L_WHO_IS_ONLINE}</h3><!-- ENDIF --> <p>{TOTAL_USERS_ONLINE} ({L_ONLINE_EXPLAIN})<br />{RECORD_USERS}<br /> <br />{LOGGED_IN_USER_LIST} diff --git a/phpBB/styles/prosilver/template/jumpbox.html b/phpBB/styles/prosilver/template/jumpbox.html index ff234464dc..dd793fbadc 100644 --- a/phpBB/styles/prosilver/template/jumpbox.html +++ b/phpBB/styles/prosilver/template/jumpbox.html @@ -10,13 +10,14 @@ <!-- ENDIF --> <!-- IF S_DISPLAY_JUMPBOX --> - <form method="post" id="jumpbox" action="{S_JUMPBOX_ACTION}" onsubmit="if(this.f.value == -1){return false;}"> + <form method="get" id="jumpbox" action="{S_JUMPBOX_ACTION}" onsubmit="if(this.f.value == -1){return false;}"> <!-- IF $CUSTOM_FIELDSET_CLASS --> <fieldset class="{$CUSTOM_FIELDSET_CLASS}"> <!-- ELSE --> <fieldset class="jumpbox"> <!-- ENDIF --> + {HIDDEN_FIELDS_FOR_JUMPBOX} <label for="f" accesskey="j"><!-- IF S_IN_MCP and S_MERGE_SELECT -->{L_SELECT_TOPICS_FROM}<!-- ELSEIF S_IN_MCP -->{L_MODERATE_FORUM}<!-- ELSE -->{L_JUMP_TO}<!-- ENDIF -->{L_COLON}</label> <select name="f" id="f" onchange="if(this.options[this.selectedIndex].value != -1){ document.forms['jumpbox'].submit() }"> <!-- BEGIN jumpbox_forums --> diff --git a/phpBB/styles/prosilver/template/overall_footer.html b/phpBB/styles/prosilver/template/overall_footer.html index 7e43ff2d0a..322d745501 100644 --- a/phpBB/styles/prosilver/template/overall_footer.html +++ b/phpBB/styles/prosilver/template/overall_footer.html @@ -6,7 +6,8 @@ <div class="inner"> <ul class="linklist"> - <li class="icon-home"><!-- IF U_SITE_HOME --><a href="{U_SITE_HOME}">{L_SITE_HOME}</a> <strong>‹</strong> <!-- ENDIF --><a href="{U_INDEX}" accesskey="h">{L_INDEX}</a></li> + <li class="icon-home"><!-- IF U_SITE_HOME --><a href="{U_SITE_HOME}">{L_SITE_HOME}</a> <strong>‹</strong> <!-- ENDIF --><a href="{U_INDEX}" accesskey="h">{L_INDEX}</a> + <!-- EVENT overall_footer_breadcrumb_append --></li> <!-- IF not S_IS_BOT --> <!-- IF U_WATCH_FORUM_LINK --><li <!-- IF S_WATCHING_FORUM -->class="icon-unsubscribe"<!-- ELSE -->class="icon-subscribe"<!-- ENDIF -->><a href="{U_WATCH_FORUM_LINK}" title="{S_WATCH_FORUM_TITLE}" data-ajax="toggle_link" data-toggle-class="icon-<!-- IF not S_WATCHING_FORUM -->unsubscribe<!-- ELSE -->subscribe<!-- ENDIF -->" data-toggle-text="{S_WATCH_FORUM_TOGGLE}" data-toggle-url="{U_WATCH_FORUM_TOGGLE}">{S_WATCH_FORUM_TITLE}</a></li><!-- ENDIF --> <!-- IF U_WATCH_TOPIC --><li <!-- IF S_WATCHING_TOPIC -->class="icon-unsubscribe"<!-- ELSE -->class="icon-subscribe"<!-- ENDIF -->><a href="{U_WATCH_TOPIC}" title="{S_WATCH_TOPIC_TITLE}" data-ajax="toggle_link" data-toggle-class="<!-- IF not S_WATCHING_TOPIC -->icon-unsubscribe<!-- ELSE -->icon-subscribe<!-- ENDIF -->" data-toggle-text="{S_WATCH_TOPIC_TOGGLE}" data-toggle-url="{U_WATCH_TOPIC_TOGGLE}">{S_WATCH_TOPIC_TITLE}</a></li><!-- ENDIF --> @@ -19,8 +20,11 @@ </div> </div> - <div class="copyright">{CREDIT_LINE} + <div class="copyright"> + <!-- EVENT overall_footer_copyright_prepend --> + {CREDIT_LINE} <!-- IF TRANSLATION_INFO --><br />{TRANSLATION_INFO}<!-- ENDIF --> + <!-- EVENT overall_footer_copyright_append --> <!-- IF DEBUG_OUTPUT --><br />{DEBUG_OUTPUT}<!-- ENDIF --> <!-- IF U_ACP --><br /><strong><a href="{U_ACP}">{L_ACP}</a></strong><!-- ENDIF --> </div> @@ -55,5 +59,6 @@ <!-- INCLUDEJS template/ajax.js --> {SCRIPTS} +<!-- EVENT overall_footer_after --> </body> </html> diff --git a/phpBB/styles/prosilver/template/overall_header.html b/phpBB/styles/prosilver/template/overall_header.html index 3e00827235..97dbc76e43 100644 --- a/phpBB/styles/prosilver/template/overall_header.html +++ b/phpBB/styles/prosilver/template/overall_header.html @@ -84,8 +84,9 @@ <link href="{T_THEME_PATH}/tweaks.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" type="text/css" media="screen, projection" /> <![endif]--> -</head> +<!-- EVENT overall_header_head_append --> +</head> <body id="phpbb" class="section-{SCRIPT_NAME} {S_CONTENT_DIRECTION}"> <div id="wrap"> @@ -121,7 +122,11 @@ <ul class="linklist navlinks"> <!-- DEFINE $MICRODATA = ' itemtype="http://data-vocabulary.org/Breadcrumb" itemscope=""' --> - <li class="icon-home"><!-- IF U_SITE_HOME --><a href="{U_SITE_HOME}"{$MICRODATA}>{L_SITE_HOME}</a> <strong>‹</strong> <!-- ENDIF --><a href="{U_INDEX}" accesskey="h"{$MICRODATA}>{L_INDEX}</a> <!-- BEGIN navlinks --> <strong>‹</strong> <a href="{navlinks.U_VIEW_FORUM}"{$MICRODATA}>{navlinks.FORUM_NAME}</a><!-- END navlinks --></li> + <li class="icon-home"><!-- IF U_SITE_HOME --><a href="{U_SITE_HOME}"{$MICRODATA}>{L_SITE_HOME}</a> <strong>‹</strong> <!-- ENDIF --> + <a href="{U_INDEX}" accesskey="h"{$MICRODATA}>{L_INDEX}</a> + <!-- BEGIN navlinks --> <strong>‹</strong> <a href="{navlinks.U_VIEW_FORUM}"{$MICRODATA}>{navlinks.FORUM_NAME}</a><!-- END navlinks --> + <!-- EVENT overall_header_breadcrumb_append --> + </li> <!-- IF U_EMAIL_TOPIC --><li class="rightside"><a href="{U_EMAIL_TOPIC}" title="{L_EMAIL_TOPIC}" class="sendemail">{L_EMAIL_TOPIC}</a></li><!-- ENDIF --> <!-- IF U_EMAIL_PM --><li class="rightside"><a href="{U_EMAIL_PM}" title="{L_EMAIL_PM}" class="sendemail">{L_EMAIL_PM}</a></li><!-- ENDIF --> @@ -145,12 +150,14 @@ <!-- ENDIF --> <ul class="linklist rightside"> + <!-- EVENT overall_header_navigation_prepend --> <li class="icon-faq"><a href="{U_FAQ}" title="{L_FAQ_EXPLAIN}">{L_FAQ}</a></li> <!-- IF not S_IS_BOT --> <!-- IF S_DISPLAY_MEMBERLIST --><li class="icon-members"><a href="{U_MEMBERLIST}" title="{L_MEMBERLIST_EXPLAIN}">{L_MEMBERLIST}</a></li><!-- ENDIF --> <!-- IF not S_USER_LOGGED_IN and S_REGISTER_ENABLED and not (S_SHOW_COPPA or S_REGISTRATION) --><li class="icon-register"><a href="{U_REGISTER}">{L_REGISTER}</a></li><!-- ENDIF --> <li class="icon-logout"><a href="{U_LOGIN_LOGOUT}" title="{L_LOGIN_LOGOUT}" accesskey="x">{L_LOGIN_LOGOUT}</a></li> <!-- ENDIF --> + <!-- EVENT overall_header_navigation_append --> </ul> </div> diff --git a/phpBB/styles/prosilver/template/posting_editor.html b/phpBB/styles/prosilver/template/posting_editor.html index be45993cef..8156968098 100644 --- a/phpBB/styles/prosilver/template/posting_editor.html +++ b/phpBB/styles/prosilver/template/posting_editor.html @@ -213,6 +213,7 @@ <div class="inner"> <fieldset class="fields1"> + <!-- EVENT posting_editor_options_prepend --> <!-- IF S_BBCODE_ALLOWED --> <div><label for="disable_bbcode"><input type="checkbox" name="disable_bbcode" id="disable_bbcode"{S_BBCODE_CHECKED} /> {L_DISABLE_BBCODE}</label></div> <!-- ENDIF --> diff --git a/phpBB/styles/prosilver/template/simple_footer.html b/phpBB/styles/prosilver/template/simple_footer.html index 897e50ced7..ec189304fc 100644 --- a/phpBB/styles/prosilver/template/simple_footer.html +++ b/phpBB/styles/prosilver/template/simple_footer.html @@ -10,5 +10,6 @@ <!-- IF S_JQUERY_FALLBACK --><script type="text/javascript">window.jQuery || document.write(unescape('%3Cscript src="{T_ASSETS_PATH}/javascript/jquery.js?assets_version={T_ASSETS_VERSION}" type="text/javascript"%3E%3C/script%3E'));</script><!-- ENDIF --> {SCRIPTS} +<!-- EVENT simple_footer_after --> </body> </html> diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html b/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html index a024a170a7..4a8d3da08a 100644 --- a/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html +++ b/phpBB/styles/prosilver/template/ucp_pm_viewmessage_print.html @@ -9,8 +9,8 @@ <title>{SITENAME} • {PAGE_TITLE}</title> <link href="{T_THEME_PATH}/print.css" rel="stylesheet" type="text/css" /> +<!-- EVENT ucp_pm_viewmessage_print_head_append --> </head> - <body id="phpbb"> <div id="wrap"> <a id="top" accesskey="t"></a> diff --git a/phpBB/styles/prosilver/template/viewforum_body.html b/phpBB/styles/prosilver/template/viewforum_body.html index a3239602ae..b47c13d573 100644 --- a/phpBB/styles/prosilver/template/viewforum_body.html +++ b/phpBB/styles/prosilver/template/viewforum_body.html @@ -28,7 +28,7 @@ <!-- IF S_HAS_SUBFORUM --> <!-- IF not S_IS_BOT and U_MARK_FORUMS --> <ul class="linklist"> - <li class="rightside"><a href="{U_MARK_FORUMS}">{L_MARK_SUBFORUMS_READ}</a></li> + <li class="rightside"><a href="{U_MARK_FORUMS}" data-ajax="mark_forums_read" data-overlay="false">{L_MARK_SUBFORUMS_READ}</a></li> </ul> <!-- ENDIF --> <!-- INCLUDE forumlist_body.html --> @@ -57,7 +57,7 @@ <!-- IF .pagination or TOTAL_POSTS or TOTAL_TOPICS --> <div class="pagination"> - <!-- IF not S_IS_BOT and U_MARK_TOPICS --><a href="{U_MARK_TOPICS}" accesskey="m" data-ajax="true">{L_MARK_TOPICS_READ}</a> • <!-- ENDIF --> + <!-- IF not S_IS_BOT and U_MARK_TOPICS --><a href="{U_MARK_TOPICS}" accesskey="m" data-ajax="mark_topics_read" data-overlay="false">{L_MARK_TOPICS_READ}</a> • <!-- ENDIF --> <!-- IF TOTAL_TOPICS -->{TOTAL_TOPICS} • <!-- ENDIF --> <!-- IF .pagination --> <!-- INCLUDE pagination.html --> @@ -211,7 +211,7 @@ <!-- IF PAGE_NUMBER or TOTAL_POSTS or TOTAL_TOPICS --> <div class="pagination"> - <!-- IF TOTAL_TOPICS and not S_IS_BOT and U_MARK_TOPICS --><a href="{U_MARK_TOPICS}">{L_MARK_TOPICS_READ}</a> • <!-- ENDIF --> + <!-- IF TOTAL_TOPICS and not S_IS_BOT and U_MARK_TOPICS --><a href="{U_MARK_TOPICS}" data-ajax="mark_topics_read" data-overlay="false">{L_MARK_TOPICS_READ}</a> • <!-- ENDIF --> <!-- IF TOTAL_POSTS and not NEWEST_USER --> {TOTAL_POSTS}<!-- ELSEIF TOTAL_TOPICS and not NEWEST_USER --> {TOTAL_TOPICS} • <!-- ENDIF --> <!-- IF TOTAL_USERS -->{TOTAL_USERS} • <!-- ENDIF --> <!-- IF .pagination --> diff --git a/phpBB/styles/prosilver/template/viewtopic_body.html b/phpBB/styles/prosilver/template/viewtopic_body.html index 1b7d78e063..7688898f5c 100644 --- a/phpBB/styles/prosilver/template/viewtopic_body.html +++ b/phpBB/styles/prosilver/template/viewtopic_body.html @@ -1,6 +1,6 @@ <!-- INCLUDE overall_header.html --> <!-- IF U_MCP --><p>[ <a href="{U_MCP}">{L_MCP}</a> ]</p><!-- ENDIF --> -<h2><a href="{U_VIEW_TOPIC}">{TOPIC_TITLE}</a></h2> +<h2><!-- EVENT viewtopic_topic_title_prepend --><a href="{U_VIEW_TOPIC}">{TOPIC_TITLE}</a></h2> <!-- NOTE: remove the style="display: none" when you want to have the forum description on the topic body --> <!-- IF FORUM_DESC --><div style="display: none !important;">{FORUM_DESC}<br /></div><!-- ENDIF --> diff --git a/phpBB/styles/prosilver/template/viewtopic_print.html b/phpBB/styles/prosilver/template/viewtopic_print.html index 54676279d2..fd0b2dc3e6 100644 --- a/phpBB/styles/prosilver/template/viewtopic_print.html +++ b/phpBB/styles/prosilver/template/viewtopic_print.html @@ -9,8 +9,8 @@ <title>{SITENAME} • {PAGE_TITLE}</title> <link href="{T_THEME_PATH}/print.css" rel="stylesheet" type="text/css" /> +<!-- EVENT viewtopic_print_head_append --> </head> - <body id="phpbb"> <div id="wrap"> <a id="top" accesskey="t"></a> diff --git a/phpBB/styles/subsilver2/template/breadcrumbs.html b/phpBB/styles/subsilver2/template/breadcrumbs.html index 49e31c0749..09ee9a8606 100644 --- a/phpBB/styles/subsilver2/template/breadcrumbs.html +++ b/phpBB/styles/subsilver2/template/breadcrumbs.html @@ -2,7 +2,8 @@ <table class="tablebg" width="100%" cellspacing="1" cellpadding="0" style="margin-top: 5px;"> <tr> <td class="row1"> - <p class="breadcrumbs"><!-- IF U_SITE_HOME --><a href="{U_SITE_HOME}"{$MICRODATA}>{L_SITE_HOME}</a> <strong>»</strong> <!-- ENDIF --><a href="{U_INDEX}"{$MICRODATA}>{L_INDEX}</a><!-- BEGIN navlinks --> » <a href="{navlinks.U_VIEW_FORUM}"{$MICRODATA}>{navlinks.FORUM_NAME}</a><!-- END navlinks --></p> + <p class="breadcrumbs"><!-- IF U_SITE_HOME --><a href="{U_SITE_HOME}"{$MICRODATA}>{L_SITE_HOME}</a> <strong>»</strong> <!-- ENDIF --><a href="{U_INDEX}"{$MICRODATA}>{L_INDEX}</a><!-- BEGIN navlinks --> » <a href="{navlinks.U_VIEW_FORUM}"{$MICRODATA}>{navlinks.FORUM_NAME}</a><!-- END navlinks --> + <!-- EVENT overall_header_breadcrumb_append --></p> <p class="datetime">{S_TIMEZONE}</p> </td> </tr> diff --git a/phpBB/styles/subsilver2/template/forumlist_body.html b/phpBB/styles/subsilver2/template/forumlist_body.html index ad505885f6..3e30561f3a 100644 --- a/phpBB/styles/subsilver2/template/forumlist_body.html +++ b/phpBB/styles/subsilver2/template/forumlist_body.html @@ -61,6 +61,7 @@ <td class="row2" align="center" nowrap="nowrap"> <!-- IF forumrow.LAST_POST_TIME --> <!-- IF forumrow.S_DISPLAY_SUBJECT --> + <!-- EVENT forumlist_body_last_post_title_prepend --> <p class="topicdetails"><a href="{forumrow.U_LAST_POST}" title="{forumrow.LAST_POST_SUBJECT}" class="lastsubject">{forumrow.LAST_POST_SUBJECT_TRUNCATED}</a></p> <!-- ENDIF --> <p class="topicdetails"><!-- IF forumrow.U_UNAPPROVED_TOPICS --><a href="{forumrow.U_UNAPPROVED_TOPICS}" class="imageset">{UNAPPROVED_IMG}</a> <!-- ENDIF -->{forumrow.LAST_POST_TIME}</p> diff --git a/phpBB/styles/subsilver2/template/index_body.html b/phpBB/styles/subsilver2/template/index_body.html index af2cefef7a..e07cfda8b3 100644 --- a/phpBB/styles/subsilver2/template/index_body.html +++ b/phpBB/styles/subsilver2/template/index_body.html @@ -18,6 +18,8 @@ <!-- INCLUDE breadcrumbs.html --> +<!-- EVENT index_body_stat_blocks_before --> + <!-- IF S_DISPLAY_ONLINE_LIST --> <br clear="all" /> diff --git a/phpBB/styles/subsilver2/template/jumpbox.html b/phpBB/styles/subsilver2/template/jumpbox.html index f4153d7692..e0603c6a6e 100644 --- a/phpBB/styles/subsilver2/template/jumpbox.html +++ b/phpBB/styles/subsilver2/template/jumpbox.html @@ -1,10 +1,10 @@ <!-- IF S_DISPLAY_JUMPBOX --> - <form method="post" name="jumpbox" action="{S_JUMPBOX_ACTION}" onsubmit="if(document.jumpbox.f.value == -1){return false;}"> + <form method="get" name="jumpbox" action="{S_JUMPBOX_ACTION}" onsubmit="if(document.jumpbox.f.value == -1){return false;}"> <table cellspacing="0" cellpadding="0" border="0"> <tr> - <td nowrap="nowrap"><span class="gensmall"><!-- IF S_IN_MCP and S_MERGE_SELECT -->{L_SELECT_TOPICS_FROM}<!-- ELSEIF S_IN_MCP -->{L_MODERATE_FORUM}<!-- ELSE -->{L_JUMP_TO}<!-- ENDIF -->{L_COLON}</span> <select name="f" onchange="if(this.options[this.selectedIndex].value != -1){ document.forms['jumpbox'].submit() }"> + <td nowrap="nowrap">{HIDDEN_FIELDS_FOR_JUMPBOX}<span class="gensmall"><!-- IF S_IN_MCP and S_MERGE_SELECT -->{L_SELECT_TOPICS_FROM}<!-- ELSEIF S_IN_MCP -->{L_MODERATE_FORUM}<!-- ELSE -->{L_JUMP_TO}<!-- ENDIF -->{L_COLON}</span> <select name="f" onchange="if(this.options[this.selectedIndex].value != -1){ document.forms['jumpbox'].submit() }"> <!-- BEGIN jumpbox_forums --> <!-- IF jumpbox_forums.S_FORUM_COUNT eq 1 --><option value="-1">------------------</option><!-- ENDIF --> diff --git a/phpBB/styles/subsilver2/template/mcp_jumpbox.html b/phpBB/styles/subsilver2/template/mcp_jumpbox.html index 734222bc77..e6ef4ecdad 100644 --- a/phpBB/styles/subsilver2/template/mcp_jumpbox.html +++ b/phpBB/styles/subsilver2/template/mcp_jumpbox.html @@ -1,7 +1,8 @@ <!-- Note: no longer in use... --> -<form name="jumpbox" method="post" action="{S_JUMPBOX_ACTION}"> +<form name="jumpbox" method="get" action="{S_JUMPBOX_ACTION}"> + {HIDDEN_FIELDS_FOR_JUMPBOX} <span class="gensmall">{L_JUMP_TO}{L_COLON}</span> <select name="f" onChange="if(this.options[this.selectedIndex].value != -1 && this.options[this.selectedIndex].value != document.jumpbox.current_f.value){ document.forms['jumpbox'].submit() }"> <!-- IF S_ENABLE_SELECT_ALL --> diff --git a/phpBB/styles/subsilver2/template/overall_footer.html b/phpBB/styles/subsilver2/template/overall_footer.html index 24c6f8105c..64e7587023 100644 --- a/phpBB/styles/subsilver2/template/overall_footer.html +++ b/phpBB/styles/subsilver2/template/overall_footer.html @@ -3,8 +3,11 @@ <div id="wrapfooter"> <!-- IF U_ACP --><span class="gensmall">[ <a href="{U_ACP}">{L_ACP}</a> ]</span><br /><br /><!-- ENDIF --> - <span class="copyright">{CREDIT_LINE} + <span class="copyright"> + <!-- EVENT overall_footer_copyright_prepend --> + {CREDIT_LINE} <!-- IF TRANSLATION_INFO --><br />{TRANSLATION_INFO}<!-- ENDIF --> + <!-- EVENT overall_footer_copyright_append --> <!-- IF DEBUG_OUTPUT --><br /><bdo dir="ltr">[ {DEBUG_OUTPUT} ]</bdo><!-- ENDIF --></span> </div> @@ -12,5 +15,6 @@ <!-- IF S_JQUERY_FALLBACK --><script type="text/javascript">window.jQuery || document.write(unescape('%3Cscript src="{T_ASSETS_PATH}/javascript/jquery.js?assets_version={T_ASSETS_VERSION}" type="text/javascript"%3E%3C/script%3E'));</script><!-- ENDIF --> {SCRIPTS} +<!-- EVENT overall_footer_after --> </body> </html> diff --git a/phpBB/styles/subsilver2/template/overall_header.html b/phpBB/styles/subsilver2/template/overall_header.html index 4ed69c56aa..d5fd20f0fe 100644 --- a/phpBB/styles/subsilver2/template/overall_header.html +++ b/phpBB/styles/subsilver2/template/overall_header.html @@ -129,6 +129,9 @@ function marklist(id, name, state) // ]]> </script> + +<!-- EVENT overall_header_head_append --> + </head> <body class="{S_CONTENT_DIRECTION}"> diff --git a/phpBB/styles/subsilver2/template/posting_body.html b/phpBB/styles/subsilver2/template/posting_body.html index 4c9df6f060..39f8f876ba 100644 --- a/phpBB/styles/subsilver2/template/posting_body.html +++ b/phpBB/styles/subsilver2/template/posting_body.html @@ -257,6 +257,7 @@ </td> <td class="row2"> <table cellpadding="1"> + <!-- EVENT posting_editor_options_prepend --> <!-- IF S_BBCODE_ALLOWED --> <tr> <td><input type="checkbox" class="radio" name="disable_bbcode"{S_BBCODE_CHECKED} /></td> diff --git a/phpBB/styles/subsilver2/template/simple_footer.html b/phpBB/styles/subsilver2/template/simple_footer.html index 38a86c5001..c847bfedcc 100644 --- a/phpBB/styles/subsilver2/template/simple_footer.html +++ b/phpBB/styles/subsilver2/template/simple_footer.html @@ -9,5 +9,6 @@ <!-- IF S_JQUERY_FALLBACK --><script type="text/javascript">window.jQuery || document.write(unescape('%3Cscript src="{T_ASSETS_PATH}/javascript/jquery.js?assets_version={T_ASSETS_VERSION}" type="text/javascript"%3E%3C/script%3E'));</script><!-- ENDIF --> {SCRIPTS} +<!-- EVENT simple_footer_after --> </body> </html> diff --git a/phpBB/styles/subsilver2/template/viewtopic_body.html b/phpBB/styles/subsilver2/template/viewtopic_body.html index e2834ffa0b..9e6377022a 100644 --- a/phpBB/styles/subsilver2/template/viewtopic_body.html +++ b/phpBB/styles/subsilver2/template/viewtopic_body.html @@ -15,7 +15,7 @@ <!-- ENDIF --> <div id="pageheader"> - <h2><a class="titles" href="{U_VIEW_TOPIC}">{TOPIC_TITLE}</a></h2> + <h2><!-- EVENT viewtopic_topic_title_prepend --><a class="titles" href="{U_VIEW_TOPIC}">{TOPIC_TITLE}</a></h2> <!-- IF MODERATORS --> <p class="moderators"><!-- IF S_SINGLE_MODERATOR -->{L_MODERATOR}<!-- ELSE -->{L_MODERATORS}<!-- ENDIF -->{L_COLON} {MODERATORS}</p> diff --git a/phpBB/viewforum.php b/phpBB/viewforum.php index 83e5d4caa5..5fed514a12 100644 --- a/phpBB/viewforum.php +++ b/phpBB/viewforum.php @@ -181,6 +181,20 @@ if ($mark_read == 'topics') $redirect_url = append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $forum_id); meta_refresh(3, $redirect_url); + 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_TOPICS' => ($user->data['is_registered'] || $config['load_anon_lastread']) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'hash=' . generate_link_hash('global') . "&f=$forum_id&mark=topics&mark_time=" . time()) : '', + 'MESSAGE_TITLE' => $user->lang['INFORMATION'], + 'MESSAGE_TEXT' => $user->lang['TOPICS_MARKED'] + ); + $json_response = new phpbb_json_response(); + $json_response->send($data); + } + trigger_error($user->lang['TOPICS_MARKED'] . '<br /><br />' . sprintf($user->lang['RETURN_FORUM'], '<a href="' . $redirect_url . '">', '</a>')); } diff --git a/phpBB/viewtopic.php b/phpBB/viewtopic.php index 3fde5b5e03..bd2c7bea77 100644 --- a/phpBB/viewtopic.php +++ b/phpBB/viewtopic.php @@ -1353,7 +1353,7 @@ if (sizeof($attach_list)) } $template->assign_vars(array( - 'S_HAS_ATTACHMENTS' => !empty($attachments), + 'S_HAS_ATTACHMENTS' => $topic_data['topic_attachment'], )); $methods = phpbb_gen_download_links('topic_id', $topic_id, $phpbb_root_path, $phpEx); diff --git a/tests/RUNNING_TESTS.txt b/tests/RUNNING_TESTS.txt index 75a6fc94f6..cb0ec629d3 100644 --- a/tests/RUNNING_TESTS.txt +++ b/tests/RUNNING_TESTS.txt @@ -30,7 +30,7 @@ example for mysqli can be found below. More information on configuration options can be found on the wiki (see below). <?php - $dbms = 'mysqli'; + $dbms = 'phpbb_db_driver_mysqli'; $dbhost = 'localhost'; $dbport = ''; $dbname = 'database'; diff --git a/tests/bbcode/parser_test.php b/tests/bbcode/parser_test.php index 8c7fbc7128..d0dcce5bbf 100644 --- a/tests/bbcode/parser_test.php +++ b/tests/bbcode/parser_test.php @@ -2,28 +2,264 @@ /** * * @package testing -* @version $Id$ -* @copyright (c) 2008 phpBB Group +* @copyright (c) 2012 phpBB Group * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 * */ -// require_once dirname(__FILE__) . '/../../phpBB/includes/bbcode/bbcode_parser_base.php'; -// require_once dirname(__FILE__) . '/../../phpBB/includes/bbcode/bbcode_parser.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_content.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/bbcode.php'; +require_once dirname(__FILE__) . '/../../phpBB/includes/message_parser.php'; class phpbb_bbcode_parser_test extends PHPUnit_Framework_TestCase { - public function test_both_passes() + public function bbcode_firstpass_data() { - $this->markTestIncomplete('New bbcode parser has not been backported from feature/ascraeus-experiment yet.'); - - $parser = new phpbb_bbcode_parser(); + return array( + // Default bbcodes from in their simplest way + array( + 'Test default bbcodes: simple bold', + '[b]bold[/b]', + '[b:]bold[/b:]', + ), + array( + 'Test default bbcodes: simple underlined', + '[u]underlined[/u]', + '[u:]underlined[/u:]', + ), + array( + 'Test default bbcodes: simple italic', + '[i]italic[/i]', + '[i:]italic[/i:]', + ), + array( + 'Test default bbcodes: simple color rgb', + '[color=#FF0000]colored[/color]', + '[color=#FF0000:]colored[/color:]', + ), + array( + 'Test default bbcodes: simple color name', + '[color=red]colored[/color]', + '[color=red:]colored[/color:]', + ), + array( + 'Test default bbcodes: simple size', + '[size=75]smaller[/size]', + '[size=75:]smaller[/size:]', + ), + array( + 'Test default bbcodes: simple quote', + '[quote]quoted[/quote]', + '[quote:]quoted[/quote:]', + ), + array( + 'Test default bbcodes: simple quote with username', + '[quote="username"]quoted[/quote]', + '[quote="username":]quoted[/quote:]', + ), + array( + 'Test default bbcodes: simple code', + '[code]unparsed code[/code]', + '[code:]unparsed code[/code:]', + ), + array( + 'Test default bbcodes: simple php code', + '[code=php]unparsed code[/code]', + '[code=php:]<span class="syntaxdefault">unparsed code</span>[/code:]', + ), + array( + 'Test default bbcodes: simple list', + '[list]no item[/list]', + '[list:]no item[/list:u:]', + ), + array( + 'Test default bbcodes: simple list-item only', + '[*]unparsed', + '[*]unparsed', + ), + array( + 'Test default bbcodes: simple list-item', + '[list][*]item[/list]', + '[list:][*:]item[/*:m:][/list:u:]', + ), + array( + 'Test default bbcodes: simple list-item closed', + '[list][*]item[/*][/list]', + '[list:][*:]item[/*:][/list:u:]', + ), + array( + 'Test default bbcodes: simple list-item numbered', + '[list=1][*]item[/list]', + '[list=1:][*:]item[/*:m:][/list:o:]', + ), + array( + 'Test default bbcodes: simple list-item alpha', + '[list=a][*]item[/list]', + '[list=a:][*:]item[/*:m:][/list:o:]', + ), + array( + 'Test default bbcodes: simple list-item roman', + '[list=i][*]item[/list]', + '[list=i:][*:]item[/*:m:][/list:o:]', + ), + array( + 'Test default bbcodes: simple list-item disc', + '[list=disc][*]item[/list]', + '[list=disc:][*:]item[/*:m:][/list:u:]', + ), + array( + 'Test default bbcodes: simple list-item circle', + '[list=circle][*]item[/list]', + '[list=circle:][*:]item[/*:m:][/list:u:]', + ), + array( + 'Test default bbcodes: simple list-item square', + '[list=square][*]item[/list]', + '[list=square:][*:]item[/*:m:][/list:u:]', + ), + array( + 'Test default bbcodes: simple img', + '[img]https://area51.phpbb.com/images/area51.png[/img]', + '[img:]https://area51.phpbb.com/images/area51.png[/img:]', + ), + array( + 'Test default bbcodes: simple url', + '[url]https://area51.phpbb.com/[/url]', + '[url:]https://area51.phpbb.com/[/url:]', + ), + array( + 'Test default bbcodes: simple url with description', + '[url=https://area51.phpbb.com/]Area51[/url]', + '[url=https://area51.phpbb.com/:]Area51[/url:]', + ), + array( + 'Test default bbcodes: simple email', + '[email]bbcode-test@phpbb.com[/email]', + '[email:]bbcode-test@phpbb.com[/email:]', + ), + array( + 'Test default bbcodes: simple email with description', + '[email=bbcode-test@phpbb.com]Email[/email]', + '[email=bbcode-test@phpbb.com:]Email[/email:]', + ), + array( + 'Test default bbcodes: simple attachment', + '[attachment=0]filename[/attachment]', + '[attachment=0:]<!-- ia0 -->filename<!-- ia0 -->[/attachment:]', + ), - $result = $parser->first_pass('[i]Italic [u]underlined text[/u][/i]'); - $result = $parser->second_pass($result); + // Special cases for quote which were reported as bugs before + array( + 'PHPBB3-1401 - correct: parsed', + '[quote="[test]test"]test [ test[/quote]', + '[quote="[test]test":]test [ test[/quote:]', + ), + array( + 'PHPBB3-6117 - correct: parsed', + '[quote]test[/quote] test ] and [ test [quote]test[/quote]', + '[quote:]test[/quote:] test ] and [ test [quote:]test[/quote:]', + ), + array( + 'PHPBB3-6200 - correct: parsed', + '[quote="["]test[/quote]', + '[quote="[":]test[/quote:]', + ), + array( + 'PHPBB3-9364 - quoted: "test[/[/b]quote] test" / non-quoted: "[/quote] test" - also failed if layout distorted', + '[quote]test[/[/b]quote] test [/quote][/quote] test', + '[quote:]test[/[/b]quote] test [/quote:][/quote] test', + ), + array( + 'PHPBB3-8096 - first quote tag parsed, second quote tag unparsed', + '[quote="a"]a[/quote][quote="a]a[/quote]', + '[quote="a":]a[/quote:][quote="a]a[/quote]', + ), - $expected = '<span style="font-style: italic">Italic <span style="text-decoration: underline">underlined text</span></span>'; + // Simple bbcodes nesting + array( + 'Allow textual bbcodes in textual bbcodes', + '[b]bold [i]bold + italic[/i][/b]', + '[b:]bold [i:]bold + italic[/i:][/b:]', + ), + array( + 'Allow textual bbcodes in url with description', + '[url=https://area51.phpbb.com/]Area51 [i]italic[/i][/url]', + '[url=https://area51.phpbb.com/:]Area51 [i:]italic[/i:][/url:]', + ), + array( + 'Allow url with description in textual bbcodes', + '[i]italic [url=https://area51.phpbb.com/]Area51[/url][/i]', + '[i:]italic [url=https://area51.phpbb.com/:]Area51[/url:][/i:]', + ), - $this->assertEquals($expected, $result, 'Simple nested BBCode first+second pass'); + // Nesting bbcodes into quote usernames + array( + 'Allow textual bbcodes in usernames', + '[quote="[i]test[/i]"]test[/quote]', + '[quote="[i:]test[/i:]":]test[/quote:]', + ), + array( + 'Allow links bbcodes in usernames', + '[quote="[url=https://area51.phpbb.com/]test[/url]"]test[/quote]', + '[quote="[url=https://area51.phpbb.com/:]test[/url:]":]test[/quote:]', + ), + array( + 'Allow img bbcodes in usernames - Username displayed the image', + '[quote="[img]https://area51.phpbb.com/images/area51.png[/img]"]test[/quote]', + '[quote="[img:]https://area51.phpbb.com/images/area51.png[/img:]":]test[/quote:]', + ), + array( + 'Disallow flash bbcodes in usernames - Username displayed as [flash]http://www.phpbb.com/[/flash]', + '[quote="[flash]http://www.phpbb.com/[/flash]"]test[/quote]', + '[quote="[flash]http://www.phpbb.com/[/flash]":]test[/quote:]', + ), + array( + 'Disallow quote bbcodes in usernames - Username displayed as [quote]test[/quote]', + '[quote="[quote]test[/quote]"]test[/quote]', + '[quote="[quote]test[/quote]":]test[/quote:]', + ), + + // Do not parse bbcodes in code boxes + array( + 'Do not parse textual bbcodes in code', + '[code]unparsed code [b]bold [i]bold + italic[/i][/b][/code]', + '[code:]unparsed code [b]bold [i]bold + italic[/i][/b][/code:]', + ), + array( + 'Do not parse quote bbcodes in code', + '[code]unparsed code [quote="username"]quoted[/quote][/code]', + '[code:]unparsed code [quote="username"]quoted[/quote][/code:]', + ), + + // New user friendly mixed nesting + array( + 'Textual bbcode nesting into textual bbcode', + '[b]bold [i]bold + italic[/b] italic[/i]', + '[b:]bold [i:]bold + italic[/b:] italic[/i:]', + 'Incomplete test case: secondpass parses as [b:]bold [i:]bold + italic[/i:] italic[/b:]', + ), + ); + } + + /** + * @dataProvider bbcode_firstpass_data + */ + public function test_bbcode_firstpass($description, $message, $expected, $incomplete = false) + { + if ($incomplete) + { + $this->markTestIncomplete($incomplete); + } + + global $user, $request; + $user = new phpbb_mock_user; + $request = new phpbb_mock_request; + + $bbcode = new bbcode_firstpass(); + $bbcode->message = $message; + $bbcode->bbcode_init(false); + $bbcode->parse_bbcode(); + $this->assertEquals($expected, $bbcode->message); } } diff --git a/tests/compress/compress_test.php b/tests/compress/compress_test.php index ac8dd358d3..6623f7ed8a 100644 --- a/tests/compress/compress_test.php +++ b/tests/compress/compress_test.php @@ -38,10 +38,16 @@ class phpbb_compress_test extends phpbb_test_case $phpbb_root_path = ''; $this->path = dirname(__FILE__) . '/fixtures/'; + } - if (!@extension_loaded('zlib') || !@extension_loaded('bz2')) + protected function check_extensions($extensions) + { + foreach ($extensions as $extension) { - $this->markTestSkipped('PHP needs to be compiled with --with-zlib and --with-bz2 in order to run these tests'); + if (!@extension_loaded($extension)) + { + $this->markTestSkipped("$extension extension is not loaded"); + } } } @@ -114,17 +120,18 @@ class phpbb_compress_test extends phpbb_test_case public function tar_archive_list() { return array( - array('archive.tar', '.tar'), - array('archive.tar.gz', '.tar.gz'), - array('archive.tar.bz2', '.tar.bz2'), + array('archive.tar', '.tar', array()), + array('archive.tar.gz', '.tar.gz', array('zlib')), + array('archive.tar.bz2', '.tar.bz2', array('bz2')), ); } /** * @dataProvider tar_archive_list */ - public function test_extract_tar($filename, $type) + public function test_extract_tar($filename, $type, $extensions) { + $this->check_extensions($extensions); $compress = new compress_tar('r', $this->path . $filename); $compress->extract('tests/compress/' . self::EXTRACT_DIR); $this->valid_extraction(); @@ -141,8 +148,10 @@ class phpbb_compress_test extends phpbb_test_case * @depends test_extract_tar * @dataProvider tar_archive_list */ - public function test_compress_tar($filename, $type) + public function test_compress_tar($filename, $type, $extensions) { + $this->check_extensions($extensions); + $tar = dirname(__FILE__) . self::ARCHIVE_DIR . $filename; $compress = new compress_tar('w', $tar); $this->archive_files($compress); @@ -160,6 +169,8 @@ class phpbb_compress_test extends phpbb_test_case */ public function test_compress_zip() { + $this->check_extensions(array('zlib')); + $zip = dirname(__FILE__) . self::ARCHIVE_DIR . 'archive.zip'; $compress = new compress_zip('w', $zip); $this->archive_files($compress); diff --git a/tests/dbal/connect_test.php b/tests/dbal/connect_test.php index 505ce28fa1..1e352d6b03 100644 --- a/tests/dbal/connect_test.php +++ b/tests/dbal/connect_test.php @@ -22,9 +22,7 @@ class phpbb_dbal_connect_test extends phpbb_database_test_case $config = $this->get_database_config(); - require_once dirname(__FILE__) . '/../../phpBB/includes/db/' . $config['dbms'] . '.php'; - $dbal = 'dbal_' . $config['dbms']; - $db = new $dbal(); + $db = new $config['dbms'](); // Failure to connect results in a trigger_error call in dbal. // phpunit converts triggered errors to exceptions. diff --git a/tests/dbal/write_sequence_test.php b/tests/dbal/write_sequence_test.php index 8975cfbfb1..f382a971a5 100644 --- a/tests/dbal/write_sequence_test.php +++ b/tests/dbal/write_sequence_test.php @@ -33,6 +33,10 @@ class phpbb_dbal_write_sequence_test extends phpbb_database_test_case { $db = $this->new_dbal(); + // dbal uses cache + global $cache; + $cache = new phpbb_mock_cache(); + $sql = 'INSERT INTO phpbb_users ' . $db->sql_build_array('INSERT', array( 'username' => $username, 'username_clean' => $username, diff --git a/tests/di/create_container_test.php b/tests/di/create_container_test.php index c2b8a0fc0b..6de8803df9 100644 --- a/tests/di/create_container_test.php +++ b/tests/di/create_container_test.php @@ -9,7 +9,6 @@ require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; require_once dirname(__FILE__) . '/../../phpBB/includes/functions_container.php'; -require_once dirname(__FILE__) . '/../../phpBB/includes/db/dbal.php'; class phpbb_di_container_test extends phpbb_test_case { @@ -52,7 +51,7 @@ class phpbb_di_container_test extends phpbb_test_case } } -class dbal_container_mock extends dbal +class phpbb_db_driver_container_mock extends phpbb_db_driver { public function sql_connect() { diff --git a/tests/functional/auth_test.php b/tests/functional/auth_test.php index e955dcb4df..662b1bd38b 100644 --- a/tests/functional/auth_test.php +++ b/tests/functional/auth_test.php @@ -18,9 +18,19 @@ class phpbb_functional_auth_test extends phpbb_functional_test_case // check for logout link $crawler = $this->request('GET', 'index.php'); + $this->assert_response_success(); $this->assertContains($this->lang('LOGOUT_USER', 'admin'), $crawler->filter('.navbar')->text()); } + public function test_login_other() + { + $this->create_user('anothertestuser'); + $this->login('anothertestuser'); + $crawler = $this->request('GET', 'index.php'); + $this->assert_response_success(); + $this->assertContains('anothertestuser', $crawler->filter('.icon-logout')->text()); + } + /** * @depends test_login */ @@ -31,10 +41,12 @@ class phpbb_functional_auth_test extends phpbb_functional_test_case // logout $crawler = $this->request('GET', 'ucp.php?sid=' . $this->sid . '&mode=logout'); + $this->assert_response_success(); $this->assertContains($this->lang('LOGOUT_REDIRECT'), $crawler->filter('#message')->text()); // look for a register link, which should be visible only when logged out $crawler = $this->request('GET', 'index.php'); + $this->assert_response_success(); $this->assertContains($this->lang('REGISTER'), $crawler->filter('.navbar')->text()); } } diff --git a/tests/functional/memberlist_test.php b/tests/functional/memberlist_test.php new file mode 100644 index 0000000000..879bee2f0e --- /dev/null +++ b/tests/functional/memberlist_test.php @@ -0,0 +1,43 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +/** +* @group functional +*/ +class phpbb_functional_memberlist_test extends phpbb_functional_test_case +{ + public function test_memberlist() + { + $this->create_user('memberlist-test-user'); + // logs in as admin + $this->login(); + $crawler = $this->request('GET', 'memberlist.php?sid=' . $this->sid); + $this->assert_response_success(); + $this->assertContains('memberlist-test-user', $crawler->text()); + + // restrict by first character + $crawler = $this->request('GET', 'memberlist.php?first_char=m&sid=' . $this->sid); + $this->assert_response_success(); + $this->assertContains('memberlist-test-user', $crawler->text()); + + // make sure results for wrong character are not returned + $crawler = $this->request('GET', 'memberlist.php?first_char=a&sid=' . $this->sid); + $this->assert_response_success(); + $this->assertNotContains('memberlist-test-user', $crawler->text()); + } + + public function test_viewprofile() + { + $this->login(); + // XXX hardcoded user id + $crawler = $this->request('GET', 'memberlist.php?mode=viewprofile&u=2&sid=' . $this->sid); + $this->assert_response_success(); + $this->assertContains('admin', $crawler->filter('h2')->text()); + } +} diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php index f54a3591b2..d05207edf0 100644 --- a/tests/functional/posting_test.php +++ b/tests/functional/posting_test.php @@ -15,70 +15,93 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case public function test_post_new_topic() { $this->login(); - $this->add_lang('posting'); - $crawler = $this->request('GET', 'posting.php?mode=post&f=2&sid=' . $this->sid); - $this->assertContains($this->lang('POST_TOPIC'), $crawler->filter('html')->text()); + // Test creating topic + $post = $this->create_topic(2, 'Test Topic 1', 'This is a test topic posted by the testing framework.'); - $hidden_fields = array(); - $hidden_fields[] = $crawler->filter('[type="hidden"]')->each(function ($node, $i) { - return array('name' => $node->getAttribute('name'), 'value' => $node->getAttribute('value')); - }); + $crawler = $this->request('GET', "viewtopic.php?t={$post['topic_id']}&sid={$this->sid}"); + $this->assertContains('This is a test topic posted by the testing framework.', $crawler->filter('html')->text()); - $test_message = 'This is a test topic posted by the testing framework.'; - $form_data = array( - 'subject' => 'Test Topic 1', - 'message' => $test_message, - 'post' => true, - 'f' => 2, - 'mode' => 'post', - 'sid' => $this->sid, - ); + // Test creating a reply + $post2 = $this->create_post(2, $post['topic_id'], 'Re: Test Topic 1', 'This is a test post posted by the testing framework.'); - foreach ($hidden_fields as $fields) - { - foreach($fields as $field) - { - $form_data[$field['name']] = $field['value']; - } - } + $crawler = $this->request('GET', "viewtopic.php?t={$post2['topic_id']}&sid={$this->sid}"); + $this->assertContains('This is a test post posted by the testing framework.', $crawler->filter('html')->text()); - // Bypass time restriction that said that if the lastclick time (i.e. time when the form was opened) - // is not at least 2 seconds before submission, cancel the form - $form_data['lastclick'] = 0; + // Test quoting a message + $crawler = $this->request('GET', "posting.php?mode=quote&f=2&t={$post2['topic_id']}&p={$post2['post_id']}&sid={$this->sid}"); + $this->assert_response_success(); + $this->assertContains('This is a test post posted by the testing framework.', $crawler->filter('html')->text()); + } - // I use a request because the form submission method does not allow you to send data that is not - // contained in one of the actual form fields that the browser sees (i.e. it ignores "hidden" inputs) - // Instead, I send it as a request with the submit button "post" set to true. - $crawler = $this->client->request('POST', 'posting.php', $form_data); - $this->assertContains($this->lang('POST_STORED'), $crawler->filter('html')->text()); + /** + * Creates a topic + * + * Be sure to login before creating + * + * @param int $forum_id + * @param string $subject + * @param string $message + * @param array $additional_form_data Any additional form data to be sent in the request + * @return array post_id, topic_id + */ + public function create_topic($forum_id, $subject, $message, $additional_form_data = array()) + { + $posting_url = "posting.php?mode=post&f={$forum_id}&sid={$this->sid}"; + + $form_data = array_merge(array( + 'subject' => $subject, + 'message' => $message, + 'post' => true, + ), $additional_form_data); - $crawler = $this->request('GET', 'viewtopic.php?t=2&sid=' . $this->sid); - $this->assertContains($test_message, $crawler->filter('html')->text()); + return $this->submit_post($posting_url, 'POST_TOPIC', $form_data); } - public function test_post_reply() + /** + * Creates a post + * + * Be sure to login before creating + * + * @param int $forum_id + * @param string $subject + * @param string $message + * @param array $additional_form_data Any additional form data to be sent in the request + * @return array post_id, topic_id + */ + public function create_post($forum_id, $topic_id, $subject, $message, $additional_form_data = array()) { - $this->login(); - $this->add_lang('posting'); + $posting_url = "posting.php?mode=reply&f={$forum_id}&t={$topic_id}&sid={$this->sid}"; - $crawler = $this->request('GET', 'posting.php?mode=reply&t=2&f=2&sid=' . $this->sid); - $this->assertContains($this->lang('POST_REPLY'), $crawler->filter('html')->text()); + $form_data = array_merge(array( + 'subject' => $subject, + 'message' => $message, + 'post' => true, + ), $additional_form_data); - $hidden_fields = array(); - $hidden_fields[] = $crawler->filter('[type="hidden"]')->each(function ($node, $i) { - return array('name' => $node->getAttribute('name'), 'value' => $node->getAttribute('value')); - }); + return $this->submit_post($posting_url, 'POST_REPLY', $form_data); + } + + /** + * Helper for submitting posts + * + * @param string $posting_url + * @param string $posting_contains + * @param array $form_data + * @return array post_id, topic_id + */ + protected function submit_post($posting_url, $posting_contains, $form_data) + { + $this->add_lang('posting'); - $test_message = 'This is a test post posted by the testing framework.'; - $form_data = array( - 'subject' => 'Re: Test Topic 1', - 'message' => $test_message, - 'post' => true, - 't' => 2, - 'f' => 2, - 'mode' => 'reply', - 'sid' => $this->sid, + $crawler = $this->request('GET', $posting_url); + $this->assert_response_success(); + $this->assertContains($this->lang($posting_contains), $crawler->filter('html')->text()); + + $hidden_fields = array( + $crawler->filter('[type="hidden"]')->each(function ($node, $i) { + return array('name' => $node->getAttribute('name'), 'value' => $node->getAttribute('value')); + }), ); foreach ($hidden_fields as $fields) @@ -89,14 +112,28 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case } } - // For reasoning behind the following command, see the test_post_new_topic() test + // Bypass time restriction that said that if the lastclick time (i.e. time when the form was opened) + // is not at least 2 seconds before submission, cancel the form $form_data['lastclick'] = 0; - // Submit the post - $crawler = $this->client->request('POST', 'posting.php', $form_data); + // I use a request because the form submission method does not allow you to send data that is not + // contained in one of the actual form fields that the browser sees (i.e. it ignores "hidden" inputs) + // Instead, I send it as a request with the submit button "post" set to true. + $crawler = $this->client->request('POST', $posting_url, $form_data); + $this->assert_response_success(); $this->assertContains($this->lang('POST_STORED'), $crawler->filter('html')->text()); - $crawler = $this->request('GET', 'viewtopic.php?t=2&sid=' . $this->sid); - $this->assertContains($test_message, $crawler->filter('html')->text()); + $url = $crawler->selectLink($this->lang('VIEW_MESSAGE', '', ''))->link()->getUri(); + + $matches = $topic_id = $post_id = false; + preg_match_all('#&t=([0-9]+)(&p=([0-9]+))?#', $url, $matches); + + $topic_id = (int) (isset($matches[1][0])) ? $matches[1][0] : 0; + $post_id = (int) (isset($matches[3][0])) ? $matches[3][0] : 0; + + return array( + 'topic_id' => $topic_id, + 'post_id' => $post_id, + ); } } diff --git a/tests/functions/build_hidden_fields_for_query_params_test.php b/tests/functions/build_hidden_fields_for_query_params_test.php new file mode 100644 index 0000000000..ef2f5744d3 --- /dev/null +++ b/tests/functions/build_hidden_fields_for_query_params_test.php @@ -0,0 +1,71 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; + +class phpbb_build_hidden_fields_for_query_params_test extends phpbb_test_case +{ + public function build_hidden_fields_for_query_params_test_data() + { + return array( + // get + // post + // exclude + // expected + array( + array('foo' => 'bar'), + array(), + array(), + "<input type='hidden' name=\"foo\" value=\"bar\" />", + ), + array( + array('foo' => 'bar', 'a' => 'b'), + array(), + array(), + "<input type='hidden' name=\"foo\" value=\"bar\" /><input type='hidden' name=\"a\" value=\"b\" />", + ), + array( + array('a' => 'quote"', 'b' => '<less>'), + array(), + array(), + "<input type='hidden' name=\"a\" value='quote\"' /><input type='hidden' name=\"b\" value=\"<less>\" />", + ), + array( + array('a' => "quotes'\""), + array(), + array(), + "<input type='hidden' name=\"a\" value=\"quotes'"\" />", + ), + array( + array('foo' => 'bar', 'a' => 'b'), + array('a' => 'c'), + array(), + "<input type='hidden' name=\"foo\" value=\"bar\" />", + ), + // strict equality check + array( + array('foo' => 'bar', 'a' => '0'), + array('a' => ''), + array(), + "<input type='hidden' name=\"foo\" value=\"bar\" />", + ), + ); + } + + /** + * @dataProvider build_hidden_fields_for_query_params_test_data + */ + public function test_build_hidden_fields_for_query_params($get, $post, $exclude, $expected) + { + $request = new phpbb_mock_request($get, $post); + $result = phpbb_build_hidden_fields_for_query_params($request, $exclude); + + $this->assertEquals($expected, $result); + } +} diff --git a/tests/functions/convert_30_dbms_to_31_test.php b/tests/functions/convert_30_dbms_to_31_test.php new file mode 100644 index 0000000000..d08bf87f15 --- /dev/null +++ b/tests/functions/convert_30_dbms_to_31_test.php @@ -0,0 +1,40 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; + +class phpbb_convert_30_dbms_to_31_test extends phpbb_test_case +{ + public function convert_30_dbms_to_31_data() + { + return array( + array('firebird'), + array('mssql'), + array('mssql_odbc'), + array('mssqlnative'), + array('mysql'), + array('mysqli'), + array('oracle'), + array('postgres'), + array('sqlite'), + ); + } + + /** + * @dataProvider convert_30_dbms_to_31_data + */ + public function test_convert_30_dbms_to_31($input) + { + $expected = "phpbb_db_driver_$input"; + + $output = phpbb_convert_30_dbms_to_31($input); + + $this->assertEquals($expected, $output); + } +} diff --git a/tests/functions/quoteattr_test.php b/tests/functions/quoteattr_test.php new file mode 100644 index 0000000000..9d2a7d470e --- /dev/null +++ b/tests/functions/quoteattr_test.php @@ -0,0 +1,44 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; + +class phpbb_quoteattr_test extends phpbb_test_case +{ + public function quoteattr_test_data() + { + return array( + array('foo', null, '"foo"'), + array('', null, '""'), + array(' ', null, '" "'), + array('<a>', null, '"<a>"'), + array('&', null, '"&amp;"'), + array('"hello"', null, "'\"hello\"'"), + array("'hello'", null, "\"'hello'\""), + array("\"'", null, "\""'\""), + array("a\nb", null, '"a b"'), + array("a\r\nb", null, '"a b"'), + array("a\tb", null, '"a	b"'), + array('a b', null, '"a b"'), + array('"a<b"', null, "'\"a<b\"'"), + array('foo', array('f' => 'z'), '"zoo"'), + array('<a>', array('a' => '&'), '"<&>"'), + ); + } + + /** + * @dataProvider quoteattr_test_data + */ + public function test_quoteattr($input, $entities, $expected) + { + $output = phpbb_quoteattr($input, $entities); + + $this->assertEquals($expected, $output); + } +} diff --git a/tests/functions_database_helper/fixtures/bookmarks_duplicates.xml b/tests/functions_database_helper/fixtures/bookmarks_duplicates.xml new file mode 100644 index 0000000000..d49f76b073 --- /dev/null +++ b/tests/functions_database_helper/fixtures/bookmarks_duplicates.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_bookmarks"> + <column>user_id</column> + <column>topic_id</column> + + <!-- one entry for this topic --> + <row> + <value>1</value> + <value>1</value> + </row> + + <!-- non-conflicting entries --> + <row> + <value>2</value> + <value>2</value> + </row> + <row> + <value>3</value> + <value>3</value> + </row> + + <!-- conflicting entries --> + <row> + <value>1</value> + <value>4</value> + </row> + <row> + <value>1</value> + <value>5</value> + </row> + + <!-- conflicting and non-conflicting entries --> + <row> + <value>1</value> + <value>6</value> + </row> + <row> + <value>1</value> + <value>7</value> + </row> + <row> + <value>2</value> + <value>6</value> + </row> + </table> +</dataset> diff --git a/tests/functions_database_helper/fixtures/topics_watch_duplicates.xml b/tests/functions_database_helper/fixtures/topics_watch_duplicates.xml new file mode 100644 index 0000000000..c387bb737a --- /dev/null +++ b/tests/functions_database_helper/fixtures/topics_watch_duplicates.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<dataset> + <table name="phpbb_topics_watch"> + <column>user_id</column> + <column>topic_id</column> + <column>notify_status</column> + + <!-- one entry for this topic --> + <row> + <value>1</value> + <value>1</value> + <value>1</value> + </row> + + <!-- non-conflicting entries --> + <row> + <value>1</value> + <value>2</value> + <value>1</value> + </row> + <row> + <value>2</value> + <value>3</value> + <value>0</value> + </row> + + <!-- conflicting entries, same notify status --> + <row> + <value>1</value> + <value>4</value> + <value>1</value> + </row> + <row> + <value>1</value> + <value>5</value> + <value>1</value> + </row> + + <!-- conflicting entries, notify status 0 into 1 --> + <row> + <value>1</value> + <value>6</value> + <value>0</value> + </row> + <row> + <value>1</value> + <value>7</value> + <value>1</value> + </row> + + <!-- conflicting entries, notify status 1 into 0 --> + <row> + <value>1</value> + <value>8</value> + <value>1</value> + </row> + <row> + <value>1</value> + <value>9</value> + <value>0</value> + </row> + + <!-- conflicting and non-conflicting entries --> + <row> + <value>1</value> + <value>10</value> + <value>0</value> + </row> + <row> + <value>1</value> + <value>11</value> + <value>1</value> + </row> + <row> + <value>2</value> + <value>10</value> + <value>1</value> + </row> + </table> +</dataset> diff --git a/tests/functions_database_helper/update_rows_avoiding_duplicates_notify_status_test.php b/tests/functions_database_helper/update_rows_avoiding_duplicates_notify_status_test.php new file mode 100644 index 0000000000..d4881daf7e --- /dev/null +++ b/tests/functions_database_helper/update_rows_avoiding_duplicates_notify_status_test.php @@ -0,0 +1,101 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_database_helper.php'; + +class phpbb_update_rows_avoiding_duplicates_notify_status_test extends phpbb_database_test_case +{ + public function getDataSet() + { + return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/topics_watch_duplicates.xml'); + } + + public static function fixture_data() + { + return array( + // description + // from array + // to value + // expected count with to value post update + // expected notify_status values + array( + 'trivial', + array(1), + 1000, + 1, + 1, + ), + array( + 'no conflict', + array(2), + 3, + 2, + 1, + ), + array( + 'conflict, same notify status', + array(4), + 5, + 1, + 1, + ), + array( + 'conflict, notify status 0 into 1', + array(6), + 7, + 1, + 0, + ), + array( + 'conflict, notify status 1 into 0', + array(8), + 9, + 1, + 0, + ), + array( + 'conflict and no conflict', + array(10), + 11, + 2, + 0, + ), + ); + } + + /** + * @dataProvider fixture_data + */ + public function test_update($description, $from, $to, $expected_result_count, $expected_notify_status) + { + $db = $this->new_dbal(); + + phpbb_update_rows_avoiding_duplicates_notify_status($db, TOPICS_WATCH_TABLE, 'topic_id', $from, $to); + + $sql = 'SELECT COUNT(*) AS remaining_rows + FROM ' . TOPICS_WATCH_TABLE . ' + WHERE topic_id = ' . (int) $to; + $result = $db->sql_query($sql); + $result_count = $db->sql_fetchfield('remaining_rows'); + $db->sql_freeresult($result); + + $this->assertEquals($expected_result_count, $result_count); + + // user id of 1 is the user being updated + $sql = 'SELECT notify_status + FROM ' . TOPICS_WATCH_TABLE . ' + WHERE topic_id = ' . (int) $to . ' + AND user_id = 1'; + $result = $db->sql_query($sql); + $notify_status = $db->sql_fetchfield('notify_status'); + $db->sql_freeresult($result); + + $this->assertEquals($expected_notify_status, $notify_status); + } +} diff --git a/tests/functions_database_helper/update_rows_avoiding_duplicates_test.php b/tests/functions_database_helper/update_rows_avoiding_duplicates_test.php new file mode 100644 index 0000000000..2f01d29d15 --- /dev/null +++ b/tests/functions_database_helper/update_rows_avoiding_duplicates_test.php @@ -0,0 +1,71 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/../../phpBB/includes/functions_database_helper.php'; + +class phpbb_update_rows_avoiding_duplicates_test extends phpbb_database_test_case +{ + public function getDataSet() + { + return $this->createXMLDataSet(dirname(__FILE__).'/fixtures/bookmarks_duplicates.xml'); + } + + public static function fixture_data() + { + return array( + // description + // from array + // to value + // expected count with to value post update + array( + 'trivial', + array(1), + 10, + 1, + ), + array( + 'no conflict', + array(2), + 3, + 2, + ), + array( + 'conflict', + array(4), + 5, + 1, + ), + array( + 'conflict and no conflict', + array(6), + 7, + 2, + ), + ); + } + + /** + * @dataProvider fixture_data + */ + public function test_update($description, $from, $to, $expected_result_count) + { + $db = $this->new_dbal(); + + phpbb_update_rows_avoiding_duplicates($db, BOOKMARKS_TABLE, 'topic_id', $from, $to); + + $sql = 'SELECT COUNT(*) AS remaining_rows + FROM ' . BOOKMARKS_TABLE . ' + WHERE topic_id = ' . (int) $to; + $result = $db->sql_query($sql); + $result_count = $db->sql_fetchfield('remaining_rows'); + $db->sql_freeresult($result); + + $this->assertEquals($expected_result_count, $result_count); + } +} diff --git a/tests/mock/cache.php b/tests/mock/cache.php index bc18ca066b..71af3037f5 100644 --- a/tests/mock/cache.php +++ b/tests/mock/cache.php @@ -121,7 +121,11 @@ class phpbb_mock_cache implements phpbb_cache_driver_interface public function sql_load($query) { } - public function sql_save($query, $query_result, $ttl) + + /** + * {@inheritDoc} + */ + public function sql_save(phpbb_db_driver $db, $query, $query_result, $ttl) { return $query_result; } diff --git a/tests/mock/filesystem_extension_manager.php b/tests/mock/filesystem_extension_manager.php new file mode 100644 index 0000000000..c5a51bbb3f --- /dev/null +++ b/tests/mock/filesystem_extension_manager.php @@ -0,0 +1,32 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +class phpbb_mock_filesystem_extension_manager extends phpbb_mock_extension_manager +{ + public function __construct($phpbb_root_path) + { + $extensions = array(); + $iterator = new DirectoryIterator($phpbb_root_path . 'ext/'); + foreach ($iterator as $fileinfo) + { + if ($fileinfo->isDir() && substr($fileinfo->getFilename(), 0, 1) != '.') + { + $name = $fileinfo->getFilename(); + $extension = array( + 'ext_name' => $name, + 'ext_active' => true, + 'ext_path' => 'ext/' . $name . '/', + ); + $extensions[$name] = $extension; + } + } + ksort($extensions); + parent::__construct($phpbb_root_path, $extensions); + } +} diff --git a/tests/mock/fileupload.php b/tests/mock/fileupload.php index 409036ba63..cbcbf4a6ab 100644 --- a/tests/mock/fileupload.php +++ b/tests/mock/fileupload.php @@ -20,33 +20,4 @@ class phpbb_mock_fileupload { return true; } - - /** - * Copied verbatim from phpBB/includes/functions_upload.php's fileupload - * class to ensure the correct behaviour of filespec::move_file. - * - * Maps file extensions to the constant in second index of the array - * returned by getimagesize() - */ - public function image_types() - { - return array( - IMAGETYPE_GIF => array('gif'), - IMAGETYPE_JPEG => array('jpg', 'jpeg'), - IMAGETYPE_PNG => array('png'), - IMAGETYPE_SWF => array('swf'), - IMAGETYPE_PSD => array('psd'), - IMAGETYPE_BMP => array('bmp'), - IMAGETYPE_TIFF_II => array('tif', 'tiff'), - IMAGETYPE_TIFF_MM => array('tif', 'tiff'), - IMAGETYPE_JPC => array('jpg', 'jpeg'), - IMAGETYPE_JP2 => array('jpg', 'jpeg'), - IMAGETYPE_JPX => array('jpg', 'jpeg'), - IMAGETYPE_JB2 => array('jpg', 'jpeg'), - IMAGETYPE_SWC => array('swc'), - IMAGETYPE_IFF => array('iff'), - IMAGETYPE_WBMP => array('wbmp'), - IMAGETYPE_XBM => array('xbm'), - ); - } } diff --git a/tests/mock/null_cache.php b/tests/mock/null_cache.php new file mode 100644 index 0000000000..7bd33b441b --- /dev/null +++ b/tests/mock/null_cache.php @@ -0,0 +1,47 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2012 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +class phpbb_mock_null_cache +{ + public function __construct() + { + } + + public function get($var_name) + { + return false; + } + + public function put($var_name, $var, $ttl = 0) + { + } + + public function destroy($var_name, $table = '') + { + } + + public function obtain_bots() + { + return array(); + } + + public function obtain_word_list() + { + return array(); + } + + public function set_bots($bots) + { + } + + public function sql_exists($query_id) + { + return false; + } +} diff --git a/tests/search/mysql_test.php b/tests/search/mysql_test.php index 3ba3915714..3ad15bd806 100644 --- a/tests/search/mysql_test.php +++ b/tests/search/mysql_test.php @@ -26,7 +26,7 @@ class phpbb_search_mysql_test extends phpbb_search_common_test_case parent::setUp(); // dbal uses cache - $cache = new phpbb_cache_service(new phpbb_cache_driver_null); + $cache = new phpbb_mock_cache(); // set config values $config['fulltext_mysql_min_word_len'] = 4; diff --git a/tests/search/native_test.php b/tests/search/native_test.php index eeee3a44f3..4a2c210013 100644 --- a/tests/search/native_test.php +++ b/tests/search/native_test.php @@ -26,7 +26,7 @@ class phpbb_search_native_test extends phpbb_search_test_case parent::setUp(); // dbal uses cache - $cache = new phpbb_cache_service(new phpbb_cache_driver_null); + $cache = new phpbb_mock_cache(); $this->db = $this->new_dbal(); $error = null; diff --git a/tests/search/postgres_test.php b/tests/search/postgres_test.php index 9c77e0c09e..923af6f854 100644 --- a/tests/search/postgres_test.php +++ b/tests/search/postgres_test.php @@ -26,7 +26,7 @@ class phpbb_search_postgres_test extends phpbb_search_common_test_case parent::setUp(); // dbal uses cache - $cache = new phpbb_cache_service(new phpbb_cache_driver_null); + $cache = new phpbb_mock_cache(); // set config values $config['fulltext_postgres_min_word_len'] = 4; diff --git a/tests/session/testable_factory.php b/tests/session/testable_factory.php index cb85a01c5c..1e2b194ece 100644 --- a/tests/session/testable_factory.php +++ b/tests/session/testable_factory.php @@ -59,10 +59,10 @@ class phpbb_session_testable_factory /** * Retrieve the configured session class instance * - * @param dbal $dbal The database connection to use for session data + * @param phpbb_db_driver $dbal The database connection to use for session data * @return phpbb_mock_session_testable A session instance */ - public function get_session(dbal $dbal) + public function get_session(phpbb_db_driver $dbal) { // set up all the global variables used by session global $SID, $_SID, $db, $config, $cache, $request; diff --git a/tests/template/datasets/event_inheritance/ext/kappa/styles/all/template/test.html b/tests/template/datasets/event_inheritance/ext/kappa/styles/all/template/test.html new file mode 100644 index 0000000000..3eb906a09e --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/kappa/styles/all/template/test.html @@ -0,0 +1 @@ +Kappa test event in all diff --git a/tests/template/datasets/event_inheritance/ext/kappa/styles/silver/template/test.html b/tests/template/datasets/event_inheritance/ext/kappa/styles/silver/template/test.html new file mode 100644 index 0000000000..3b65d80a6d --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/kappa/styles/silver/template/test.html @@ -0,0 +1 @@ +Kappa test event in silver diff --git a/tests/template/datasets/event_inheritance/ext/kappa/styles/silver_inherit/template/test.html b/tests/template/datasets/event_inheritance/ext/kappa/styles/silver_inherit/template/test.html new file mode 100644 index 0000000000..26826d59e3 --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/kappa/styles/silver_inherit/template/test.html @@ -0,0 +1 @@ +Kappa test event in silver_inherit diff --git a/tests/template/datasets/event_inheritance/ext/omega/styles/all/template/test.html b/tests/template/datasets/event_inheritance/ext/omega/styles/all/template/test.html new file mode 100644 index 0000000000..003d193dc3 --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/omega/styles/all/template/test.html @@ -0,0 +1 @@ +Omega test event in all diff --git a/tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/test.html b/tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/test.html new file mode 100644 index 0000000000..6bf06f5457 --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/test.html @@ -0,0 +1 @@ +Omega test event in silver diff --git a/tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/two.html b/tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/two.html new file mode 100644 index 0000000000..7f8058f4e4 --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/omega/styles/silver/template/two.html @@ -0,0 +1 @@ +two in silver in omega diff --git a/tests/template/datasets/event_inheritance/ext/zeta/styles/all/template/test.html b/tests/template/datasets/event_inheritance/ext/zeta/styles/all/template/test.html new file mode 100644 index 0000000000..5fc7e5ac12 --- /dev/null +++ b/tests/template/datasets/event_inheritance/ext/zeta/styles/all/template/test.html @@ -0,0 +1 @@ +Zeta test event in all diff --git a/tests/template/datasets/event_inheritance/styles/silver/template/event_test.html b/tests/template/datasets/event_inheritance/styles/silver/template/event_test.html new file mode 100644 index 0000000000..4d78dddb12 --- /dev/null +++ b/tests/template/datasets/event_inheritance/styles/silver/template/event_test.html @@ -0,0 +1 @@ +<!-- EVENT test --> diff --git a/tests/template/datasets/event_inheritance/styles/silver/template/event_two.html b/tests/template/datasets/event_inheritance/styles/silver/template/event_two.html new file mode 100644 index 0000000000..fe46be3782 --- /dev/null +++ b/tests/template/datasets/event_inheritance/styles/silver/template/event_two.html @@ -0,0 +1 @@ +<!-- EVENT two --> diff --git a/tests/template/datasets/event_inheritance/styles/silver_inherit/template/event_test.html b/tests/template/datasets/event_inheritance/styles/silver_inherit/template/event_test.html new file mode 100644 index 0000000000..4d78dddb12 --- /dev/null +++ b/tests/template/datasets/event_inheritance/styles/silver_inherit/template/event_test.html @@ -0,0 +1 @@ +<!-- EVENT test --> diff --git a/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/universal.html b/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/universal.html new file mode 100644 index 0000000000..f2c5762ade --- /dev/null +++ b/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/universal.html @@ -0,0 +1 @@ +Universal in trivial extension. diff --git a/tests/template/datasets/ext_trivial/ext/trivial/styles/silver/template/simple.html b/tests/template/datasets/ext_trivial/ext/trivial/styles/silver/template/simple.html new file mode 100644 index 0000000000..fe32a1ed3f --- /dev/null +++ b/tests/template/datasets/ext_trivial/ext/trivial/styles/silver/template/simple.html @@ -0,0 +1 @@ +Simple in trivial extension. diff --git a/tests/template/datasets/ext_trivial/styles/silver/template/event_simple.html b/tests/template/datasets/ext_trivial/styles/silver/template/event_simple.html new file mode 100644 index 0000000000..604c1acdce --- /dev/null +++ b/tests/template/datasets/ext_trivial/styles/silver/template/event_simple.html @@ -0,0 +1 @@ +<!-- EVENT simple --> diff --git a/tests/template/datasets/ext_trivial/styles/silver/template/event_universal.html b/tests/template/datasets/ext_trivial/styles/silver/template/event_universal.html new file mode 100644 index 0000000000..15425cacc3 --- /dev/null +++ b/tests/template/datasets/ext_trivial/styles/silver/template/event_universal.html @@ -0,0 +1 @@ +<!-- EVENT universal --> diff --git a/tests/template/includephp_test.php b/tests/template/includephp_test.php index c93a53e2ad..f1012b6939 100644 --- a/tests/template/includephp_test.php +++ b/tests/template/includephp_test.php @@ -48,7 +48,7 @@ class phpbb_template_includephp_test extends phpbb_template_template_test_case $this->setup_engine(array('tpl_allow_php' => true)); - $this->style->set_custom_style('tests', $cache_dir, ''); + $this->style->set_custom_style('tests', $cache_dir, array(), ''); $cache_file = $this->template->cachepath . 'includephp_absolute.html.php'; $this->run_template('includephp_absolute.html', array(), array(), array(), "Path is absolute.\ntesting included php", $cache_file); diff --git a/tests/template/template_compile_test.php b/tests/template/template_compile_test.php index 0cfcd6ceb5..7393fc1747 100644 --- a/tests/template/template_compile_test.php +++ b/tests/template/template_compile_test.php @@ -16,7 +16,7 @@ class phpbb_template_template_compile_test extends phpbb_test_case protected function setUp() { - $this->template_compile = new phpbb_template_compile(false, null, ''); + $this->template_compile = new phpbb_template_compile(false, null, $this->style_resource_locator, ''); $this->template_path = dirname(__FILE__) . '/templates'; } diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php new file mode 100644 index 0000000000..6cea9b92e3 --- /dev/null +++ b/tests/template/template_events_test.php @@ -0,0 +1,118 @@ +<?php +/** +* +* @package testing +* @copyright (c) 2011 phpBB Group +* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2 +* +*/ + +require_once dirname(__FILE__) . '/template_test_case.php'; + +class phpbb_template_template_events_test extends phpbb_template_template_test_case +{ + public function template_data() + { + return array( + /* + array( + '', // file + '', // dataset + array(), // style names + array(), // vars + array(), // block vars + array(), // destroy + '', // expected result + ), + */ + array( + 'Simple template event', + 'ext_trivial', + array(), + 'event_simple.html', + array(), + array(), + array(), + "Simple in trivial extension.", + ), + array( + 'Universal template event ("all" style)', + 'ext_trivial', + array(), + 'event_universal.html', + array(), + array(), + array(), + "Universal in trivial extension.", + ), + array( + 'Template event with inheritance - parent', + 'event_inheritance', + array('silver'), + 'event_test.html', + array(), + array(), + array(), +'Kappa test event in all +Omega test event in all +Zeta test event in all +Kappa test event in silver +Omega test event in silver', + ), + array( + 'Template event with inheritance - child', + 'event_inheritance', + array('silver_inherit', 'silver'), + 'event_test.html', + array(), + array(), + array(), +'Kappa test event in all +Omega test event in all +Zeta test event in all +Kappa test event in silver_inherit', + ), + array( + 'Definition in parent style', + 'event_inheritance', + array('silver_inherit', 'silver'), + 'event_two.html', + array(), + array(), + array(), +'two in silver in omega', + ), + ); + } + + /** + * @dataProvider template_data + */ + public function test_event($desc, $dataset, $style_names, $file, array $vars, array $block_vars, array $destroy, $expected) + { + // Reset the engine state + $this->setup_engine_for_events($dataset, $style_names); + + // Run test + $cache_file = $this->template->cachepath . str_replace('/', '.', $file) . '.php'; + $this->run_template($file, $vars, $block_vars, $destroy, $expected, $cache_file); + } + + protected function setup_engine_for_events($dataset, $style_names, array $new_config = array()) + { + global $phpbb_root_path, $phpEx, $user; + + $defaults = $this->config_defaults(); + $config = new phpbb_config(array_merge($defaults, $new_config)); + + $this->template_path = dirname(__FILE__) . "/datasets/$dataset/styles/silver/template"; + $this->style_resource_locator = new phpbb_style_resource_locator(); + $this->extension_manager = new phpbb_mock_filesystem_extension_manager( + dirname(__FILE__) . "/datasets/$dataset/" + ); + $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, new phpbb_template_context, $this->extension_manager); + $this->style_provider = new phpbb_style_path_provider(); + $this->style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider, $this->template); + $this->style->set_custom_style('silver', array($this->template_path), $style_names, ''); + } +} diff --git a/tests/template/template_test_case.php b/tests/template/template_test_case.php index 2e6f703eb1..3c997cb00e 100644 --- a/tests/template/template_test_case.php +++ b/tests/template/template_test_case.php @@ -69,7 +69,7 @@ class phpbb_template_template_test_case extends phpbb_test_case $this->style_provider = new phpbb_style_path_provider(); $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, new phpbb_template_context()); $this->style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider, $this->template); - $this->style->set_custom_style('tests', $this->template_path, ''); + $this->style->set_custom_style('tests', $this->template_path, array(), ''); } protected function setUp() diff --git a/tests/template/template_test_case_with_tree.php b/tests/template/template_test_case_with_tree.php index 6a226f317a..7585be5728 100644 --- a/tests/template/template_test_case_with_tree.php +++ b/tests/template/template_test_case_with_tree.php @@ -24,6 +24,6 @@ class phpbb_template_template_test_case_with_tree extends phpbb_template_templat $this->style_provider = new phpbb_style_path_provider(); $this->template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, new phpbb_template_context()); $this->style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $this->style_resource_locator, $this->style_provider, $this->template); - $this->style->set_custom_style('tests', array($this->template_path, $this->parent_template_path), ''); + $this->style->set_custom_style('tests', array($this->template_path, $this->parent_template_path), array(), ''); } } diff --git a/tests/template/templates/events.html b/tests/template/templates/events.html new file mode 100644 index 0000000000..c44a7469e7 --- /dev/null +++ b/tests/template/templates/events.html @@ -0,0 +1,4 @@ +<!-- EVENT child_only --> +<!-- EVENT parent_only --> +<!-- EVENT parent_and_child --> +<!-- EVENT random_event --> diff --git a/tests/test_framework/phpbb_database_test_case.php b/tests/test_framework/phpbb_database_test_case.php index b5076b92e9..72bce2e38a 100644 --- a/tests/test_framework/phpbb_database_test_case.php +++ b/tests/test_framework/phpbb_database_test_case.php @@ -49,7 +49,7 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test $db_config = $this->get_database_config(); // Firebird requires table and column names to be uppercase - if ($db_config['dbms'] == 'firebird') + if ($db_config['dbms'] == 'phpbb_db_driver_firebird') { $xml_data = file_get_contents($path); $xml_data = preg_replace_callback('/(?:(<table name="))([a-z_]+)(?:(">))/', 'phpbb_database_test_case::to_upper', $xml_data); @@ -118,9 +118,7 @@ abstract class phpbb_database_test_case extends PHPUnit_Extensions_Database_Test $config = $this->get_database_config(); - require_once dirname(__FILE__) . '/../../phpBB/includes/db/' . $config['dbms'] . '.php'; - $dbal = 'dbal_' . $config['dbms']; - $db = new $dbal(); + $db = new $config['dbms'](); $db->sql_connect($config['dbhost'], $config['dbuser'], $config['dbpasswd'], $config['dbname'], $config['dbport']); return $db; diff --git a/tests/test_framework/phpbb_database_test_connection_manager.php b/tests/test_framework/phpbb_database_test_connection_manager.php index d7c2804aa7..03097a10a0 100644 --- a/tests/test_framework/phpbb_database_test_connection_manager.php +++ b/tests/test_framework/phpbb_database_test_connection_manager.php @@ -108,7 +108,7 @@ class phpbb_database_test_connection_manager // These require different connection strings on the phpBB side than they do in PDO // so you must provide a DSN string for ODBC separately - if (!empty($this->config['custom_dsn']) && ($this->config['dbms'] == 'mssql' || $this->config['dbms'] == 'firebird')) + if (!empty($this->config['custom_dsn']) && ($this->config['dbms'] == 'phpbb_db_driver_mssql' || $this->config['dbms'] == 'phpbb_db_driver_firebird')) { $dsn = 'odbc:' . $this->config['custom_dsn']; } @@ -117,12 +117,12 @@ class phpbb_database_test_connection_manager { switch ($this->config['dbms']) { - case 'mssql': - case 'mssql_odbc': + case 'phpbb_db_driver_mssql': + case 'phpbb_db_driver_mssql_odbc': $this->pdo = new phpbb_database_connection_odbc_pdo_wrapper('mssql', 0, $dsn, $this->config['dbuser'], $this->config['dbpasswd']); break; - case 'firebird': + case 'phpbb_db_driver_firebird': if (!empty($this->config['custom_dsn'])) { $this->pdo = new phpbb_database_connection_odbc_pdo_wrapper('firebird', 0, $dsn, $this->config['dbuser'], $this->config['dbpasswd']); @@ -165,8 +165,8 @@ class phpbb_database_test_connection_manager { switch ($this->config['dbms']) { - case 'sqlite': - case 'firebird': + case 'phpbb_db_driver_sqlite': + case 'phpbb_db_driver_firebird': $this->connect(); // Drop all of the tables foreach ($this->get_tables() as $table) @@ -176,7 +176,7 @@ class phpbb_database_test_connection_manager $this->purge_extras(); break; - case 'oracle': + case 'phpbb_db_driver_oracle': $this->connect(); // Drop all of the tables foreach ($this->get_tables() as $table) @@ -226,39 +226,38 @@ class phpbb_database_test_connection_manager switch ($this->config['dbms']) { - case 'mysql': - case 'mysql4': - case 'mysqli': + case 'phpbb_db_driver_mysql': + case 'phpbb_db_driver_mysqli': $sql = 'SHOW TABLES'; break; - case 'sqlite': + case 'phpbb_db_driver_sqlite': $sql = 'SELECT name FROM sqlite_master WHERE type = "table"'; break; - case 'mssql': - case 'mssql_odbc': - case 'mssqlnative': + case 'phpbb_db_driver_mssql': + case 'phpbb_db_driver_mssql_odbc': + case 'phpbb_db_driver_mssqlnative': $sql = "SELECT name FROM sysobjects WHERE type='U'"; break; - case 'postgres': + case 'phpbb_db_driver_postgres': $sql = 'SELECT relname FROM pg_stat_user_tables'; break; - case 'firebird': + case 'phpbb_db_driver_firebird': $sql = 'SELECT rdb$relation_name FROM rdb$relations WHERE rdb$view_source is null AND rdb$system_flag = 0'; break; - case 'oracle': + case 'phpbb_db_driver_oracle': $sql = 'SELECT table_name FROM USER_TABLES'; break; @@ -293,8 +292,8 @@ class phpbb_database_test_connection_manager protected function load_schema_from_file($directory) { $schema = $this->dbms['SCHEMA']; - - if ($this->config['dbms'] == 'mysql') + + if ($this->config['dbms'] == 'phpbb_db_driver_mysql') { $sth = $this->pdo->query('SELECT VERSION() AS version'); $row = $sth->fetch(PDO::FETCH_ASSOC); @@ -313,7 +312,7 @@ class phpbb_database_test_connection_manager $queries = file_get_contents($filename); $sql = phpbb_remove_comments($queries); - + $sql = split_sql_file($sql, $this->dbms['DELIM']); foreach ($sql as $query) @@ -328,47 +327,47 @@ class phpbb_database_test_connection_manager protected function get_dbms_data($dbms) { $available_dbms = array( - 'firebird' => array( + 'phpbb_db_driver_firebird' => array( 'SCHEMA' => 'firebird', 'DELIM' => ';;', 'PDO' => 'firebird', ), - 'mysqli' => array( + 'phpbb_db_driver_mysqli' => array( 'SCHEMA' => 'mysql_41', 'DELIM' => ';', 'PDO' => 'mysql', ), - 'mysql' => array( + 'phpbb_db_driver_mysql' => array( 'SCHEMA' => 'mysql', 'DELIM' => ';', 'PDO' => 'mysql', ), - 'mssql' => array( + 'phpbb_db_driver_mssql' => array( 'SCHEMA' => 'mssql', 'DELIM' => 'GO', 'PDO' => 'odbc', ), - 'mssql_odbc'=> array( + 'phpbb_db_driver_mssql_odbc'=> array( 'SCHEMA' => 'mssql', 'DELIM' => 'GO', 'PDO' => 'odbc', ), - 'mssqlnative' => array( + 'phpbb_db_driver_mssqlnative' => array( 'SCHEMA' => 'mssql', 'DELIM' => 'GO', 'PDO' => 'sqlsrv', ), - 'oracle' => array( + 'phpbb_db_driver_oracle' => array( 'SCHEMA' => 'oracle', 'DELIM' => '/', 'PDO' => 'oci', ), - 'postgres' => array( + 'phpbb_db_driver_postgres' => array( 'SCHEMA' => 'postgres', 'DELIM' => ';', 'PDO' => 'pgsql', ), - 'sqlite' => array( + 'phpbb_db_driver_sqlite' => array( 'SCHEMA' => 'sqlite', 'DELIM' => ';', 'PDO' => 'sqlite2', @@ -397,7 +396,7 @@ class phpbb_database_test_connection_manager switch ($this->config['dbms']) { - case 'firebird': + case 'phpbb_db_driver_firebird': $sql = 'SELECT RDB$GENERATOR_NAME FROM RDB$GENERATORS WHERE RDB$SYSTEM_FLAG = 0'; @@ -409,7 +408,7 @@ class phpbb_database_test_connection_manager } break; - case 'oracle': + case 'phpbb_db_driver_oracle': $sql = 'SELECT sequence_name FROM USER_SEQUENCES'; $result = $this->pdo->query($sql); @@ -444,7 +443,7 @@ class phpbb_database_test_connection_manager switch ($this->config['dbms']) { - case 'oracle': + case 'phpbb_db_driver_oracle': // Get all of the information about the sequences $sql = "SELECT t.table_name, tc.column_name, d.referenced_name as sequence_name, s.increment_by, s.min_value FROM USER_TRIGGERS t @@ -486,7 +485,7 @@ class phpbb_database_test_connection_manager } break; - case 'postgres': + case 'phpbb_db_driver_postgres': // Get the sequences attached to the tables $sql = 'SELECT column_name, table_name FROM information_schema.columns WHERE table_name IN (' . implode(', ', $table_names) . ") diff --git a/tests/test_framework/phpbb_functional_test_case.php b/tests/test_framework/phpbb_functional_test_case.php index 16e1ccaff9..67a5050892 100644 --- a/tests/test_framework/phpbb_functional_test_case.php +++ b/tests/test_framework/phpbb_functional_test_case.php @@ -34,13 +34,36 @@ class phpbb_functional_test_case extends phpbb_test_case static protected $config = array(); static protected $already_installed = false; - public function setUp() + static public function setUpBeforeClass() { + parent::setUpBeforeClass(); + + self::$config = phpbb_test_case_helpers::get_test_config(); + + // Important: this is used both for installation and by + // test cases for querying the tables. + // Therefore table prefix must be set before a board is + // installed, and also before each test case is run. + self::$config['table_prefix'] = 'phpbb_'; + if (!isset(self::$config['phpbb_functional_url'])) { - $this->markTestSkipped('phpbb_functional_url was not set in test_config and wasn\'t set as PHPBB_FUNCTIONAL_URL environment variable either.'); + self::markTestSkipped('phpbb_functional_url was not set in test_config and wasn\'t set as PHPBB_FUNCTIONAL_URL environment variable either.'); } + if (!self::$already_installed) + { + self::install_board(); + self::$already_installed = true; + } + } + + public function setUp() + { + parent::setUp(); + + $this->bootstrap(); + $this->cookieJar = new CookieJar; $this->client = new Goutte\Client(array(), null, $this->cookieJar); // Reset the curl handle because it is 0 at this point and not a valid @@ -73,27 +96,16 @@ class phpbb_functional_test_case extends phpbb_test_case $this->backupStaticAttributesBlacklist += array( 'phpbb_functional_test_case' => array('config', 'already_installed'), ); - - if (!static::$already_installed) - { - $this->install_board(); - $this->bootstrap(); - static::$already_installed = true; - } } protected function get_db() { global $phpbb_root_path, $phpEx; // so we don't reopen an open connection - if (!($this->db instanceof dbal)) + if (!($this->db instanceof phpbb_db_driver)) { - if (!class_exists('dbal_' . self::$config['dbms'])) - { - include($phpbb_root_path . 'includes/db/' . self::$config['dbms'] . ".$phpEx"); - } - $sql_db = 'dbal_' . self::$config['dbms']; - $this->db = new $sql_db(); + $dbms = self::$config['dbms']; + $this->db = new $dbms(); $this->db->sql_connect(self::$config['dbhost'], self::$config['dbuser'], self::$config['dbpasswd'], self::$config['dbname'], self::$config['dbport']); } return $this->db; @@ -137,19 +149,11 @@ class phpbb_functional_test_case extends phpbb_test_case return $this->extension_manager; } - protected function install_board() + static protected function install_board() { global $phpbb_root_path, $phpEx; - self::$config = phpbb_test_case_helpers::get_test_config(); - - if (!isset(self::$config['phpbb_functional_url'])) - { - return; - } - - self::$config['table_prefix'] = 'phpbb_'; - $this->recreate_database(self::$config); + self::recreate_database(self::$config); if (file_exists($phpbb_root_path . "config.$phpEx")) { @@ -194,19 +198,30 @@ class phpbb_functional_test_case extends phpbb_test_case )); // end data - $content = $this->do_request('install'); - $this->assertContains('Welcome to Installation', $content); - - $this->do_request('create_table', $data); - - $this->do_request('config_file', $data); + $content = self::do_request('install'); + self::assertNotSame(false, $content); + self::assertContains('Welcome to Installation', $content); + + // Installer uses 3.0-style dbms name + $data['dbms'] = str_replace('phpbb_db_driver_', '', $data['dbms']); + $content = self::do_request('create_table', $data); + self::assertNotSame(false, $content); + self::assertContains('The database tables used by phpBB', $content); + // 3.0 or 3.1 + self::assertContains('have been created and populated with some initial data.', $content); + + $content = self::do_request('config_file', $data); + self::assertNotSame(false, $content); + self::assertContains('Configuration file', $content); file_put_contents($phpbb_root_path . "config.$phpEx", phpbb_create_config_file_data($data, self::$config['dbms'], true, true)); - $this->do_request('final', $data); + $content = self::do_request('final', $data); + self::assertNotSame(false, $content); + self::assertContains('You have successfully installed', $content); copy($phpbb_root_path . "config.$phpEx", $phpbb_root_path . "config_test.$phpEx"); } - private function do_request($sub, $post_data = null) + static private function do_request($sub, $post_data = null) { $context = null; @@ -225,13 +240,62 @@ class phpbb_functional_test_case extends phpbb_test_case return file_get_contents(self::$config['phpbb_functional_url'] . 'install/index.php?mode=install&sub=' . $sub, false, $context); } - private function recreate_database($config) + static private function recreate_database($config) { $db_conn_mgr = new phpbb_database_test_connection_manager($config); $db_conn_mgr->recreate_db(); } - protected function login() + /** + * Creates a new user with limited permissions + * + * @param string $username Also doubles up as the user's password + * @return int ID of created user + */ + protected function create_user($username) + { + // Required by unique_id + global $config; + + $config = new phpbb_config(array()); + $config['rand_seed'] = ''; + $config['rand_seed_last_update'] = time() + 600; + + // Required by user_add + global $db, $cache, $phpbb_dispatcher; + $db = $this->get_db(); + if (!function_exists('phpbb_mock_null_cache')) + { + require_once(__DIR__ . '/../mock/null_cache.php'); + } + $cache = new phpbb_mock_null_cache; + + if (!function_exists('utf_clean_string')) + { + require_once(__DIR__ . '/../../phpBB/includes/utf/utf_tools.php'); + } + if (!function_exists('user_add')) + { + require_once(__DIR__ . '/../../phpBB/includes/functions_user.php'); + } + set_config(null, null, null, $config); + set_config_count(null, null, null, $config); + $phpbb_dispatcher = new phpbb_mock_event_dispatcher(); + + $user_row = array( + 'username' => $username, + 'group_id' => 2, + 'user_email' => 'nobody@example.com', + 'user_type' => 0, + 'user_lang' => 'en', + 'user_timezone' => 0, + 'user_dateformat' => '', + 'user_password' => phpbb_hash($username), + ); + return user_add($user_row); + } + + protected function login($username = 'admin') { $this->add_lang('ucp'); @@ -239,7 +303,9 @@ class phpbb_functional_test_case extends phpbb_test_case $this->assertContains($this->lang('LOGIN_EXPLAIN_UCP'), $crawler->filter('html')->text()); $form = $crawler->selectButton($this->lang('LOGIN'))->form(); - $login = $this->client->submit($form, array('username' => 'admin', 'password' => 'admin')); + $crawler = $this->client->submit($form, array('username' => $username, 'password' => $username)); + $this->assert_response_success(); + $this->assertContains($this->lang('LOGIN_REDIRECT'), $crawler->filter('html')->text()); $cookies = $this->cookieJar->all(); diff --git a/tests/test_framework/phpbb_test_case_helpers.php b/tests/test_framework/phpbb_test_case_helpers.php index fe15eded90..47459832d5 100644 --- a/tests/test_framework/phpbb_test_case_helpers.php +++ b/tests/test_framework/phpbb_test_case_helpers.php @@ -54,7 +54,7 @@ class phpbb_test_case_helpers if (extension_loaded('sqlite') && version_compare(PHPUnit_Runner_Version::id(), '3.4.15', '>=')) { $config = array_merge($config, array( - 'dbms' => 'sqlite', + 'dbms' => 'phpbb_db_driver_sqlite', 'dbhost' => dirname(__FILE__) . '/../phpbb_unit_tests.sqlite2', // filename 'dbport' => '', 'dbname' => '', @@ -78,7 +78,7 @@ class phpbb_test_case_helpers include($test_config); $config = array_merge($config, array( - 'dbms' => $dbms, + 'dbms' => phpbb_convert_30_dbms_to_31($dbms), 'dbhost' => $dbhost, 'dbport' => $dbport, 'dbname' => $dbname, @@ -104,8 +104,13 @@ class phpbb_test_case_helpers if (isset($_SERVER['PHPBB_TEST_DBMS'])) { + if (!function_exists('phpbb_convert_30_dbms_to_31')) + { + require_once dirname(__FILE__) . '/../../phpBB/includes/functions.php'; + } + $config = array_merge($config, array( - 'dbms' => isset($_SERVER['PHPBB_TEST_DBMS']) ? $_SERVER['PHPBB_TEST_DBMS'] : '', + 'dbms' => isset($_SERVER['PHPBB_TEST_DBMS']) ? phpbb_convert_30_dbms_to_31($_SERVER['PHPBB_TEST_DBMS']) : '', 'dbhost' => isset($_SERVER['PHPBB_TEST_DBHOST']) ? $_SERVER['PHPBB_TEST_DBHOST'] : '', 'dbport' => isset($_SERVER['PHPBB_TEST_DBPORT']) ? $_SERVER['PHPBB_TEST_DBPORT'] : '', 'dbname' => isset($_SERVER['PHPBB_TEST_DBNAME']) ? $_SERVER['PHPBB_TEST_DBNAME'] : '', diff --git a/tests/upload/filespec_test.php b/tests/upload/filespec_test.php index c7ff2e78e0..87cd00197f 100644 --- a/tests/upload/filespec_test.php +++ b/tests/upload/filespec_test.php @@ -205,8 +205,7 @@ class phpbb_filespec_test extends phpbb_test_case */ public function test_get_extension($filename, $expected) { - $filespec = $this->get_filespec(); - $this->assertEquals($expected, $filespec->get_extension($filename)); + $this->assertEquals($expected, filespec::get_extension($filename)); } public function is_image_variables() diff --git a/travis/phpunit-mysql-travis.xml b/travis/phpunit-mysql-travis.xml index 5366494c8b..cc033ff959 100644 --- a/travis/phpunit-mysql-travis.xml +++ b/travis/phpunit-mysql-travis.xml @@ -28,7 +28,7 @@ </groups> <php> - <server name="PHPBB_TEST_DBMS" value="mysqli" /> + <server name="PHPBB_TEST_DBMS" value="phpbb_db_driver_mysqli" /> <server name="PHPBB_TEST_DBHOST" value="0.0.0.0" /> <server name="PHPBB_TEST_DBPORT" value="3306" /> <server name="PHPBB_TEST_DBNAME" value="phpbb_tests" /> diff --git a/travis/phpunit-postgres-travis.xml b/travis/phpunit-postgres-travis.xml index 0383edd9d6..5019c225b4 100644 --- a/travis/phpunit-postgres-travis.xml +++ b/travis/phpunit-postgres-travis.xml @@ -30,7 +30,7 @@ <php> <!-- "Real" test database --> <!-- uncomment, otherwise sqlite memory runs --> - <server name="PHPBB_TEST_DBMS" value="postgres"/> + <server name="PHPBB_TEST_DBMS" value="phpbb_db_driver_postgres"/> <server name="PHPBB_TEST_DBHOST" value="localhost" /> <server name="PHPBB_TEST_DBPORT" value="5432" /> <server name="PHPBB_TEST_DBNAME" value="phpbb_tests" /> |